Em um sistema de requisição e resposta, as setas do diagrama são o grafo de chamadas. Em um sistema orientado a eventos, não. Um produtor grava um evento em um tópico e não sabe quem o lê. Desenhe isso de forma ingênua, com todos os serviços ligados a uma grande caixa do Kafka, e o diagrama esconde tudo de que você precisa: quais eventos existem, quem reage a eles, em que ordem e o que acontece quando um consumidor falha.
Este guia traz uma notação para diagramas de arquitetura orientada a eventos que mantém o fluxo legível, percorre um exemplo de processamento de pedidos no Kafka e cobre os detalhes que as pessoas esquecem de desenhar: chaves, grupos de consumidores, o outbox e o caminho de dead-letter.
O que o diagrama precisa mostrar
Um diagrama orientado a eventos deve responder a estas perguntas sem um documento à parte:
- Quais eventos existem? Nomeados no passado, como
OrderPlacedouPaymentFailed. - Quem produz cada um? O padrão saudável é exatamente um dono por tipo de evento.
- Quem consome, e em qual grupo de consumidores? No Kafka, todo grupo de consumidores recebe todos os eventos, então cada grupo é um leitor separado.
- O que define a ordem? O Kafka só mantém a ordem dentro de uma partição, e a chave escolhe a partição.
- O que acontece em caso de falha? Novas tentativas, tópicos de dead-letter e quem faz o replay.
Uma notação que funciona
| Elemento | Como desenhar |
|---|---|
| Produtor | Um nó de serviço com uma conexão tracejada até o tópico, rotulada com o tipo de evento |
| Tópico | Um nó próprio, com o nome usado no cluster (orders.v1) e a chave no rótulo |
| Grupo de consumidores | Uma conexão tracejada do tópico até o consumidor, rotulada com o id do grupo |
| Evento vs. comando | Eventos no passado (OrderPlaced), comandos no imperativo (ReserveStock) |
| Tópico de dead-letter | Um nó de tópico separado, alimentado pelo consumidor que desistiu |
| Conector | Um nó entre um tópico e um armazenamento externo, como um sink para o data warehouse |
| Cluster de brokers | Um frame em volta dos tópicos; brokers e partições ficam no diagrama de operações |
Use conexões sólidas só para chamadas síncronas, como uma requisição HTTP a um provedor de pagamentos. Assim quem lê percebe de relance quais partes de um fluxo acontecem na mesma requisição e quais acontecem depois.
O exemplo: eventos de pedido no Kafka
Uma loja online processa pedidos com eventos:
- O serviço orders grava o pedido e uma linha de outbox na mesma transação do banco de dados.
- Um outbox relay (Debezium no Kafka Connect) lê o outbox pelo log do banco de dados e publica
OrderPlacedemorders.v1, comorder_idcomo chave. - Três grupos de consumidores leem
orders.v1: payments cobra o cartão, inventory reserva o estoque e um warehouse sink carrega cada evento no data warehouse. - Payments publica
PaymentSucceededouPaymentFailedempayments.v1, também comorder_idcomo chave, e o serviço orders consome esse tópico para atualizar o status do pedido. - Quando inventory não consegue processar uma mensagem depois de três tentativas, grava a mensagem em
inventory.dlqe segue em frente.
Aqui está o fluxo inteiro em um só canvas:
Conteúdo do diagrama
- Orders
- Orders DB (orders + outbox)
- Outbox relay
- Kafka cluster
- payments.v1 · key order_id
- orders.v1 · key order_id
- inventory.dlq
- Payments
- Warehouse sink
- Inventory
- Data warehouse
- order + outbox row, one transaction
- reads WAL
- OrderPlaced
- group: payments
- group: warehouse-sink
- group: inventory
- PaymentSucceeded/Failed
- group: orders
- load
- after 3 failed attempts
Repare no que o diagrama deixa óbvio: ninguém chama payments, adicionar um quarto grupo de consumidores não muda nada upstream, e os eventos de um pedido ficam em ordem dentro de cada tópico porque os dois usam order_id como chave (o Kafka não garante ordem entre tópicos).
Cinco regras para diagramas orientados a eventos
1. Tópicos são nós, não setas
Uma seta de orders para payments com o rótulo "Kafka" sugere uma chamada que não existe. Desenhe o tópico como um nó entre os dois. Ele é algo real, com nome, dono, período de retenção e schema.
2. As setas seguem os dados
Desenhe do produtor para o tópico e do tópico para o consumidor, na direção em que os dados se movem. Consumidores do Kafka fazem pull, mas um diagrama com setas saindo dos consumidores para os tópicos parece invertido para quase todo mundo. Se a semântica de pull importa para a discussão, adicione uma nota.
3. Rotule eventos e grupos de consumidores
Coloque o tipo de evento na conexão do produtor e o grupo de consumidores em cada conexão de consumidor. Quando alguém perguntar "quem mais lê OrderPlaced?", a resposta é a lista de conexões rotuladas que saem do tópico.
4. Mostre a chave quando a ordem importa
O Kafka garante a ordem dentro de uma partição, e eventos com a mesma chave vão para a mesma partição. Se seus consumidores dependem de ver OrderPlaced antes de OrderCancelled, escreva a chave no tópico: orders.v1 · key order_id. Um tópico sem chave no rótulo deixa essa pergunta no ar.
5. Desenhe o caminho de falha
Os grupos de consumidores do Kafka não têm uma dead-letter queue embutida: o código do seu consumidor ou o framework decide quantas vezes tentar de novo e onde colocar uma mensagem que não consegue processar (os conectores sink do Kafka Connect têm, sim, uma configuração de tópico de dead-letter). Desenhe essa decisão. Um tópico de dead-letter com uma conexão vinda do consumidor, e uma nota sobre quem o monitora e como as mensagens são reprocessadas, evita um incidente.
Desenhe o outbox, não o atalho
Se um serviço grava no banco de dados e depois publica no Kafka em duas etapas separadas, uma queda entre elas faz com que um evento se perca ou que seja publicado um evento de uma mudança que nunca chegou a ser confirmada. O padrão outbox evita essa escrita dupla: o serviço grava o evento em uma tabela de outbox na mesma transação, e um relay o publica.
No diagrama, desenhe o caminho real: do serviço para o banco de dados, daí para o relay e do relay para o tópico. Uma seta direta do serviço para o tópico descreveria um sistema diferente e menos confiável, e as pessoas vão tomar decisões com base nela.
Coreografia ou orquestração
O exemplo usa coreografia: os serviços reagem aos eventos uns dos outros, e ninguém comanda o fluxo inteiro. Se você usar um orquestrador, ou seja, um motor de workflow que envia comandos como ReserveStock e espera as respostas, desenhe o orquestrador como um serviço no meio e rotule as conexões dele como comandos. Em qualquer caso, numere os passos do fluxo principal nas conexões para que quem lê consiga seguir a saga em ordem.
Deixe o cluster fora da visão lógica
Brokers, partições, fatores de replicação e nós controladores importam para capacidade e operação, não para entender o fluxo. Coloque-os em um diagrama de operações separado. Na visão lógica, basta um frame com o rótulo "Kafka cluster" em volta dos tópicos.
Monte no Archboard
- Entre com Google ou GitHub e crie um diagrama.
- Adicione os serviços como nós Contêiner do pack Modelo C4 e o banco de dados de orders pelo pack Dados (Postgres).
- Adicione uma Moldura do pack Básico com o rótulo
Kafka clustere coloque dentro dela nós Tópico do pack Dados. - Adicione o outbox relay e o warehouse sink como contêineres com
Kafka Connectno campo Tecnologia, e um nó Armazém de dados do pack Dados. - Conecte as portas, deixe as conexões de evento tracejadas e rotule-as com os tipos de evento e os grupos de consumidores.
- Abra o diagrama no modo apresentação para a revisão, compartilhe o link ao vivo ou exporte SVG e PNG.
O exemplo usa 11 nós de diagrama, dentro dos 15 do plano Free. Para outro layout de streaming, veja /examples/streaming-data-platform e, para o lado síncrono de uma loja parecida, o guia de diagrama de arquitetura de microsserviços.
Perguntas frequentes
Devo desenhar as partições? Não na visão lógica. Escreva o número de partições no rótulo do tópico se isso importar, e desenhe partições e brokers em um diagrama de operações.
Qual a diferença entre uma fila e um tópico no diagrama? Em uma fila, cada mensagem vai para um único consumidor; em um tópico do Kafka, cada grupo de consumidores recebe todas as mensagens. Use um nó Fila para filas como SQS ou RabbitMQ, e diga de qual semântica você depende.
Onde ficam os schemas dos eventos? Em uma nota ou no rótulo do tópico, com um link para o schema registry ou para o repositório dono do schema. O diagrama deve mostrar que existe um contrato e onde ele fica.
Como mostro o replay?
Escreva a retenção no tópico (por exemplo retention 7d) e adicione uma nota sobre como um grupo de consumidores redefine seus offsets. O replay é um recurso de design; deixe-o visível.
Preciso de um diagrama por evento? Não. Um diagrama por fluxo de negócio funciona bem. Liste os eventos nas conexões e mantenha um catálogo de eventos para a lista completa.