Para quem é
Você escreve Go e o seu serviço roda em uma única máquina Linux, sob o systemd. Pode ser uma API com um worker em background e SQLite, um receptor de webhooks ou uma ferramenta interna da qual a empresa inteira depende. Ele funciona. O que você quer saber é o que acontece nos extremos: um deploy com requisições em andamento, um cliente que nunca termina de mandar os headers, um container com pouca memória, um crash às 3 da manhã.
Este não é um tutorial de Go. Ele parte do princípio de que você já conhece a linguagem e já colocou algo em produção. Se você procura uma introdução a goroutines, os livros de Go mais conhecidos são um ponto de partida melhor.
O que tem dentro
Um livro de 16 capítulos, com cerca de 2,000 linhas, e um pequeno serviço de referência de onde sai cada listagem de Go do livro. Um script confere se cada um dos 60 blocos de código bate com o código-fonte testado, então nada no texto é um trecho que ninguém executou.
| # | Capítulo |
|---|---|
| 1 | Estrutura de projeto para um serviço pequeno |
| 2 | Configuração pelo ambiente: valide tudo e falhe cedo |
| 3 | Logging estruturado com log/slog, sem vazar segredos |
| 4 | Timeouts do servidor HTTP |
| 5 | Graceful shutdown |
| 6 | Health e readiness: qual é a diferença |
| 7 | Context, cancelamento e checagem de goroutine leak |
| 8 | Acesso a banco com SQLite: WAL, um único escritor, migrations |
| 9 | Erros e panics |
| 10 | Métricas e pprof, com segurança |
| 11 | Testes |
| 12 | Build: binários estáticos e reproduzíveis |
| 13 | systemd: unit, hardening, restart, stop |
| 14 | Memória: o que um processo Go faz sob pressão |
| 15 | Deploy com pastas de release |
| 16 | Bugs comuns em produção, cada um com uma checagem que o pega |
Você também recebe o serviço de referência (biblioteca padrão mais um driver de SQLite), um gerador de carga, um pequeno experimento de memória, a unit do systemd e um Dockerfile, três checklists e um harness em Docker que refaz todas as checagens a partir de um container limpo. A saída da nossa última execução completa vai junto, para você comparar.
O que os testes mostram
Os capítulos de shutdown e de systemd têm por trás testes que sobem o binário de verdade e mandam sinais de verdade.
| O que fizemos | O que aconteceu |
|---|---|
| SIGTERM com um job de 1.5 s em andamento | Novas conexões foram recusadas após 11 ms, a requisição em andamento terminou em 1.399 s e o processo saiu com código 0 após 1.669 s |
| SIGTERM em um serviço ocioso | Saída em 2 ms |
| SIGTERM com um job de 9 s e limite de shutdown de 500 ms | Saída após 515 ms com código 1, job devolvido para a fila |
| Cliente que manda os headers devagar, header timeout de 300 ms | Conexão cortada após 295 ms |
systemctl stop com uma requisição de 3 s em andamento | A requisição retornou 200 e o stop levou 3.19 s |
kill -9 sob o systemd | De volta ao normal 2.10 s depois |
| Dois builds a partir de diretórios diferentes | Binários idênticos byte a byte (e diferentes quando o -trimpath é omitido, como controle) |
A unit do systemd vem com opções de hardening, e lemos o resultado no processo em execução em vez de confiar no arquivo: nenhuma capability, um filtro seccomp, /usr e /etc somente leitura, um limite de memória. O systemd-analyze security deu à unit uma nota de exposição de 1.4.
Throughput e memória
Ambiente: Docker Desktop em um notebook Apple Silicon, 8 CPUs, com o serviço, o gerador de carga e o banco em um único container, 16 clientes, três execuções de 8 segundos por modo.
| Modo | Requisições por segundo (3 execuções) |
|---|---|
| Escritas | 9,190 a 11,189 (p99 8.4 a 11.7 ms) |
| Leituras | 13,541 a 18,421 |
| Endpoint de health | 23,032 a 26,757 |
A memória residente foi de 13 MiB em repouso e 23 MiB depois da carga, com pico de 25 MiB.
GOMEMLIMIT, medido
O capítulo 14 não manda você definir o GOMEMLIMIT e seguir em frente. Ele roda um programa pequeno, com 40 MiB de heap ativa, dentro de um container limitado a 80 MiB. Sem limite, o processo foi morto por OOM em 3 de 3 execuções. Com GOMEMLIMIT=56MiB, sobreviveu em 3 de 3, ao custo de umas quatro vezes mais coletas de lixo. O livro também explica por que o limite é soft e o que isso significa para o dimensionamento.
Requisitos e formato
Go 1.24 ou mais recente. Docker só se você quiser refazer o harness. Tudo é Markdown, código Go, shell e arquivos de configuração: sem trava de PDF, sem conta, e dá para ler em qualquer lugar.
Perguntas frequentes
É um livro para iniciantes?
Não. Ele pressupõe que você já escreve Go. O assunto é o lado de produção: o que o processo faz quando algo dá errado.
Cobre Postgres?
O serviço de referência e os testes usam SQLite. O capítulo de banco de dados também traz orientações para Postgres.
Qual a diferença para o Go Webhook Receiver Starter?
O starter é um produto pequeno que você coloca para rodar. O handbook traz o raciocínio e os testes por trás de um serviço Go bem-comportado, usando um serviço de referência diferente.
Posso usar o código nos meus projetos?
Pode, nos seus projetos e nos servidores seus ou da empresa onde você trabalha. Não revenda nem redistribua o livro ou o kit.
Changelog
- 0.1.0: primeira release.
Ler mais
- Graceful shutdown for a Go HTTP server under systemd (em inglês)
- GOMEMLIMIT in an 80 MB container, with the numbers (em inglês)
- Go SQLite reads returning 404 for rows that exist (em inglês)
- log/slog setup for a small Go service on journald (em inglês)
- Go HTTP server timeouts that survive slow and stuck clients (em inglês)
Quero este
Pagamento, impostos e notas fiscais ficam com a Polar, que atua como merchant of record. Você recebe o link de download assim que concluir a compra.