[{"data":1,"prerenderedAt":1555},["ShallowReactive",2],{"article-\u002Fintegracoes\u002Fevent-driven-architecture-kafka":3},{"id":4,"title":5,"author":6,"body":7,"category":1539,"date":1540,"description":1541,"extension":1542,"keywords":1543,"meta":1549,"navigation":593,"path":1550,"seo":1551,"slug":1552,"stem":1553,"updated":1540,"__hash__":1554},"content\u002Fintegracoes\u002Fevent-driven-architecture-kafka.md","Event-driven architecture com Kafka: guia prático","Inicialize Tec",{"type":8,"value":9,"toc":1502},"minimark",[10,15,86,90,103,110,117,120,141,145,151,163,166,192,280,284,287,292,305,309,316,335,349,353,359,369,375,379,383,386,400,404,407,411,422,436,446,452,456,463,486,493,497,500,504,507,511,518,529,533,544,552,556,563,567,805,808,828,832,993,996,1028,1032,1036,1065,1069,1105,1167,1171,1175,1193,1196,1219,1223,1245,1249,1268,1271,1298,1302,1397,1401,1485,1488,1498],[11,12,14],"h2",{"id":13},"índice","Índice",[16,17,18,26,32,38,44,50,56,62,68,74,80],"ol",{},[19,20,21],"li",{},[22,23,25],"a",{"href":24},"#o-que-e","O que é event-driven architecture",[19,27,28],{},[22,29,31],{"href":30},"#kafka","O que é o Apache Kafka",[19,33,34],{},[22,35,37],{"href":36},"#conceitos","Conceitos essenciais: tópicos, partitions, offsets",[19,39,40],{},[22,41,43],{"href":42},"#producers-consumers","Producers, consumers e consumer groups",[19,45,46],{},[22,47,49],{"href":48},"#pubsub-vs-fila","Pub\u002FSub vs. fila tradicional",[19,51,52],{},[22,53,55],{"href":54},"#garantias","Garantias de entrega: pelo menos uma vez, exatamente uma vez",[19,57,58],{},[22,59,61],{"href":60},"#exemplo-python","Exemplo prático em Python",[19,63,64],{},[22,65,67],{"href":66},"#quando-usar","Quando usar (e quando NÃO usar) Kafka",[19,69,70],{},[22,71,73],{"href":72},"#particoes-chaves","Esquemas, partições e chaves na prática",[19,75,76],{},[22,77,79],{"href":78},"#erros","Erros comuns",[19,81,82],{},[22,83,85],{"href":84},"#checklist","Checklist de adoção",[11,87,89],{"id":88},"o-que-é-event-driven-architecture-o-que-e","O que é event-driven architecture {#o-que-e}",[91,92,93,94,98,99,102],"p",{},"Antes de entender ",[95,96,97],"strong",{},"event-driven architecture"," (arquitetura orientada a\neventos), vale explicar a palavra-chave: ",[95,100,101],{},"evento",". Um evento é \"algo que\naconteceu no passado e foi registrado\" — um pedido foi criado, um pagamento foi\nconfirmado, um sensor detectou temperatura acima do limite. O evento é um fato\nimutável: você não \"des-faz\" um evento, no máximo emite outro que o compensa.",[91,104,105,106,109],{},"Na arquitetura tradicional (síncrona, baseada em requests), o serviço A chama\no serviço B e ",[95,107,108],{},"fica esperando"," a resposta. Pense numa ligação telefônica:\nvocê liga para o colega, ele atende, você fala, ele responde, e ninguém desliga\nenquanto a conversa não termina. Se ele não atende, você fica preso.",[91,111,112,113,116],{},"Na arquitetura orientada a eventos, o serviço A simplesmente ",[95,114,115],{},"anuncia"," que\nalgo aconteceu e segue sua vida. Pense num canal de rádio: o locutor fala \"o\npedido 1234 foi pago\" e desliga o microfone. Quem estiver ouvindo e se importar\nreage; quem não estiver ouvindo, perdeu. Ninguém fica esperando ninguém.",[91,118,119],{},"Isso traz três propriedades poderosas:",[121,122,123,129,135],"ul",{},[19,124,125,128],{},[95,126,127],{},"Desacoplamento temporal",": o produtor não precisa que o consumidor esteja\nonline no momento do evento.",[19,130,131,134],{},[95,132,133],{},"Desacoplamento espacial",": o produtor não precisa saber quem consome —\nnovos consumidores podem surgir sem o produtor mudar uma linha.",[19,136,137,140],{},[95,138,139],{},"Elasticidade",": dá para adicionar mais consumidores se o volume crescer,\nsem mexer em quem produz os eventos.",[11,142,144],{"id":143},"o-que-é-o-apache-kafka-kafka","O que é o Apache Kafka {#kafka}",[91,146,147,150],{},[95,148,149],{},"Apache Kafka"," é uma plataforma de streaming de eventos distribuída, criada\nno LinkedIn em 2011 e hoje mantida pela Confluent e pela comunidade. Em termos\nsimples, é um \"correio de alta velocidade\" para eventos.",[91,152,153,154,157,158,162],{},"A analogia mais útil: Kafka é como um ",[95,155,156],{},"correio que distribui cartas para todos\nos destinatários interessados, sem que o remetente precise saber quem são",".\nVocê entrega a carta no correio dizendo \"esta é sobre o assunto\n",[159,160,161],"code",{},"pedidos-criados","\", e o correio garante que todo assinante daquele assunto\nreceba uma cópia. O remetente não conhece os destinatários, os destinatários\nnão se conhecem entre si, e o correio guarda as cartas por vários dias caso\nalguém esteja de folga.",[91,164,165],{},"O que torna o Kafka diferente de um banco de dados ou de uma fila comum:",[16,167,168,174,180,186],{},[19,169,170,173],{},[95,171,172],{},"É um log append-only",": eventos são só acrescentados, nunca alterados\nnem apagados no fluxo normal (apagamento só por retenção por tempo\u002Ftamanho).",[19,175,176,179],{},[95,177,178],{},"Distribuído e replicado",": roda em cluster, com partições espalhadas e\nréplicas para tolerância a falhas.",[19,181,182,185],{},[95,183,184],{},"Replay",": consumidores podem \"rebobinar\" e ler eventos antigos, como um\nDVR de TV. Isso é brutalmente útil para reprocessar dados, treinar modelos\nde ML, ou reconstruir views materializadas.",[19,187,188,191],{},[95,189,190],{},"Altíssimo throughput",": centenas de milhares de eventos por segundo numa\nmáquina modesta, milhões por segundo num cluster bem ajustado.",[193,194,195,211],"table",{},[196,197,198],"thead",{},[199,200,201,205,208],"tr",{},[202,203,204],"th",{},"Característica",[202,206,207],{},"Fila tradicional (RabbitMQ)",[202,209,210],{},"Kafka",[212,213,214,226,237,247,258,269],"tbody",{},[199,215,216,220,223],{},[217,218,219],"td",{},"Modelo",[217,221,222],{},"Mensagem consumida e removida",[217,224,225],{},"Log persistente, múltiplas leituras",[199,227,228,231,234],{},[217,229,230],{},"Retenção",[217,232,233],{},"Até leitura",[217,235,236],{},"Por tempo\u002Ftamanho configurável",[199,238,239,241,244],{},[217,240,184],{},[217,242,243],{},"Não (consumida = sumiu)",[217,245,246],{},"Sim, rebobinando o offset",[199,248,249,252,255],{},[217,250,251],{},"Throughput",[217,253,254],{},"Milhares\u002Fs",[217,256,257],{},"Centenas de milhares a milhões\u002Fs",[199,259,260,263,266],{},[217,261,262],{},"Ordenação",[217,264,265],{},"Por fila",[217,267,268],{},"Por partition",[199,270,271,274,277],{},[217,272,273],{},"Caso típico",[217,275,276],{},"Comando pontual",[217,278,279],{},"Stream de eventos, integração de sistemas",[11,281,283],{"id":282},"conceitos-essenciais-tópicos-partitions-offsets-conceitos","Conceitos essenciais: tópicos, partitions, offsets {#conceitos}",[91,285,286],{},"Esses três conceitos são a base de tudo no Kafka. Vamos devagar.",[288,289,291],"h3",{"id":290},"tópico-topic","Tópico (topic)",[91,293,294,295,297,298,297,301,304],{},"Um tópico é o \"assunto\" da carta. É um canal nomeado para um tipo de evento.\nExemplos: ",[159,296,161],{},", ",[159,299,300],{},"pagamentos-confirmados",[159,302,303],{},"sensor-temperatura",".\nProdutores publicam em tópicos; consumidores assinam tópicos.",[288,306,308],{"id":307},"partition-partição","Partition (partição)",[91,310,311,312,315],{},"Cada tópico é dividido em ",[95,313,314],{},"partitions"," — pense em várias esteiras paralelas\ndo mesmo correio. A partição é o que permite escala horizontal: múltiplas\npartições significam múltiplos consumidores em paralelo.",[121,317,318,325,332],{},[19,319,320,321,324],{},"Cada evento vai para ",[95,322,323],{},"uma"," partition, decidida por uma chave (key).",[19,326,327,328,331],{},"Eventos com a mesma chave sempre vão para a mesma partition → garante\n",[95,329,330],{},"ordem por chave",".",[19,333,334],{},"Eventos em partitions diferentes não têm ordem garantida entre si.",[91,336,337,338,340,341,344,345,348],{},"Exemplo: num tópico ",[159,339,161],{}," com 6 partições, o evento com\n",[159,342,343],{},"key=cliente-123"," sempre cai na partition 2 (por hash). Assim, todos os pedidos\ndo ",[159,346,347],{},"cliente-123"," são processados em ordem pelo consumidor que pegou a partition 2.",[288,350,352],{"id":351},"offset","Offset",[91,354,355,356,358],{},"Cada evento dentro de uma partition recebe um número sequencial chamado\n",[95,357,351],{},", começando em 0. É como a numeração das páginas de um livro. O\nconsumidor registra \"li até a página 47\" e, se reiniciar, volta da página 48.\nIsso permite parar e retomar sem perder nem duplicar (se o commit for feito\ncorreto).",[360,361,366],"pre",{"className":362,"code":364,"language":365},[363],"language-text","Tópico: pedidos-criados (3 partições)\n\nPartition 0:  [evt0] [evt3] [evt6] [evt9]   ← offsets 0,1,2,3\nPartition 1:  [evt1] [evt4] [evt7] [evt10]  ← offsets 0,1,2,3\nPartition 2:  [evt2] [evt5] [evt8] [evt11]  ← offsets 0,1,2,3\n","text",[159,367,364],{"__ignoreMap":368},"",[370,371,372],"blockquote",{},[91,373,374],{},"Nota importante: o offset é por partition, não global. O evento offset 3 da\npartition 0 não é \"o quarto evento do tópico todo\".",[11,376,378],{"id":377},"producers-consumers-e-consumer-groups-producers-consumers","Producers, consumers e consumer groups {#producers-consumers}",[288,380,382],{"id":381},"producer-produtor","Producer (produtor)",[91,384,385],{},"Quem publica eventos no tópico. Pode publicar:",[121,387,388,394],{},[19,389,390,393],{},[95,391,392],{},"Com chave",": Kafka decide a partition via hash da chave → ordem garantida\npor chave.",[19,395,396,399],{},[95,397,398],{},"Sem chave",": Kafka escolhe a partition (round-robin ou sticky) → sem ordem.",[288,401,403],{"id":402},"consumer-consumidor","Consumer (consumidor)",[91,405,406],{},"Quem lê eventos do tópico. Um consumer lê de uma ou mais partitions.",[288,408,410],{"id":409},"consumer-group-grupo-de-consumidores","Consumer group (grupo de consumidores)",[91,412,413,414,417,418,421],{},"Aqui está a mágica da escala. Um ",[95,415,416],{},"consumer group"," é um conjunto de consumers\nque dividem as partitions de um tópico entre si: cada partition é lida por\n",[95,419,420],{},"exatamente um"," consumer dentro do grupo.",[121,423,424,427,430],{},[19,425,426],{},"Tópico com 6 partitions e consumer group com 6 consumers → cada consumer\npega uma partition, paralelismo máximo.",[19,428,429],{},"Consumer group com 3 consumers → cada um pega 2 partitions.",[19,431,432,433],{},"Consumer group com 10 consumers → 4 ficam parados (não há partition para\neles). ",[95,434,435],{},"Mais consumers que partitions = desperdício.",[91,437,438,439,442,443,445],{},"Diferentes consumer groups ",[95,440,441],{},"não competem",": cada grupo recebe uma cópia\ncompleta dos eventos. É o que permite que o serviço de estoque, o de\nnotificação e o de analytics leiam o mesmo ",[159,444,161],{}," independentemente.",[360,447,450],{"className":448,"code":449,"language":365},[363],"              Tópico: pedidos-criados (6 partições)\n                        │\n        ┌───────────────┼───────────────┐\n        ▼               ▼               ▼\n   Group A           Group B         Group C\n   (estoque)        (notifica)       (analytics)\n   3 consumers      6 consumers      1 consumer\n   2 parts cada    1 part cada      6 parts\n",[159,451,449],{"__ignoreMap":368},[11,453,455],{"id":454},"pubsub-vs-fila-tradicional-pubsub-vs-fila","Pub\u002FSub vs. fila tradicional {#pubsub-vs-fila}",[91,457,458,459,462],{},"O modelo ",[95,460,461],{},"pub\u002Fsub"," (publish\u002Fsubscribe) é o coração do Kafka. Diferente de\numa fila comum onde a mensagem é consumida e some, no Kafka:",[121,464,465,472,475],{},[19,466,467,468,471],{},"Cada consumer group mantém ",[95,469,470],{},"seu próprio offset"," — o Kafka não remove o\nevento quando alguém lê.",[19,473,474],{},"Múltiplos grupos independentes leem o mesmo stream.",[19,476,477,478,481,482,485],{},"A retenção é por ",[95,479,480],{},"tempo"," (ex.: 7 dias) ou ",[95,483,484],{},"tamanho"," (ex.: 10GB por\npartition), independente de leitura.",[91,487,488,489,492],{},"Isso explica por que Kafka é usado para ",[95,490,491],{},"integração entre sistemas",": o ERP,\no CRM e o data warehouse podem ler o mesmo evento de \"cliente cadastrado\" sem\nque um atrapalhe o outro. Cada um segue no seu ritmo.",[11,494,496],{"id":495},"garantias-de-entrega-pelo-menos-uma-vez-exatamente-uma-vez-garantias","Garantias de entrega: pelo menos uma vez, exatamente uma vez {#garantias}",[91,498,499],{},"Esse é o tópico que mais confunde iniciantes. Vamos com calma.",[288,501,503],{"id":502},"at-most-once-no-máximo-uma-vez","At-most-once (no máximo uma vez)",[91,505,506],{},"O produtor envia e esquece. Pode perder eventos. Raramente é o que você quer\nem negócio (perder um pagamento é grave).",[288,508,510],{"id":509},"at-least-once-pelo-menos-uma-vez","At-least-once (pelo menos uma vez)",[91,512,513,514,517],{},"O produtor reenvia enquanto não recebe confirmação. Pode haver ",[95,515,516],{},"duplicação",":\no evento chegou, mas a confirmação se perdeu, então ele é reenviado. É o\npadrão mais comum no Kafka.",[91,519,520,521,524,525,528],{},"Para lidar com duplicação, seus consumers precisam ser ",[95,522,523],{},"idempotentes"," —\nprocessar o mesmo evento duas vezes deve dar o mesmo resultado que processar\numa vez. Exemplo: usar o ",[159,526,527],{},"event_id"," como chave de deduplicação no banco.",[288,530,532],{"id":531},"exactly-once-exatamente-uma-vez","Exactly-once (exatamente uma vez)",[91,534,535,536,539,540,543],{},"Kafka suporta exactly-once com ",[95,537,538],{},"transactions API"," (produtor transacional +\n",[159,541,542],{},"read_process_write","), mas é mais complexo e tem custo de throughput. Em\nmuitos casos, at-least-once + idempotência no consumidor é mais simples e\nigualmente correto.",[370,545,546],{},[91,547,548,551],{},[95,549,550],{},"Regra prática",": prefira at-least-once + consumidor idempotente. Reserve\nexactly-once transacional para fluxos financeiros sensíveis onde a\nduplicação é cara de deduplicar.",[11,553,555],{"id":554},"exemplo-prático-em-python-exemplo-python","Exemplo prático em Python {#exemplo-python}",[91,557,558,559,562],{},"Vamos usar ",[159,560,561],{},"confluent-kafka"," (cliente Python performático, baseado em librdkafka).",[288,564,566],{"id":565},"produtor","Produtor",[360,568,572],{"className":569,"code":570,"language":571,"meta":368,"style":368},"language-python shiki shiki-themes github-light github-dark","from confluent_kafka import Producer\nimport json\n\n# Configuração do produtor\nconf = {\n    \"bootstrap.servers\": \"kafka1:9092,kafka2:9092\",  # brokers do cluster\n    \"client.id\": \"pedido-service\",\n    \"acks\": \"all\",        # espera confirmação de todas as réplicas → seguro\n    \"retries\": 5,         # reenvia em caso de falha transitória\n    \"enable.idempotence\": True,  # produtor idempotente → sem duplicação no broker\n}\n\nproducer = Producer(conf)\n\ndef delivery_report(err, msg):\n    \"\"\"Callback chamado quando o broker confirma (ou falha) a entrega.\"\"\"\n    if err is not None:\n        print(f\"Falha ao entregar evento: {err}\")\n    else:\n        print(f\"Entregue em {msg.topic()}[{msg.partition()}]@{msg.offset()}\")\n\n# Publicando um evento com chave = customer_id (ordem garantida por cliente)\nevento = {\n    \"event_id\": \"a1b2c3\",\n    \"order_id\": 4567,\n    \"customer_id\": \"cliente-123\",\n    \"total\": 199.90,\n    \"timestamp\": \"2026-08-26T10:15:00Z\",\n}\n\nproducer.produce(\n    topic=\"pedidos-criados\",\n    key=evento[\"customer_id\"].encode(\"utf-8\"),  # chave → partição estável\n    value=json.dumps(evento).encode(\"utf-8\"),\n    callback=delivery_report,\n)\n\n# Garante que todas as mensagens pendentes sejam enviadas antes de sair\nproducer.flush()\n","python",[159,573,574,582,588,595,601,607,613,619,625,631,637,643,648,654,659,665,671,677,683,689,695,700,706,712,718,724,730,736,742,747,752,758,764,770,776,782,788,793,799],{"__ignoreMap":368},[575,576,579],"span",{"class":577,"line":578},"line",1,[575,580,581],{},"from confluent_kafka import Producer\n",[575,583,585],{"class":577,"line":584},2,[575,586,587],{},"import json\n",[575,589,591],{"class":577,"line":590},3,[575,592,594],{"emptyLinePlaceholder":593},true,"\n",[575,596,598],{"class":577,"line":597},4,[575,599,600],{},"# Configuração do produtor\n",[575,602,604],{"class":577,"line":603},5,[575,605,606],{},"conf = {\n",[575,608,610],{"class":577,"line":609},6,[575,611,612],{},"    \"bootstrap.servers\": \"kafka1:9092,kafka2:9092\",  # brokers do cluster\n",[575,614,616],{"class":577,"line":615},7,[575,617,618],{},"    \"client.id\": \"pedido-service\",\n",[575,620,622],{"class":577,"line":621},8,[575,623,624],{},"    \"acks\": \"all\",        # espera confirmação de todas as réplicas → seguro\n",[575,626,628],{"class":577,"line":627},9,[575,629,630],{},"    \"retries\": 5,         # reenvia em caso de falha transitória\n",[575,632,634],{"class":577,"line":633},10,[575,635,636],{},"    \"enable.idempotence\": True,  # produtor idempotente → sem duplicação no broker\n",[575,638,640],{"class":577,"line":639},11,[575,641,642],{},"}\n",[575,644,646],{"class":577,"line":645},12,[575,647,594],{"emptyLinePlaceholder":593},[575,649,651],{"class":577,"line":650},13,[575,652,653],{},"producer = Producer(conf)\n",[575,655,657],{"class":577,"line":656},14,[575,658,594],{"emptyLinePlaceholder":593},[575,660,662],{"class":577,"line":661},15,[575,663,664],{},"def delivery_report(err, msg):\n",[575,666,668],{"class":577,"line":667},16,[575,669,670],{},"    \"\"\"Callback chamado quando o broker confirma (ou falha) a entrega.\"\"\"\n",[575,672,674],{"class":577,"line":673},17,[575,675,676],{},"    if err is not None:\n",[575,678,680],{"class":577,"line":679},18,[575,681,682],{},"        print(f\"Falha ao entregar evento: {err}\")\n",[575,684,686],{"class":577,"line":685},19,[575,687,688],{},"    else:\n",[575,690,692],{"class":577,"line":691},20,[575,693,694],{},"        print(f\"Entregue em {msg.topic()}[{msg.partition()}]@{msg.offset()}\")\n",[575,696,698],{"class":577,"line":697},21,[575,699,594],{"emptyLinePlaceholder":593},[575,701,703],{"class":577,"line":702},22,[575,704,705],{},"# Publicando um evento com chave = customer_id (ordem garantida por cliente)\n",[575,707,709],{"class":577,"line":708},23,[575,710,711],{},"evento = {\n",[575,713,715],{"class":577,"line":714},24,[575,716,717],{},"    \"event_id\": \"a1b2c3\",\n",[575,719,721],{"class":577,"line":720},25,[575,722,723],{},"    \"order_id\": 4567,\n",[575,725,727],{"class":577,"line":726},26,[575,728,729],{},"    \"customer_id\": \"cliente-123\",\n",[575,731,733],{"class":577,"line":732},27,[575,734,735],{},"    \"total\": 199.90,\n",[575,737,739],{"class":577,"line":738},28,[575,740,741],{},"    \"timestamp\": \"2026-08-26T10:15:00Z\",\n",[575,743,745],{"class":577,"line":744},29,[575,746,642],{},[575,748,750],{"class":577,"line":749},30,[575,751,594],{"emptyLinePlaceholder":593},[575,753,755],{"class":577,"line":754},31,[575,756,757],{},"producer.produce(\n",[575,759,761],{"class":577,"line":760},32,[575,762,763],{},"    topic=\"pedidos-criados\",\n",[575,765,767],{"class":577,"line":766},33,[575,768,769],{},"    key=evento[\"customer_id\"].encode(\"utf-8\"),  # chave → partição estável\n",[575,771,773],{"class":577,"line":772},34,[575,774,775],{},"    value=json.dumps(evento).encode(\"utf-8\"),\n",[575,777,779],{"class":577,"line":778},35,[575,780,781],{},"    callback=delivery_report,\n",[575,783,785],{"class":577,"line":784},36,[575,786,787],{},")\n",[575,789,791],{"class":577,"line":790},37,[575,792,594],{"emptyLinePlaceholder":593},[575,794,796],{"class":577,"line":795},38,[575,797,798],{},"# Garante que todas as mensagens pendentes sejam enviadas antes de sair\n",[575,800,802],{"class":577,"line":801},39,[575,803,804],{},"producer.flush()\n",[91,806,807],{},"Pontos-chave do código acima:",[121,809,810,816,822],{},[19,811,812,815],{},[159,813,814],{},"acks=all",": o evento só é confirmado quando todas as réplicas in-sync\ngravam — máxima durabilidade.",[19,817,818,821],{},[159,819,820],{},"enable.idempotence=True",": mesmo se o produtor reenviar, o broker descarta\nduplicatas baseado em PID (Producer ID) e sequência.",[19,823,824,827],{},[159,825,826],{},"key=customer_id",": garante que todos os eventos do mesmo cliente caiam na\nmesma partition, preservando ordem por cliente.",[288,829,831],{"id":830},"consumidor","Consumidor",[360,833,835],{"className":569,"code":834,"language":571,"meta":368,"style":368},"from confluent_kafka import Consumer\nimport json\n\nconf = {\n    \"bootstrap.servers\": \"kafka1:9092,kafka2:9092\",\n    \"group.id\": \"estoque-service\",        # identidade do consumer group\n    \"auto.offset.reset\": \"earliest\",      # começa do início se não houver offset salvo\n    \"enable.auto.commit\": False,          # commit manual → controle de \"processado\"\n}\n\nconsumer = Consumer(conf)\nconsumer.subscribe([\"pedidos-criados\"])\n\ntry:\n    while True:\n        msg = consumer.poll(1.0)          # espera até 1s por uma mensagem\n        if msg is None:\n            continue                      # sem mensagem neste instante\n        if msg.error():\n            print(f\"Erro: {msg.error()}\")\n            continue\n\n        evento = json.loads(msg.value())\n\n        # IDEMPOTÊNCIA: usa event_id para não duplicar o processamento\n        # Em produção: INSERT ... ON CONFLICT (event_id) DO NOTHING\n        reservar_estoque(evento[\"order_id\"], evento[\"customer_id\"])\n\n        # Só confirma o offset DEPOIS de processar com sucesso\n        # Se o processo cair antes disso, o evento será reprocessado ao reiniciar\n        consumer.commit(msg)\nfinally:\n    consumer.close()\n",[159,836,837,842,846,850,854,859,864,869,874,878,882,887,892,896,901,906,911,916,921,926,931,936,940,945,949,954,959,964,968,973,978,983,988],{"__ignoreMap":368},[575,838,839],{"class":577,"line":578},[575,840,841],{},"from confluent_kafka import Consumer\n",[575,843,844],{"class":577,"line":584},[575,845,587],{},[575,847,848],{"class":577,"line":590},[575,849,594],{"emptyLinePlaceholder":593},[575,851,852],{"class":577,"line":597},[575,853,606],{},[575,855,856],{"class":577,"line":603},[575,857,858],{},"    \"bootstrap.servers\": \"kafka1:9092,kafka2:9092\",\n",[575,860,861],{"class":577,"line":609},[575,862,863],{},"    \"group.id\": \"estoque-service\",        # identidade do consumer group\n",[575,865,866],{"class":577,"line":615},[575,867,868],{},"    \"auto.offset.reset\": \"earliest\",      # começa do início se não houver offset salvo\n",[575,870,871],{"class":577,"line":621},[575,872,873],{},"    \"enable.auto.commit\": False,          # commit manual → controle de \"processado\"\n",[575,875,876],{"class":577,"line":627},[575,877,642],{},[575,879,880],{"class":577,"line":633},[575,881,594],{"emptyLinePlaceholder":593},[575,883,884],{"class":577,"line":639},[575,885,886],{},"consumer = Consumer(conf)\n",[575,888,889],{"class":577,"line":645},[575,890,891],{},"consumer.subscribe([\"pedidos-criados\"])\n",[575,893,894],{"class":577,"line":650},[575,895,594],{"emptyLinePlaceholder":593},[575,897,898],{"class":577,"line":656},[575,899,900],{},"try:\n",[575,902,903],{"class":577,"line":661},[575,904,905],{},"    while True:\n",[575,907,908],{"class":577,"line":667},[575,909,910],{},"        msg = consumer.poll(1.0)          # espera até 1s por uma mensagem\n",[575,912,913],{"class":577,"line":673},[575,914,915],{},"        if msg is None:\n",[575,917,918],{"class":577,"line":679},[575,919,920],{},"            continue                      # sem mensagem neste instante\n",[575,922,923],{"class":577,"line":685},[575,924,925],{},"        if msg.error():\n",[575,927,928],{"class":577,"line":691},[575,929,930],{},"            print(f\"Erro: {msg.error()}\")\n",[575,932,933],{"class":577,"line":697},[575,934,935],{},"            continue\n",[575,937,938],{"class":577,"line":702},[575,939,594],{"emptyLinePlaceholder":593},[575,941,942],{"class":577,"line":708},[575,943,944],{},"        evento = json.loads(msg.value())\n",[575,946,947],{"class":577,"line":714},[575,948,594],{"emptyLinePlaceholder":593},[575,950,951],{"class":577,"line":720},[575,952,953],{},"        # IDEMPOTÊNCIA: usa event_id para não duplicar o processamento\n",[575,955,956],{"class":577,"line":726},[575,957,958],{},"        # Em produção: INSERT ... ON CONFLICT (event_id) DO NOTHING\n",[575,960,961],{"class":577,"line":732},[575,962,963],{},"        reservar_estoque(evento[\"order_id\"], evento[\"customer_id\"])\n",[575,965,966],{"class":577,"line":738},[575,967,594],{"emptyLinePlaceholder":593},[575,969,970],{"class":577,"line":744},[575,971,972],{},"        # Só confirma o offset DEPOIS de processar com sucesso\n",[575,974,975],{"class":577,"line":749},[575,976,977],{},"        # Se o processo cair antes disso, o evento será reprocessado ao reiniciar\n",[575,979,980],{"class":577,"line":754},[575,981,982],{},"        consumer.commit(msg)\n",[575,984,985],{"class":577,"line":760},[575,986,987],{},"finally:\n",[575,989,990],{"class":577,"line":766},[575,991,992],{},"    consumer.close()\n",[91,994,995],{},"Repare em três decisões críticas desse consumidor:",[16,997,998,1010,1016],{},[19,999,1000,1005,1006,1009],{},[95,1001,1002],{},[159,1003,1004],{},"enable.auto.commit=False",": o offset só avança quando ",[95,1007,1008],{},"você"," decide.\nCom auto-commit, o Kafka pode marcar como lido antes do processamento\nterminar — se o processo cair, você perde o evento.",[19,1011,1012,1015],{},[95,1013,1014],{},"Commit manual após processar",": garante at-least-once. Se der crash entre\nprocessar e commitar, o evento é reprocessado (daí a idempotência).",[19,1017,1018,1023,1024,1027],{},[95,1019,1020,1021],{},"Idempotência com ",[159,1022,527],{},": o ",[159,1025,1026],{},"INSERT ... ON CONFLICT DO NOTHING"," evita\nduplicar a reserva de estoque caso o evento seja reprocessado.",[11,1029,1031],{"id":1030},"quando-usar-e-quando-não-usar-kafka-quando-usar","Quando usar (e quando NÃO usar) Kafka {#quando-usar}",[288,1033,1035],{"id":1034},"use-kafka-quando","Use Kafka quando…",[121,1037,1038,1044,1050,1056,1062],{},[19,1039,1040,1043],{},[95,1041,1042],{},"Vários sistemas precisam reagir ao mesmo fato",": pedido criado dispara\nestoque, notificação, analytics, faturamento. Pub\u002FSub brilha aqui.",[19,1045,1046,1049],{},[95,1047,1048],{},"Volume muito alto",": milhões de eventos\u002Fdia, em que uma fila comum sente.",[19,1051,1052,1055],{},[95,1053,1054],{},"Replay é necessário",": reconstruir uma base, treinar modelo, reprocessar\napós bug.",[19,1057,1058,1061],{},[95,1059,1060],{},"Integração de dados",": alimentar data lake, warehouse e caches a partir\nde um único stream (CDC — change data capture).",[19,1063,1064],{},"** buffering entre produtores e consumidores**: produtores em picos, consumidores\nconstantes — Kafka absorve o pico no log.",[288,1066,1068],{"id":1067},"não-use-kafka-quando","NÃO use Kafka quando…",[121,1070,1071,1077,1087,1093,1099],{},[19,1072,1073,1076],{},[95,1074,1075],{},"Simples fila de tarefas",": worker pegar job, processar, pronto. RabbitMQ,\nSQS ou Redis Streams são mais simples e baratos.",[19,1078,1079,1082,1083,1086],{},[95,1080,1081],{},"Solicitação-resposta síncrona",": o cliente precisa da resposta ",[95,1084,1085],{},"agora",".\nKafka não foi feito para RPC. Use REST\u002FgRPC.",[19,1088,1089,1092],{},[95,1090,1091],{},"Time pequeno, volume baixo",": a complexidade operacional do Kafka (cluster,\nZooKeeper\u002FKRaft, monitoramento de lag) não se paga. Use um broker simples.",[19,1094,1095,1098],{},[95,1096,1097],{},"Mensagens grandes",": Kafka é otimizado para mensagens pequenas (KBs).\nArquivos grandes devem ir para object storage e o evento só carrega a URL.",[19,1100,1101,1104],{},[95,1102,1103],{},"Fila com prioridade",": Kafka não tem prioridade nativa entre mensagens\ndo mesmo tópico. Para isso, use RabbitMQ com filas prioritárias.",[193,1106,1107,1117],{},[196,1108,1109],{},[199,1110,1111,1114],{},[202,1112,1113],{},"Cenário",[202,1115,1116],{},"Ferramenta recomendada",[212,1118,1119,1127,1135,1143,1151,1159],{},[199,1120,1121,1124],{},[217,1122,1123],{},"Worker queue simples",[217,1125,1126],{},"RabbitMQ, SQS, Redis",[199,1128,1129,1132],{},[217,1130,1131],{},"Pub\u002FSub de alta escala",[217,1133,1134],{},"Kafka, Pulsar",[199,1136,1137,1140],{},[217,1138,1139],{},"RPC síncrono",[217,1141,1142],{},"REST, gRPC",[199,1144,1145,1148],{},[217,1146,1147],{},"Streaming + processamento",[217,1149,1150],{},"Kafka + Flink\u002FStreams",[199,1152,1153,1156],{},[217,1154,1155],{},"Notificação simples entre serviços",[217,1157,1158],{},"RabbitMQ, SNS",[199,1160,1161,1164],{},[217,1162,1163],{},"Event sourcing \u002F log de domínio",[217,1165,1166],{},"Kafka, EventStoreDB",[11,1168,1170],{"id":1169},"esquemas-partições-e-chaves-na-prática-particoes-chaves","Esquemas, partições e chaves na prática {#particoes-chaves}",[288,1172,1174],{"id":1173},"esquema-schema-dos-eventos","Esquema (schema) dos eventos",[91,1176,1177,1178,1181,1182,297,1185,1188,1189,1192],{},"Eventos sem contrato quebram consumidores a cada mudança. Use um ",[95,1179,1180],{},"schema\nregistry"," (Confluent Schema Registry, Apicurio) com ",[95,1183,1184],{},"Avro",[95,1186,1187],{},"Protobuf","\nou ",[95,1190,1191],{},"JSON Schema",". O registro valida que cada evento respeita o contrato e\npermite evolução compatível (backward\u002Fforward compatibility).",[91,1194,1195],{},"Boas práticas de schema:",[121,1197,1198,1213,1216],{},[19,1199,1200,1201,297,1203,297,1206,297,1209,1212],{},"Inclua ",[159,1202,527],{},[159,1204,1205],{},"event_type",[159,1207,1208],{},"timestamp",[159,1210,1211],{},"version"," em todo evento.",[19,1214,1215],{},"Nunca remova campos — marque como deprecated e mantenha nullable.",[19,1217,1218],{},"Adicione campos novos como opcionais (default) para não quebrar consumidores\nantigos.",[288,1220,1222],{"id":1221},"quantas-partições","Quantas partições?",[121,1224,1225,1232,1242],{},[19,1226,1227,1228,1231],{},"Calcule pelo ",[95,1229,1230],{},"throughput desejado dividido pela capacidade de cada consumidor",".\nSe 1 consumidor processa 1.000 eventos\u002Fs e você precisa de 6.000\u002Fs, precisa\nde no mínimo 6 partições (e 6 consumers).",[19,1233,1234,1237,1238,1241],{},[95,1235,1236],{},"Arredonde para cima com folga",": partições são baratas, mas ",[95,1239,1240],{},"não dá para\ndiminuir"," depois de criadas (precisa recriar o tópico).",[19,1243,1244],{},"Considere paralelismo futuro: mais partições hoje = headroom para escalar\nconsumers amanhã.",[288,1246,1248],{"id":1247},"escolha-da-chave","Escolha da chave",[91,1250,1251,1252,1255,1256,1259,1260,1263,1264,1267],{},"A chave decide a partition e, portanto, a ",[95,1253,1254],{},"ordem garantida",". Pergunte:\n\"para qual entidade a ordem dos eventos importa?\". Se for por cliente, use\n",[159,1257,1258],{},"customer_id"," como chave. Se for por pedido, use ",[159,1261,1262],{},"order_id",". Cuidado com\nchaves de baixa cardinalidade (ex.: 10 regiões) que causam ",[95,1265,1266],{},"hot partitions",":\numa partition recebe quase todo o tráfego e vira gargalo.",[288,1269,230],{"id":1270},"retenção",[121,1272,1273,1283,1292],{},[19,1274,1275,1278,1279,1282],{},[95,1276,1277],{},"Por tempo",": ",[159,1280,1281],{},"retention.ms=604800000"," (7 dias). Padrão comum.",[19,1284,1285,1278,1288,1291],{},[95,1286,1287],{},"Por tamanho",[159,1289,1290],{},"retention.bytes=10737418240"," (10GB por partition).",[19,1293,1294,1297],{},[95,1295,1296],{},"Log compaction",": para tópicos de \"estado atual\" (ex.: saldos de conta),\nKafka mantém só o último valor por chave. Útil para materializar views.",[11,1299,1301],{"id":1300},"erros-comuns-erros","Erros comuns {#erros}",[16,1303,1304,1312,1318,1324,1334,1340,1350,1367,1373,1379],{},[19,1305,1306,1309,1310,331],{},[95,1307,1308],{},"Consumer sem idempotência",": duplica reservas\u002Fpagamentos quando há\nreprocessamento. Sempre deduque por ",[159,1311,527],{},[19,1313,1314,1317],{},[95,1315,1316],{},"Auto-commit ligado",": o offset avança antes do processamento terminar.\nCrash no meio = evento perdido. Desligue e faça commit manual.",[19,1319,1320,1323],{},[95,1321,1322],{},"Poucas partições para o volume",": consumers parados, lag crescente.\nCalcule partições pelo throughput e deixe folga.",[19,1325,1326,1329,1330,1333],{},[95,1327,1328],{},"Chave errada \u002F hot partition",": usar ",[159,1331,1332],{},"country=BR"," como chave quando 90%\ndos seus clientes são brasileiros concentra tudo numa partition. Use\nchaves de alta cardinalidade.",[19,1335,1336,1339],{},[95,1337,1338],{},"Mensagens gigantes",": mandar PDF\u002Fimagem dentro do evento. Kafka sofre\ncom mensagens grandes. Use object storage e passe a URL.",[19,1341,1342,1345,1346,1349],{},[95,1343,1344],{},"Ignorar lag",": não monitorar o ",[159,1347,1348],{},"consumer_lag"," é não saber que seu\npipeline está atrasado. Alertas em lag crescente são obrigatórios.",[19,1351,1352,1355,1356,1359,1360,297,1363,1366],{},[95,1353,1354],{},"Tópico único para tudo event types",": misturar ",[159,1357,1358],{},"pedido.criado",",\n",[159,1361,1362],{},"pagamento.aprovado",[159,1364,1365],{},"usuario.atualizado"," num tópico só obriga todos os\nconsumers a filtrar. Separe por domínio\u002Fevent type.",[19,1368,1369,1372],{},[95,1370,1371],{},"Sem schema registry",": consumidores quebram a cada mudança de campo.\nVersione e valide os eventos.",[19,1374,1375,1378],{},[95,1376,1377],{},"Tratar Kafka como banco de dados",": consultar o mesmo evento de forma\naleatória é lento e caro. Kafka é log sequencial, não é store de lookup.",[19,1380,1381,1384,1385,1388,1389,1392,1393,1396],{},[95,1382,1383],{},"Cluster mal dimensionado",": poucos brokers = risco de perda de dados se\n",[159,1386,1387],{},"min.insync.replicas"," não for respeitado. No mínimo 3 brokers com\n",[159,1390,1391],{},"replication.factor=3"," e ",[159,1394,1395],{},"min.insync.replicas=2"," para produção.",[11,1398,1400],{"id":1399},"checklist-de-adoção-checklist","Checklist de adoção {#checklist}",[121,1402,1405,1414,1420,1426,1432,1441,1447,1453,1459,1467,1473,1479],{"className":1403},[1404],"contains-task-list",[19,1406,1409,1413],{"className":1407},[1408],"task-list-item",[1410,1411],"input",{"disabled":593,"type":1412},"checkbox"," Definiu se o problema é pub\u002Fsub de escala (Kafka) ou fila simples (RabbitMQ)",[19,1415,1417,1419],{"className":1416},[1408],[1410,1418],{"disabled":593,"type":1412}," Esquema de eventos versionado em schema registry",[19,1421,1423,1425],{"className":1422},[1408],[1410,1424],{"disabled":593,"type":1412}," Particionamento calculado pelo throughput + folga",[19,1427,1429,1431],{"className":1428},[1408],[1410,1430],{"disabled":593,"type":1412}," Chave de partição escolhida para ordem por entidade correta",[19,1433,1435,1437,1438,1440],{"className":1434},[1408],[1410,1436],{"disabled":593,"type":1412}," Produtores com ",[159,1439,814],{}," e idempotência",[19,1442,1444,1446],{"className":1443},[1408],[1410,1445],{"disabled":593,"type":1412}," Consumidores com commit manual e idempotência",[19,1448,1450,1452],{"className":1449},[1408],[1410,1451],{"disabled":593,"type":1412}," Monitoramento de consumer lag com alertas",[19,1454,1456,1458],{"className":1455},[1408],[1410,1457],{"disabled":593,"type":1412}," Retenção configurada (tempo e\u002Fou tamanho) por tópico",[19,1460,1462,1464,1465],{"className":1461},[1408],[1410,1463],{"disabled":593,"type":1412}," Cluster com no mínimo 3 brokers, ",[159,1466,1391],{},[19,1468,1470,1472],{"className":1469},[1408],[1410,1471],{"disabled":593,"type":1412}," Tópicos separados por domínio\u002Fevent type",[19,1474,1476,1478],{"className":1475},[1408],[1410,1477],{"disabled":593,"type":1412}," Estratégia de DLQ (dead letter queue) para eventos que falham",[19,1480,1482,1484],{"className":1481},[1408],[1410,1483],{"disabled":593,"type":1412}," Testes de caos: matar broker, reiniciar consumer, simular reprocessamento",[1486,1487],"hr",{},[91,1489,1490,1493,1494,331],{},[95,1491,1492],{},"Construindo integrações orientadas a eventos?"," A Inicialize Tec projeta e\nimplementa pipelines com Kafka — da modelagem de tópicos e esquemas aos\nconsumidores idempotentes e monitoramento de lag. ",[22,1495,1497],{"href":1496},"\u002F#top","Conversamos sobre seu caso",[1499,1500,1501],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":368,"searchDepth":590,"depth":590,"links":1503},[1504,1505,1506,1507,1512,1517,1518,1523,1527,1531,1537,1538],{"id":13,"depth":584,"text":14},{"id":88,"depth":584,"text":89},{"id":143,"depth":584,"text":144},{"id":282,"depth":584,"text":283,"children":1508},[1509,1510,1511],{"id":290,"depth":590,"text":291},{"id":307,"depth":590,"text":308},{"id":351,"depth":590,"text":352},{"id":377,"depth":584,"text":378,"children":1513},[1514,1515,1516],{"id":381,"depth":590,"text":382},{"id":402,"depth":590,"text":403},{"id":409,"depth":590,"text":410},{"id":454,"depth":584,"text":455},{"id":495,"depth":584,"text":496,"children":1519},[1520,1521,1522],{"id":502,"depth":590,"text":503},{"id":509,"depth":590,"text":510},{"id":531,"depth":590,"text":532},{"id":554,"depth":584,"text":555,"children":1524},[1525,1526],{"id":565,"depth":590,"text":566},{"id":830,"depth":590,"text":831},{"id":1030,"depth":584,"text":1031,"children":1528},[1529,1530],{"id":1034,"depth":590,"text":1035},{"id":1067,"depth":590,"text":1068},{"id":1169,"depth":584,"text":1170,"children":1532},[1533,1534,1535,1536],{"id":1173,"depth":590,"text":1174},{"id":1221,"depth":590,"text":1222},{"id":1247,"depth":590,"text":1248},{"id":1270,"depth":590,"text":230},{"id":1300,"depth":584,"text":1301},{"id":1399,"depth":584,"text":1400},"integracoes","2026-08-26","Aprenda arquitetura orientada a eventos com Apache Kafka: producers, consumers, tópicos e quando usar — com exemplos em Python e analogias do dia-a-dia.","md",[1544,1545,1546,461,1547,149,1548],"kafka","event-driven","mensageria","eventos","microserviços comunicação",{},"\u002Fintegracoes\u002Fevent-driven-architecture-kafka",{"title":5,"description":1541},"event-driven-architecture-kafka","integracoes\u002Fevent-driven-architecture-kafka","DstY79jPycoaD0CYBvFn7pLhzps7hIhiDSYVYl7SQW0",1787796309109]