{"id":38172,"date":"2019-10-31T22:22:05","date_gmt":"2019-10-31T19:22:05","guid":{"rendered":"https:\/\/prohoster.info\/blog\/ponimanie-brokerov-soobshhenij-izuchenie-mehaniki-obmena-soobshheniyami-posredstvom-activemq-i-kafka-glava-3-kafka\/"},"modified":"2019-10-31T22:22:05","modified_gmt":"2019-10-31T19:22:05","slug":"ponimanie-brokerov-soobshhenij-izuchenie-mehaniki-obmena-soobshheniyami-posredstvom-activemq-i-kafka-glava-3-kafka","status":"publish","type":"post","link":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/ponimanie-brokerov-soobshhenij-izuchenie-mehaniki-obmena-soobshheniyami-posredstvom-activemq-i-kafka-glava-3-kafka","title":{"rendered":"Entendimento de corretores de mensagens. Estudo da mec\u00e2nica de troca de mensagens atrav\u00e9s do ActiveMQ e Kafka. Cap\u00edtulo 3. Kafka","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Continua\u00e7\u00e3o da tradu\u00e7\u00e3o de um pequeno livro:<br \/>\n\u00abUnderstanding Message Brokers\u00bb,<br \/>\nautor: Jakub Korab, editora: O'Reilly Media, Inc., data de publica\u00e7\u00e3o: junho de 2017, ISBN: 9781492049296.<\/p>\n<p>Parte anterior traduzida: <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/466385\/\">Entendimento de corretores de mensagens. Estudo da mec\u00e2nica de troca de mensagens atrav\u00e9s do ActiveMQ e Kafka. Cap\u00edtulo 1. Introdu\u00e7\u00e3o<\/a><\/noindex><br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>CAP\u00cdTULO 3<\/h2>\n<p><\/p>\n<h2>Kafka<\/h2>\n<p>\nKafka foi desenvolvido no LinkedIn para contornar algumas limita\u00e7\u00f5es dos corretores de mensagens tradicionais e evitar a necessidade de configurar v\u00e1rios corretores de mensagens para diferentes intera\u00e7\u00f5es 'ponto a ponto', como descrito neste livro na se\u00e7\u00e3o 'Escalonamento Vertical e Horizontal' na p\u00e1gina 28. Os cen\u00e1rios de uso no LinkedIn foram, em sua maioria, baseados em absor\u00e7\u00e3o unidirecional de grandes volumes de dados, como cliques em p\u00e1ginas e logs de acesso, permitindo ao mesmo tempo que esses dados fossem utilizados por v\u00e1rios sistemas, sem impactar a performance dos produtores ou de outros consumidores. De fato, a raz\u00e3o da exist\u00eancia do Kafka \u00e9 estabelecer uma arquitetura de troca de mensagens, conforme descrito no Universal Data Pipeline.<\/p>\n<p>Considerando esse objetivo final, naturalmente surgiram outras exig\u00eancias. O Kafka deve:<\/p>\n<ul>\n<li>Ser extremamente r\u00e1pido<\/li>\n<li>Fornecer alta capacidade de processamento ao lidar com mensagens<\/li>\n<li>Suportar modelos 'Publicador-Assinante' e 'Ponto a Ponto'<\/li>\n<li>N\u00e3o desacelerar com a adi\u00e7\u00e3o de consumidores. Por exemplo, a performance tanto das filas quanto dos t\u00f3picos no ActiveMQ se deteriora com o aumento do n\u00famero de consumidores no destinat\u00e1rio<\/li>\n<li>Ser escal\u00e1vel horizontalmente; se um corretor que persiste mensagens s\u00f3 pode fazer isso na velocidade m\u00e1xima do disco, ent\u00e3o faz sentido ultrapassar a capacidade de uma \u00fanica inst\u00e2ncia de corretor para aumentar a performance<\/li>\n<li>Delimitar o acesso ao armazenamento e \u00e0 recupera\u00e7\u00e3o de mensagens<\/li>\n<\/ul>\n<p>\nPara alcan\u00e7ar tudo isso, o Kafka adotou uma arquitetura que redefiniu os pap\u00e9is e responsabilidades dos clientes e dos corretores de mensagens. O modelo JMS \u00e9 muito centrado no corretor, onde ele \u00e9 respons\u00e1vel pela distribui\u00e7\u00e3o de mensagens, enquanto os clientes precisam se preocupar apenas em enviar e receber mensagens. O Kafka, por outro lado, \u00e9 centrado no cliente, onde o cliente assume muitas fun\u00e7\u00f5es do corretor tradicional, como a distribui\u00e7\u00e3o justa de mensagens relevantes entre os consumidores, em troca de um corretor extremamente r\u00e1pido e escal\u00e1vel. Para aqueles que trabalharam com sistemas tradicionais de troca de mensagens, trabalhar com o Kafka exige mudan\u00e7as fundamentais na forma de pensar.<br \/>\nEssa abordagem de engenharia levou \u00e0 cria\u00e7\u00e3o de uma infraestrutura de troca de mensagens capaz de aumentar a largura de banda em muitos pedidos em compara\u00e7\u00e3o com um corretor convencional. Como veremos, essa abordagem envolve compromissos que significam que o Kafka n\u00e3o \u00e9 adequado para certos tipos de cargas de trabalho e software estabelecido.<\/p>\n<h3>Modelo unificado de destinat\u00e1rio<\/h3>\n<p>\nPara atender aos requisitos mencionados acima, o Kafka combinou mensagens do tipo 'publica\u00e7\u00e3o-assinatura' e 'ponto-a-ponto' em um \u00fanico tipo de destinat\u00e1rio \u2014 <i>t\u00f3pico<\/i>. Isso confunde pessoas que trabalharam com sistemas de troca de mensagens onde a palavra 't\u00f3pico' se refere a um mecanismo de transmiss\u00e3o, do qual a leitura (do t\u00f3pico) n\u00e3o \u00e9 confi\u00e1vel (\u00e9 n\u00e3o dur\u00e1vel). Os t\u00f3picos no Kafka devem ser vistos como um tipo h\u00edbrido de destinat\u00e1rio, de acordo com a defini\u00e7\u00e3o fornecida na introdu\u00e7\u00e3o deste livro.<\/p>\n<blockquote><p>Na restante parte deste cap\u00edtulo, a menos que indiquemos explicitamente o contr\u00e1rio, o termo 't\u00f3pico' se referir\u00e1 ao t\u00f3pico do Kafka.<\/p><\/blockquote>\n<p>\nPara entender completamente como os t\u00f3picos se comportam e quais garantias oferecem, devemos primeiro considerar como eles s\u00e3o implementados no Kafka.<br \/>\n<i>Cada t\u00f3pico no Kafka tem seu pr\u00f3prio log.<\/i><br \/>\nOs produtores que enviam mensagens para o Kafka escrevem neste log, enquanto os consumidores leem do log usando ponteiros que se movem constantemente para frente. Periodicamente, o Kafka remove as partes mais antigas do log, independentemente de as mensagens nessas partes terem sido lidas ou n\u00e3o. A parte central do design do Kafka \u00e9 que o broker n\u00e3o se preocupa se as mensagens foram lidas ou n\u00e3o \u2014 essa \u00e9 uma responsabilidade do cliente.<\/p>\n<blockquote><p>Os termos \u201clog\u201d e \u201cponteiro\u201d n\u00e3o aparecem na <noindex><a rel=\"nofollow\" href=\"https:\/\/kafka.apache.org\/documentation.html\">documenta\u00e7\u00e3o do Kafka<\/a><\/noindex>. Estes termos bem conhecidos s\u00e3o utilizados aqui para ajudar na compreens\u00e3o.<\/p><\/blockquote>\n<p>\nEste modelo \u00e9 completamente diferente do ActiveMQ, onde as mensagens de todas as filas s\u00e3o armazenadas em um \u00fanico log e o broker marca as mensagens como removidas depois que foram lidas.<br \/>\nVamos agora nos aprofundar um pouco e examinar o log do t\u00f3pico com mais detalhes.<br \/>\nO log do Kafka consiste em v\u00e1rias parti\u00e7\u00f5es (<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/tm\/w2\/yf\/tmw2yf3lanppqtrumxoidotplhi.png\">Figura 3-1<\/a><\/noindex>). O Kafka garante uma ordena\u00e7\u00e3o estrita em cada parti\u00e7\u00e3o. Isso significa que as mensagens gravadas em uma parti\u00e7\u00e3o em uma determinada ordem ser\u00e3o lidas na mesma ordem. Cada parti\u00e7\u00e3o \u00e9 implementada como um arquivo de log c\u00edclico (rolling) que cont\u00e9m <i>um subconjunto <\/i>(subset) de todas as mensagens enviadas para o t\u00f3pico por seus produtores. O t\u00f3pico criado cont\u00e9m por padr\u00e3o uma parti\u00e7\u00e3o. A ideia de parti\u00e7\u00f5es \u00e9 o conceito central do Kafka para escalabilidade horizontal.<\/p>\n<p><img decoding=\"async\" alt=\"Entendimento de corretores de mensagens. Estudo da mec\u00e2nica de troca de mensagens atrav\u00e9s do ActiveMQ e Kafka. Cap\u00edtulo 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/39f41ebcb73ec247656c0dea438158a9.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figura 3-1. Parti\u00e7\u00f5es do Kafka<\/i><\/p>\n<p>Quando um produtor envia uma mensagem para um t\u00f3pico Kafka, ele decide em qual parti\u00e7\u00e3o enviar a mensagem. Vamos abordar isso com mais detalhes mais tarde.<\/p>\n<h2>Leitura de mensagens<\/h2>\n<p>\nO cliente que deseja ler mensagens gerencia um ponteiro nomeado chamado <i>grupo de consumidores (consumer group)<\/i>, que aponta para <i>o deslocamento (offset)<\/i> da mensagem na parti\u00e7\u00e3o. O deslocamento \u00e9 uma posi\u00e7\u00e3o com um n\u00famero crescente que come\u00e7a em 0 no in\u00edcio da parti\u00e7\u00e3o. Este grupo de consumidores, ao qual se refere na API atrav\u00e9s de um identificador definido pelo usu\u00e1rio group_id, corresponde <i>a um \u00fanico consumidor l\u00f3gico ou sistema<\/i>.<\/p>\n<p>A maioria dos sistemas que utilizam troca de mensagens l\u00ea os dados do destinat\u00e1rio atrav\u00e9s de v\u00e1rias inst\u00e2ncias e fluxos para o processamento paralelo das mensagens. Assim, geralmente haver\u00e1 muitas inst\u00e2ncias de consumidores compartilhando um mesmo grupo de consumidores.<\/p>\n<p>O problema da leitura pode ser apresentado da seguinte forma:<\/p>\n<ul>\n<li>O t\u00f3pico possui v\u00e1rias parti\u00e7\u00f5es<\/li>\n<li>M\u00faltiplos grupos de consumidores podem usar o t\u00f3pico simultaneamente<\/li>\n<li>Um grupo de consumidores pode ter v\u00e1rias inst\u00e2ncias separadas<\/li>\n<\/ul>\n<p>\nEste \u00e9 um problema n\u00e3o trivial de 'muitos para muitos'. Para entender como o Kafka lida com as rela\u00e7\u00f5es entre grupos de consumidores, inst\u00e2ncias de consumidores e parti\u00e7\u00f5es, vamos considerar uma s\u00e9rie de cen\u00e1rios de leitura que se tornam gradualmente mais complexos.<\/p>\n<h3>Consumidores e grupos de consumidores<\/h3>\n<p>\nVamos tomar como ponto de partida um t\u00f3pico com uma parti\u00e7\u00e3o (<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/6z\/tz\/dh\/6ztzdhqmjweck-z15htxb2xbe28.png\">Figura 3-2<\/a><\/noindex>).<\/p>\n<p><img decoding=\"async\" alt=\"Entendimento de corretores de mensagens. Estudo da mec\u00e2nica de troca de mensagens atrav\u00e9s do ActiveMQ e Kafka. Cap\u00edtulo 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/46c92e6bd38774dfef3be4bd198bf35d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figura 3-2. O consumidor l\u00ea a partir da parti\u00e7\u00e3o<\/i><\/p>\n<p>Quando uma inst\u00e2ncia de consumidor se conecta a este t\u00f3pico com seu pr\u00f3prio group_id, uma parti\u00e7\u00e3o \u00e9 designada para leitura e um deslocamento nesta parti\u00e7\u00e3o. A posi\u00e7\u00e3o desse deslocamento \u00e9 configurada no cliente, como um ponteiro para a posi\u00e7\u00e3o mais recente (a mensagem mais nova) ou a posi\u00e7\u00e3o mais antiga (a mensagem mais antiga). O consumidor solicita (polls) as mensagens do t\u00f3pico, resultando em sua leitura sequencial do registro.<br \/>\nA posi\u00e7\u00e3o do deslocamento \u00e9 regularmente confirmada de volta ao Kafka e armazenada como mensagens no t\u00f3pico interno <i>_consumer_offsets<\/i>. As mensagens lidas n\u00e3o s\u00e3o removidas, ao contr\u00e1rio de um broker comum, e o cliente pode retroceder (rewind) o deslocamento para reprocessar mensagens j\u00e1 visualizadas.<\/p>\n<p>Quando um segundo consumidor l\u00f3gico se conecta, usando um group_id diferente, ele gerencia um segundo ponteiro que n\u00e3o depende do primeiro (<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/qe\/v1\/yk\/qev1yktga3s-g1gqlynylbe3n9w.png\">Figura 3-3<\/a><\/noindex>). Dessa forma, o t\u00f3pico Kafka funciona como uma fila, onde existe um consumidor, e como um t\u00f3pico convencional de publica\u00e7\u00e3o-assinatura (pub-sub), no qual v\u00e1rios consumidores est\u00e3o inscritos, com a vantagem adicional de que todas as mensagens s\u00e3o armazenadas e podem ser processadas v\u00e1rias vezes.<\/p>\n<p><img decoding=\"async\" alt=\"Entendimento de corretores de mensagens. Estudo da mec\u00e2nica de troca de mensagens atrav\u00e9s do ActiveMQ e Kafka. Cap\u00edtulo 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/e9e8b9063ef7367005254d36abb47f4f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figura 3-3. Dois consumidores em diferentes grupos de consumidores leem de uma parti\u00e7\u00e3o<\/i><\/p>\n<h3>Consumidores em um grupo de consumidores<\/h3>\n<p>\nQuando uma inst\u00e2ncia do consumidor l\u00ea dados de uma parti\u00e7\u00e3o, ela controla completamente o apontador e processa as mensagens, como descrito na se\u00e7\u00e3o anterior.<br \/>\nSe v\u00e1rias inst\u00e2ncias de consumidores estiverem conectadas com o mesmo group_id a um t\u00f3pico com uma parti\u00e7\u00e3o, a inst\u00e2ncia que se conectar por \u00faltimo obter\u00e1 o controle sobre o apontador e, a partir desse momento, receber\u00e1 todas as mensagens (<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/0j\/ao\/f2\/0jaof2mdwg3cqvmwemhtxkrltuq.png\">Figura 3-4<\/a><\/noindex>).<\/p>\n<p><img decoding=\"async\" alt=\"Entendimento de corretores de mensagens. Estudo da mec\u00e2nica de troca de mensagens atrav\u00e9s do ActiveMQ e Kafka. Cap\u00edtulo 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/ec6af819445dad4028f65449a735ae22.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figura 3-4. Duas inst\u00e2ncias de consumidores no mesmo grupo de consumidores leem de uma parti\u00e7\u00e3o<\/i><\/p>\n<p>Esse modo de processamento, em que o n\u00famero de inst\u00e2ncias de consumidores supera o n\u00famero de parti\u00e7\u00f5es, pode ser considerado uma forma de consumidor monopolista. Isso pode ser \u00fatil se voc\u00ea precisar de uma clusteriza\u00e7\u00e3o \"ativa-passiva\" (ou \"quente-morna\") de suas inst\u00e2ncias de consumidores, embora a opera\u00e7\u00e3o paralela de v\u00e1rios consumidores (\"ativa-ativa\" ou \"quente-quente\") seja muito mais t\u00edpica do que consumidores em modo de espera.<\/p>\n<blockquote><p>Esse comportamento de distribui\u00e7\u00e3o de mensagens, descrito acima, pode surpreender em compara\u00e7\u00e3o com o que acontece em uma fila JMS comum. Nesse modelo, as mensagens enviadas para a fila s\u00e3o distribu\u00eddas uniformemente entre os dois consumidores.<\/p><\/blockquote>\n<p>\nNa maioria das vezes, ao criar v\u00e1rias inst\u00e2ncias de consumidores, fazemos isso para processamento paralelo de mensagens, para aumentar a velocidade de leitura ou para melhorar a resili\u00eancia do processo de leitura. Como uma inst\u00e2ncia de consumidor pode ler dados de uma parti\u00e7\u00e3o simultaneamente, como isso \u00e9 alcan\u00e7ado no Kafka?<\/p>\n<p>Uma das maneiras de fazer isso \u00e9 usar uma inst\u00e2ncia de consumidor para ler todas as mensagens e passar para um pool de threads. Embora essa abordagem aumente a taxa de processamento, aumenta a complexidade da l\u00f3gica dos consumidores e n\u00e3o faz nada para melhorar a resili\u00eancia do sistema de leitura. Se uma inst\u00e2ncia de consumidor falhar devido a uma perda de energia ou evento semelhante, a leitura \u00e9 interrompida.<\/p>\n<p>A maneira can\u00f4nica de resolver esse problema no Kafka \u00e9 usar um<i>A<\/i>maior n\u00famero de parti\u00e7\u00f5es.<\/p>\n<h3>Particionamento<\/h3>\n<p>\nAs parti\u00e7\u00f5es s\u00e3o o principal mecanismo para paralelizar a leitura e escalar o t\u00f3pico al\u00e9m da capacidade de um \u00fanico broker. Para entender melhor isso, vamos considerar uma situa\u00e7\u00e3o em que existe um t\u00f3pico com duas parti\u00e7\u00f5es e um consumidor se inscreve neste t\u00f3pico (<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/en\/9g\/ct\/en9gct0o017cqp8buawguwlscty.png\">Figura 3-5<\/a><\/noindex>).<\/p>\n<p><img decoding=\"async\" alt=\"Entendimento de corretores de mensagens. Estudo da mec\u00e2nica de troca de mensagens atrav\u00e9s do ActiveMQ e Kafka. Cap\u00edtulo 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/cc766bf69af22698aacc3f1ac70b067f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figura 3-5. Um consumidor l\u00ea de v\u00e1rias parti\u00e7\u00f5es<\/i><\/p>\n<p>Neste cen\u00e1rio, o consumidor tem controle sobre os ponteiros correspondentes ao seu group_id em ambas as parti\u00e7\u00f5es e come\u00e7a a ler mensagens de ambas as parti\u00e7\u00f5es.<br \/>\nQuando um consumidor adicional \u00e9 adicionado a este t\u00f3pico para o mesmo group_id, o Kafka realoca uma das parti\u00e7\u00f5es do primeiro para o segundo consumidor. A partir da\u00ed, cada inst\u00e2ncia do consumidor ler\u00e1 de uma parti\u00e7\u00e3o do t\u00f3pico (<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/8b\/a0\/um\/8ba0umn2yzr9yy3vztonhdfiub0.png\">Figura 3-6<\/a><\/noindex>).<\/p>\n<p>Para garantir o processamento de mensagens em paralelo em 20 threads, voc\u00ea precisar\u00e1 de pelo menos 20 parti\u00e7\u00f5es. Se houver menos parti\u00e7\u00f5es, voc\u00ea ter\u00e1 consumidores que n\u00e3o t\u00eam nada com o que trabalhar, como discutido anteriormente no t\u00f3pico dos consumidores monopolistas.<\/p>\n<p><img decoding=\"async\" alt=\"Entendimento de corretores de mensagens. Estudo da mec\u00e2nica de troca de mensagens atrav\u00e9s do ActiveMQ e Kafka. Cap\u00edtulo 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/a3c4001e4a5b92d53b6f529b2633254a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figura 3-6. Dois consumidores no mesmo grupo de consumidores leem de parti\u00e7\u00f5es diferentes<\/i><\/p>\n<p>Esse esquema reduz significativamente a complexidade do trabalho do broker Kafka em compara\u00e7\u00e3o com a distribui\u00e7\u00e3o de mensagens necess\u00e1ria para suportar uma fila JMS. Aqui, n\u00e3o \u00e9 necess\u00e1rio se preocupar com os seguintes aspectos:<\/p>\n<ul>\n<li>Qual consumidor deve receber a pr\u00f3xima mensagem, com base na distribui\u00e7\u00e3o em round-robin, na capacidade atual dos buffers de pr\u00e9-busca ou em mensagens anteriores (como para grupos de mensagens JMS).<\/li>\n<li>Quais mensagens foram enviadas para quais consumidores e se devem ser entregues novamente em caso de falha.<\/li>\n<\/ul>\n<p>\nTudo o que o broker Kafka precisa fazer \u00e9 encaminhar mensagens sequencialmente ao consumidor quando este as solicita.<\/p>\n<p>No entanto, as exig\u00eancias para a paraleliza\u00e7\u00e3o da leitura e reenvio de mensagens falhas n\u00e3o desaparecem - a responsabilidade por elas simplesmente passa do broker para o cliente. Isso significa que elas devem ser consideradas no seu c\u00f3digo.<\/p>\n<h2>Envio de Mensagens<\/h2>\n<p>\nA responsabilidade pela decis\u00e3o de em qual parti\u00e7\u00e3o enviar uma mensagem recai sobre o produtor dessa mensagem. Para entender o mecanismo pelo qual isso \u00e9 feito, primeiro precisamos considerar o que exatamente estamos enviando.<\/p>\n<p>Enquanto no JMS usamos uma estrutura de mensagem com metadados (cabe\u00e7alhos e propriedades) e um corpo contendo a carga \u00fatil (payload), no Kafka a mensagem \u00e9 <i>um par \"chave-valor\".<\/i>A carga \u00fatil da mensagem \u00e9 enviada como o valor (value). A chave, por outro lado, \u00e9 usada principalmente para particionamento e deve conter <i>uma chave espec\u00edfica para a l\u00f3gica de neg\u00f3cios<\/i>, para colocar mensagens relacionadas na mesma parti\u00e7\u00e3o.<\/p>\n<p>No Cap\u00edtulo 2, discutimos o cen\u00e1rio de apostas online, onde eventos relacionados devem ser processados em ordem por um \u00fanico consumidor:<\/p>\n<ol>\n<li>A conta do usu\u00e1rio est\u00e1 configurada.<\/li>\n<li>O dinheiro \u00e9 creditado na conta.<\/li>\n<li>Uma aposta \u00e9 feita, retirando dinheiro da conta.<\/li>\n<\/ol>\n<p>\nSe cada evento representa uma mensagem enviada para o t\u00f3pico, ent\u00e3o a chave natural seria o identificador da conta.<br \/>\nQuando uma mensagem \u00e9 enviada usando a API do Kafka Producer, ela \u00e9 passada para a fun\u00e7\u00e3o de particionamento, que, considerando a mensagem e o estado atual do cluster Kafka, retorna o identificador da parti\u00e7\u00e3o para a qual a mensagem deve ser enviada. Esta fun\u00e7\u00e3o \u00e9 implementada em Java atrav\u00e9s da interface Partitioner.<\/p>\n<p>Esta interface \u00e9 a seguinte:<\/p>\n<pre><code class=\"java\">interface Partitioner {\n    int partition(String topic,\n        Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster);\n}<\/code><\/pre>\n<p>\nA implementa\u00e7\u00e3o do Partitioner para determinar a parti\u00e7\u00e3o usa por padr\u00e3o um algoritmo de hash da chave (general-purpose hashing algorithm over the key) ou round-robin, se a chave n\u00e3o for especificada. Este valor padr\u00e3o funciona bem na maioria dos casos. No entanto, no futuro, voc\u00ea pode querer escrever o seu pr\u00f3prio.<\/p>\n<h3>Escrevendo sua pr\u00f3pria estrat\u00e9gia de particionamento<\/h3>\n<p>\nVamos considerar um exemplo em que voc\u00ea deseja enviar metadados junto com a carga \u00fatil da mensagem. A carga \u00fatil no nosso exemplo \u00e9 uma instru\u00e7\u00e3o para fazer um dep\u00f3sito na conta de jogo. A instru\u00e7\u00e3o \u00e9 algo que gostar\u00edamos de garantir que n\u00e3o ser\u00e1 modificado durante a transmiss\u00e3o e queremos ter certeza de que apenas um sistema confi\u00e1vel de n\u00edvel superior pode iniciar essa instru\u00e7\u00e3o. Nesse caso, os sistemas remetente e receptor concordam em usar uma assinatura para verificar a autenticidade da mensagem.<br \/>\nNo JMS padr\u00e3o, simplesmente definimos a propriedade \"assinatura da mensagem\" e a acrescentamos \u00e0 mensagem. No entanto, o Kafka n\u00e3o nos fornece um mecanismo para transmitir metadados \u2014 apenas chave e valor.<\/p>\n<p>Como o valor \u00e9 a carga \u00fatil de uma transfer\u00eancia banc\u00e1ria, cuja integridade queremos preservar, n\u00e3o temos escolha a n\u00e3o ser definir uma estrutura de dados para usar na chave. Assumindo que precisamos de um identificador de conta para particionar, j\u00e1 que todas as mensagens relacionadas \u00e0 conta devem ser processadas em ordem, iremos criar a seguinte estrutura JSON:<\/p>\n<pre><code class=\"json\">{\n  \"signature\": \"541661622185851c248b41bf0cea7ad0\",\n  \"accountId\": \"10007865234\"\n}<\/code><\/pre>\n<p>\nComo o valor da assinatura variar\u00e1 dependendo da carga \u00fatil, a estrat\u00e9gia padr\u00e3o de hash da interface Partitioner n\u00e3o ir\u00e1 agrupar mensagens relacionadas de forma confi\u00e1vel. Portanto, precisaremos escrever nossa pr\u00f3pria estrat\u00e9gia, que analisar\u00e1 essa chave e particionar\u00e1 o valor accountId.<\/p>\n<blockquote><p>O Kafka inclui somat\u00f3rios de verifica\u00e7\u00e3o para detectar corrup\u00e7\u00e3o de mensagens no armazenamento e possui um conjunto completo de funcionalidades de seguran\u00e7a. Mesmo assim, \u00e0s vezes surgem requisitos espec\u00edficos da ind\u00fastria, como o mencionado acima.<\/p><\/blockquote>\n<p>\nA estrat\u00e9gia de particionamento personalizada deve garantir que todas as mensagens relacionadas sejam colocadas na mesma parti\u00e7\u00e3o. Embora isso pare\u00e7a simples, a exig\u00eancia pode ser complicada devido \u00e0 import\u00e2ncia de ordenar mensagens relacionadas e a rigidez do n\u00famero de parti\u00e7\u00f5es no t\u00f3pico.<\/p>\n<p>O n\u00famero de parti\u00e7\u00f5es em um t\u00f3pico pode mudar ao longo do tempo, pois podem ser adicionadas se o tr\u00e1fego exceder as expectativas iniciais. Assim, as chaves de mensagem podem estar associadas \u00e0 parti\u00e7\u00e3o para a qual foram enviadas inicialmente, implicando uma parte do estado que deve ser distribu\u00eddo entre as inst\u00e2ncias do produtor.<\/p>\n<p>Outro fator a ser considerado \u00e9 a uniformidade da distribui\u00e7\u00e3o de mensagens entre parti\u00e7\u00f5es. De modo geral, as chaves n\u00e3o s\u00e3o distribu\u00eddas uniformemente entre as mensagens, e fun\u00e7\u00f5es de hash n\u00e3o garantem uma distribui\u00e7\u00e3o justa de mensagens para um pequeno conjunto de chaves.<br \/>\n\u00c9 importante notar que, independentemente de como voc\u00ea decide dividir as mensagens, o pr\u00f3prio delimitador pode precisar ser reutilizado.<\/p>\n<p>Consideremos o requisito de replica\u00e7\u00e3o de dados entre clusters Kafka em diferentes locais geogr\u00e1ficos. Para isso, o Kafka vem com uma ferramenta de linha de comando chamada MirrorMaker, que \u00e9 usada para ler mensagens de um cluster e transmiti-las para outro.<\/p>\n<p>O MirrorMaker deve entender as chaves do t\u00f3pico replicado para manter a ordem relativa entre as mensagens durante a replica\u00e7\u00e3o entre clusters, uma vez que o n\u00famero de parti\u00e7\u00f5es desse t\u00f3pico pode n\u00e3o coincidir em ambos os clusters.<\/p>\n<p>Estrat\u00e9gias de particionamento personalizadas s\u00e3o relativamente raras, pois a parti\u00e7\u00e3o padr\u00e3o por hashing ou round-robin funciona com sucesso na maioria dos cen\u00e1rios. No entanto, se voc\u00ea precisa de garantias rigorosas de ordena\u00e7\u00e3o ou precisa extrair metadados das cargas \u00fateis, o particionamento \u00e9 algo que voc\u00ea deve examinar com mais detalhes.<\/p>\n<p>Os benef\u00edcios de escalabilidade e desempenho do Kafka s\u00e3o devido \u00e0 transfer\u00eancia de algumas responsabilidades de um corretor tradicional para o cliente. Neste caso, uma decis\u00e3o \u00e9 tomada para distribuir mensagens potencialmente relacionadas entre v\u00e1rios consumidores que trabalham em paralelo.<\/p>\n<blockquote><p>Os corretores JMS tamb\u00e9m precisam lidar com esses requisitos. Curiosamente, o mecanismo de envio de mensagens relacionadas ao mesmo consumidor, implementado por meio de JMS Message Groups (uma variante da estrat\u00e9gia de balanceamento de carga sticky load balancing (SLB)), tamb\u00e9m requer que o remetente marque as mensagens como relacionadas. No caso do JMS, o corretor \u00e9 respons\u00e1vel por enviar este grupo de mensagens relacionadas a um consumidor entre muitos e transferir a propriedade do grupo se o consumidor falhar.<\/p><\/blockquote>\n<p><\/p>\n<h2>Acordos sobre o produtor<\/h2>\n<p>\nO particionamento n\u00e3o \u00e9 a \u00fanica coisa a considerar ao enviar mensagens. Vamos considerar os m\u00e9todos send() da classe Producer na API Java:<\/p>\n<pre><code class=\"java\">Future  send(ProducerRecord  record);\nFuture  send(ProducerRecord  record, Callback callback);<\/code><\/pre>\n<p>\n\u00c9 importante notar que ambos os m\u00e9todos retornam um Future, indicando que a opera\u00e7\u00e3o de envio n\u00e3o \u00e9 realizada imediatamente. Como resultado, a mensagem (ProducerRecord) \u00e9 gravada no buffer de envio para cada parti\u00e7\u00e3o ativa e enviada ao corretor em uma thread de fundo na biblioteca cliente do Kafka. Embora isso torne a opera\u00e7\u00e3o incrivelmente r\u00e1pida, significa que um aplicativo mal escrito pode perder mensagens se seu processo for interrompido.<\/p>\n<p>Como sempre, h\u00e1 uma maneira de tornar a opera\u00e7\u00e3o de envio mais confi\u00e1vel em termos de desempenho. O tamanho desse buffer pode ser definido como 0, for\u00e7ando a thread do aplicativo enviador a aguardar at\u00e9 que a transmiss\u00e3o da mensagem ao corretor seja conclu\u00edda, da seguinte forma:<\/p>\n<pre><code class=\"java\">RecordMetadata metadata = producer.send(record).get();<\/code><\/pre>\n<p><\/p>\n<h2>Novamente sobre a leitura de mensagens<\/h2>\n<p>\nA leitura de mensagens apresenta complexidades adicionais que precisam ser discutidas. Ao contr\u00e1rio da API JMS, que pode iniciar um listener de mensagens em resposta \u00e0 chegada de uma mensagem, a interface <i>Consumer <\/i>Kafka apenas faz polling. Vamos examinar mais de perto o m\u00e9todo <i>poll ()<\/i>, utilizado para esse prop\u00f3sito:<\/p>\n<pre><code class=\"java\">ConsumerRecords &lt; K, V &gt; poll(long timeout);<\/code><\/pre>\n<p>\nO valor retornado pelo m\u00e9todo \u00e9 uma estrutura contendo v\u00e1rios objetos <i>ConsumerRecord <\/i>de potencialmente v\u00e1rias parti\u00e7\u00f5es. <i>ConsumerRecord <\/i>Esse \u00e9 um objeto que cont\u00e9m um par chave-valor com metadados correspondentes, como a parti\u00e7\u00e3o de onde foi obtido.<\/p>\n<p>Como discutido no Cap\u00edtulo 2, devemos sempre ter em mente o que acontece com as mensagens ap\u00f3s seu processamento bem-sucedido ou n\u00e3o, por exemplo, se o cliente n\u00e3o consegue processar a mensagem ou se ele falha. Na JMS, isso era tratado por meio do modo de reconhecimento (acknowledgement mode). O corretor pode remover a mensagem processada com sucesso ou reentregar a mensagem n\u00e3o processada ou falhada (desde que transa\u00e7\u00f5es tenham sido utilizadas). <br \/>\nO Kafka funciona de maneira completamente diferente. As mensagens n\u00e3o s\u00e3o removidas no corretor ap\u00f3s a leitura, e a responsabilidade pelo que acontece em caso de falha recai sobre o pr\u00f3prio c\u00f3digo de leitura.<\/p>\n<p>Como j\u00e1 mencionamos, um grupo de consumidores est\u00e1 associado a um deslocamento no log. A posi\u00e7\u00e3o no log associada a esse deslocamento corresponde \u00e0 pr\u00f3xima mensagem que ser\u00e1 emitida em resposta a <i>poll ()<\/i>O momento em que esse deslocamento aumenta tem um significado crucial na leitura.<\/p>\n<p>Voltando ao modelo de leitura discutido anteriormente, o processamento da mensagem consiste em tr\u00eas etapas:<\/p>\n<ol>\n<li>Extrair a mensagem para leitura.<\/li>\n<li>Processar a mensagem.<\/li>\n<li>Confirmar a mensagem.<\/li>\n<\/ol>\n<p>\nO consumidor Kafka vem com a op\u00e7\u00e3o de configura\u00e7\u00e3o <i>enable.auto.commit<\/i>. Esta \u00e9 uma configura\u00e7\u00e3o frequentemente utilizada como padr\u00e3o, como \u00e9 comum com configura\u00e7\u00f5es que cont\u00eam a palavra \"auto\".<\/p>\n<p>At\u00e9 o Kafka 0.10, o cliente que usava esse par\u00e2metro enviava o deslocamento da \u00faltima mensagem lida na pr\u00f3xima chamada <i>poll ()<\/i> ap\u00f3s o processamento. Isso significava que quaisquer mensagens que j\u00e1 tinham sido extra\u00eddas (fetched) poderiam ser processadas novamente, se o cliente j\u00e1 as tivesse processado, mas fosse inesperadamente encerrado antes da chamada <i>poll ()<\/i>. Como o corretor n\u00e3o mant\u00e9m nenhum estado sobre quantas vezes a mensagem foi lida, o pr\u00f3ximo consumidor que extrai essa mensagem n\u00e3o saber\u00e1 que algo deu errado. Esse comportamento era pseudo-transacional. O deslocamento era confirmado apenas em caso de processamento bem-sucedido da mensagem, mas se o cliente interrompesse o trabalho, o corretor enviava a mesma mensagem para outro cliente. Esse comportamento estava de acordo com a garantia de entrega de mensagens \u00ab<i>pelo menos uma vez<\/i>&#171;.<\/p>\n<p>No Kafka 0.10, o c\u00f3digo do cliente foi alterado de modo que o commit come\u00e7asse a ser executado periodicamente pela biblioteca do cliente, de acordo com a configura\u00e7\u00e3o <i>auto.commit.interval.ms<\/i>. Esse comportamento est\u00e1 em algum lugar entre os modos JMS AUTO_ACKNOWLEDGE e DUPS_OK_ACKNOWLEDGE. Ao usar o auto commit, as mensagens podiam ser confirmadas independentemente de terem sido realmente processadas \u2014 isso poderia ocorrer no caso de um consumidor lento. Se o consumidor parasse de funcionar, as mensagens eram extra\u00eddas pelo pr\u00f3ximo consumidor, come\u00e7ando pela posi\u00e7\u00e3o confirmada, o que poderia levar \u00e0 perda de mensagens. Nesse caso, o Kafka n\u00e3o perdia mensagens, o c\u00f3digo de leitura simplesmente n\u00e3o as processava.<\/p>\n<p>Este modo tem as mesmas perspectivas que na vers\u00e3o 0.9: as mensagens podem ser processadas, mas em caso de falha, o deslocamento pode n\u00e3o ser confirmado, o que pode potencialmente levar \u00e0 duplica\u00e7\u00e3o da entrega. Quanto mais mensagens voc\u00ea extrai ao realizar <i>poll ()<\/i>, maior \u00e9 esse problema.<\/p>\n<p>Como discutido na se\u00e7\u00e3o \"Leitura de mensagens da fila\" na p\u00e1gina 21, n\u00e3o existe o conceito de entrega \u00fanica de mensagens no sistema de troca de mensagens, considerando os modos de falha.<\/p>\n<p>No Kafka, existem duas maneiras de confirmar (commitar) o offset: automaticamente e manualmente. Em ambos os casos, as mensagens podem ser processadas v\u00e1rias vezes, caso a mensagem tenha sido processada, mas uma falha ocorra antes do commit. Voc\u00ea tamb\u00e9m pode n\u00e3o processar a mensagem de forma alguma, se o commit ocorreu em segundo plano e seu c\u00f3digo foi finalizado antes de come\u00e7ar a process\u00e1-la (possivelmente nas vers\u00f5es do Kafka 0.9 e anteriores).<\/p>\n<p>Gerenciar o processo de commit de offset manualmente pode ser feito na API do consumidor Kafka, definindo o par\u00e2metro <i>enable.auto.commit<\/i> como false e chamando explicitamente um dos seguintes m\u00e9todos:<\/p>\n<pre><code class=\"java\">void commitSync();\nvoid commitAsync();<\/code><\/pre>\n<p>\nSe voc\u00ea deseja processar uma mensagem \"pelo menos uma vez\", deve comitar o offset manualmente usando <i>commitSync ()<\/i>, executando este comando imediatamente ap\u00f3s o processamento das mensagens.<\/p>\n<p>Esses m\u00e9todos n\u00e3o permitem confirmar (acknowledge) mensagens at\u00e9 que elas sejam processadas, mas n\u00e3o fazem nada para eliminar a potencial duplica\u00e7\u00e3o de processamento, ao mesmo tempo que criam a apar\u00eancia de transacionalidade. O Kafka n\u00e3o possui transa\u00e7\u00f5es. O cliente n\u00e3o pode fazer o seguinte:<\/p>\n<ul>\n<li>Reverter automaticamente (roll back) uma mensagem com falha. Os consumidores devem tratar as exce\u00e7\u00f5es decorrentes de payloads problem\u00e1ticos e falhas no backend, uma vez que n\u00e3o podem contar com a reentrega de mensagens pelo broker.<\/li>\n<li>Enviar mensagens para m\u00faltiplos t\u00f3picos como uma \u00fanica opera\u00e7\u00e3o at\u00f4mica. Como veremos em breve, o controle sobre diversos t\u00f3picos e parti\u00e7\u00f5es pode estar em diferentes m\u00e1quinas no cluster Kafka, que n\u00e3o coordenam transa\u00e7\u00f5es ao enviar. No momento da reda\u00e7\u00e3o deste artigo, um trabalho consider\u00e1vel havia sido feito para tornar isso poss\u00edvel atrav\u00e9s do KIP-98.<\/li>\n<li>Vincular a leitura de uma mensagem de um t\u00f3pico ao envio de outra mensagem para outro t\u00f3pico. Novamente, a arquitetura do Kafka depende de v\u00e1rias m\u00e1quinas independentes operando como um \u00fanico barramento e n\u00e3o h\u00e1 tentativas de ocultar isso. Por exemplo, n\u00e3o existem componentes na API que permitam vincular <i>Consumidor <\/i>e <i>Produtor <\/i>na transa\u00e7\u00e3o. No JMS isso \u00e9 garantido pelo objeto <i>Sess\u00e3o<\/i>, do qual s\u00e3o criados <i>MessageProducers <\/i>e <i>MessageConsumers<\/i>.<\/li>\n<\/ul>\n<p>\nSe n\u00e3o podemos confiar em transa\u00e7\u00f5es, como podemos garantir uma sem\u00e2ntica mais pr\u00f3xima daquela fornecida por sistemas tradicionais de troca de mensagens?<\/p>\n<p>Se houver a possibilidade de que o deslocamento do consumidor possa aumentar antes que a mensagem tenha sido processada, por exemplo, durante uma falha do consumidor, ent\u00e3o o consumidor n\u00e3o tem como saber se seu grupo de consumidores perdeu mensagens quando recebeu a parti\u00e7\u00e3o. Assim, uma das estrat\u00e9gias envolve retroceder (rewind) o deslocamento para a posi\u00e7\u00e3o anterior. A API do consumidor Kafka fornece os seguintes m\u00e9todos para isso:<\/p>\n<pre><code class=\"java\">void seek(TopicPartition partition, long offset);\nvoid seekToBeginning(Collection  partitions);<\/code><\/pre>\n<p>\nM\u00e9todo <i>seek ()<\/i> pode ser usado com o m\u00e9todo <br \/>\n<i>offsetsForTimes (Map timestampsToSearch)<\/i> para retroceder a um estado em um momento espec\u00edfico no passado.<\/p>\n<p>Implicitamente, usar essa abordagem significa que, provavelmente, algumas mensagens que foram processadas anteriormente ser\u00e3o lidas e processadas novamente. Para evitar isso, podemos usar leitura idempotente, conforme descrito no Cap\u00edtulo 4, para acompanhar mensagens visualizadas anteriormente e excluir duplicatas.<\/p>\n<p>Como alternativa, o c\u00f3digo do seu consumidor pode ser simples, se a perda ou duplica\u00e7\u00e3o de mensagens for aceit\u00e1vel. Quando consideramos cen\u00e1rios de uso para os quais o Kafka \u00e9 geralmente usado, como processamento de eventos de logs, m\u00e9tricas, rastreamento de cliques, etc., entendemos que a perda de mensagens individuais dificilmente ter\u00e1 um impacto significativo nas aplica\u00e7\u00f5es circundantes. Nesses casos, os valores padr\u00e3o s\u00e3o bastante aceit\u00e1veis. Por outro lado, se seu aplicativo precisar transmitir pagamentos, voc\u00ea deve cuidar de cada mensagem individualmente. Tudo se resume ao contexto.<\/p>\n<p>Observa\u00e7\u00f5es pessoais mostram que, \u00e0 medida que a intensidade das mensagens aumenta, o valor de cada mensagem individual diminui. Mensagens de alto volume se tornam, geralmente, valiosas se consideradas em uma forma agregada.<\/p>\n<h2>Alta Disponibilidade (High Availability)<\/h2>\n<p>\nA abordagem do Kafka em rela\u00e7\u00e3o \u00e0 alta disponibilidade difere substancialmente da abordagem do ActiveMQ. O Kafka foi projetado com base em clusters horizontalmente escal\u00e1veis, onde todas as inst\u00e2ncias do broker aceitam e distribuem mensagens simultaneamente.<\/p>\n<p>Um cluster Kafka \u00e9 composto por v\u00e1rias inst\u00e2ncias de brokers que operam em servidores diferentes. O Kafka foi desenvolvido para funcionar em hardware aut\u00f4nomo comum, onde cada n\u00f3 tem seu pr\u00f3prio armazenamento dedicado. O uso de armazenamento em rede (SAN) n\u00e3o \u00e9 recomendado, uma vez que m\u00faltiplos n\u00f3s de computa\u00e7\u00e3o podem competir por janelas de tempo<i>de<\/i>armazenamento e criar conflitos.<\/p>\n<p>Kafka \u00e9 uma <i>sistema sempre ativo.<\/i> Muitos grandes usu\u00e1rios do Kafka nunca desativam seus clusters, e o software sempre realiza atualiza\u00e7\u00f5es atrav\u00e9s de reinicializa\u00e7\u00f5es sequenciais. Isso \u00e9 alcan\u00e7ado garantindo a compatibilidade com vers\u00f5es anteriores para mensagens e intera\u00e7\u00f5es entre brokers.<\/p>\n<p>Os brokers est\u00e3o conectados ao cluster de servidores <noindex><a rel=\"nofollow\" href=\"http:\/\/zookeeper.apache.org\">ZooKeeper<\/a><\/noindex>, que atua como um registro de dados de configura\u00e7\u00e3o e \u00e9 usado para coordenar os pap\u00e9is de cada broker. O ZooKeeper \u00e9, por si s\u00f3, um sistema distribu\u00eddo que fornece alta disponibilidade atrav\u00e9s da replica\u00e7\u00e3o de informa\u00e7\u00f5es estabelecendo um <i>qu\u00f3rum.<\/i>.<\/p>\n<p>No caso b\u00e1sico, um t\u00f3pico \u00e9 criado no cluster Kafka com as seguintes propriedades:<\/p>\n<ul>\n<li>N\u00famero de parti\u00e7\u00f5es. Como discutido anteriormente, o valor exato utilizado aqui depende do n\u00edvel desejado de leitura paralela.<\/li>\n<li>O fator de replica\u00e7\u00e3o determina quantas inst\u00e2ncias de brokers no cluster devem conter logs para essa parti\u00e7\u00e3o.<\/li>\n<\/ul>\n<p>\nUsando o ZooKeeper para coordena\u00e7\u00e3o, o Kafka tenta distribuir novas parti\u00e7\u00f5es de forma justa entre os brokers no cluster. Isso \u00e9 feito por uma inst\u00e2ncia que atua como Controlador.<\/p>\n<p>Em tempo de execu\u00e7\u00e3o, <i>para cada parti\u00e7\u00e3o do t\u00f3pico,<\/i> <i>Controlador <\/i>atribui ao broker pap\u00e9is de <i>l\u00edder <\/i>(l\u00edder, master) e <i>seguidores. <\/i>(seguidores, escravos, subordinados). O broker que atua como l\u00edder para essa parti\u00e7\u00e3o \u00e9 respons\u00e1vel por receber todas as mensagens enviadas a ele pelos produtores e espalhar as mensagens para os consumidores. Ao enviar mensagens para a parti\u00e7\u00e3o do t\u00f3pico, elas s\u00e3o replicadas em todos os n\u00f3s do broker que atuam como seguidores dessa parti\u00e7\u00e3o. Cada n\u00f3 que cont\u00e9m logs para a parti\u00e7\u00e3o \u00e9 chamado de <i>r\u00e9plica<\/i>. O broker pode atuar como l\u00edder para algumas parti\u00e7\u00f5es e como seguidor para outras.<\/p>\n<p>O seguidor que cont\u00e9m todas as mensagens armazenadas no l\u00edder \u00e9 chamado de <i>r\u00e9plica sincronizada<\/i> (r\u00e9plica que est\u00e1 em estado sincronizado, in-sync replica). Se o broker que atua como l\u00edder para a parti\u00e7\u00e3o falha, qualquer broker que esteja em um estado atualizado ou sincronizado para essa parti\u00e7\u00e3o pode assumir o papel de l\u00edder. Este \u00e9 um design incrivelmente resiliente.<\/p>\n<p>Parte da configura\u00e7\u00e3o do produtor \u00e9 o par\u00e2metro <i>acks<\/i>, que determina quantas r\u00e9plicas devem confirmar (acknowledge) o recebimento da mensagem antes que o fluxo do aplicativo continue o envio: 0, 1 ou todos. Se o valor <i>all<\/i>for especificado, ao receber a mensagem, o l\u00edder enviar\u00e1 uma confirma\u00e7\u00e3o (confirmation) de volta ao produtor assim que receber confirma\u00e7\u00f5es (acknowledgements) da grava\u00e7\u00e3o de v\u00e1rias r\u00e9plicas (incluindo a si mesmo), conforme definido pela configura\u00e7\u00e3o do t\u00f3pico <i>min.insync.replicas<\/i> (padr\u00e3o 1). Se a mensagem n\u00e3o puder ser replicada com sucesso, o produtor lan\u00e7ar\u00e1 uma exce\u00e7\u00e3o para o aplicativo (<i>NotEnoughReplicas<\/i> ou <i>NotEnoughReplicasAfterAppend<\/i>).<\/p>\n<p>Em uma configura\u00e7\u00e3o t\u00edpica, um t\u00f3pico \u00e9 criado com um fator de replica\u00e7\u00e3o de 3 (1 l\u00edder, 2 seguidores para cada parti\u00e7\u00e3o) e o par\u00e2metro <i>min.insync.replicas<\/i> \u00e9 definido como 2. Nesse caso, o cluster permitir\u00e1 que um dos brokers que gerenciam a parti\u00e7\u00e3o do t\u00f3pico possa falhar sem afetar os aplicativos clientes.<\/p>\n<p>Isso nos traz de volta ao compromisso familiar entre desempenho e confiabilidade. A replica\u00e7\u00e3o ocorre devido ao tempo adicional necess\u00e1rio para receber confirma\u00e7\u00f5es (acknowledgments) dos seguidores. No entanto, como acontece em paralelo, a replica\u00e7\u00e3o, pelo menos em tr\u00eas n\u00f3s, tem o mesmo desempenho que em dois (ignorando o aumento do uso da largura de banda da rede).<\/p>\n<p>Usando este esquema de replica\u00e7\u00e3o, o Kafka habilmente evita a necessidade de garantir a grava\u00e7\u00e3o f\u00edsica de cada mensagem no disco atrav\u00e9s da opera\u00e7\u00e3o <i>sync ()<\/i>. Cada mensagem enviada pelo produtor ser\u00e1 gravada no log da parti\u00e7\u00e3o, mas, como discutido no Cap\u00edtulo 2, a grava\u00e7\u00e3o no arquivo \u00e9 inicialmente feita no buffer do sistema operacional. Se essa mensagem for replicada em outra inst\u00e2ncia do Kafka e estiver em sua mem\u00f3ria, a perda do l\u00edder n\u00e3o significa que a pr\u00f3pria mensagem foi perdida \u2014 ela pode ser assumida por uma r\u00e9plica sincronizada.<br \/>\nAbandonar a necessidade de realizar a opera\u00e7\u00e3o <i>sync ()<\/i> significa que o Kafka pode aceitar mensagens na velocidade com que pode grav\u00e1-las na mem\u00f3ria. E, inversamente, quanto mais tempo puder evitar o descarregamento (flushing) da mem\u00f3ria no disco, melhor. Por esse motivo, n\u00e3o \u00e9 incomum que os corretores Kafka sejam alocados com 64 GB de mem\u00f3ria ou mais. Esse uso de mem\u00f3ria significa que uma inst\u00e2ncia do Kafka pode operar facilmente em velocidades milhares de vezes mais r\u00e1pidas do que um corretor de mensagens tradicional.<\/p>\n<p>O Kafka tamb\u00e9m pode ser configurado para aplicar a opera\u00e7\u00e3o <i>sync ()<\/i> em pacotes de mensagens. Como tudo no Kafka \u00e9 orientado a trabalhar com pacotes, isso realmente funciona bastante bem para muitos cen\u00e1rios de uso e \u00e9 uma ferramenta \u00fatil para os usu\u00e1rios que requerem garantias muito fortes. Grande parte do desempenho puro do Kafka est\u00e1 relacionada \u00e0s mensagens que s\u00e3o enviadas ao corretor em forma de pacotes e ao fato de que essas mensagens s\u00e3o lidas do corretor em blocos consecutivos usando <noindex><a rel=\"nofollow\" href=\"http:\/\/www.linuxjournal.com\/article\/6345\">zero-copy<\/a><\/noindex> opera\u00e7\u00f5es (com opera\u00e7\u00f5es nas quais n\u00e3o h\u00e1 execu\u00e7\u00e3o da tarefa de copiar dados de uma \u00e1rea de mem\u00f3ria para outra). O \u00faltimo \u00e9 um grande ganho em termos de desempenho e recursos e \u00e9 poss\u00edvel apenas gra\u00e7as ao uso da estrutura de dados subjacente do log, que define o esquema de parti\u00e7\u00e3o.<\/p>\n<p>Em um cluster Kafka, \u00e9 poss\u00edvel obter uma performance muito maior do que ao usar um \u00fanico broker Kafka, pois as parti\u00e7\u00f5es do t\u00f3pico podem ser escaladas horizontalmente em v\u00e1rias m\u00e1quinas distintas.<\/p>\n<h2>Resultados<\/h2>\n<p>\nNeste cap\u00edtulo, examinamos como a arquitetura do Kafka recontextualiza as rela\u00e7\u00f5es entre clientes e brokers para proporcionar um pipeline de troca de mensagens incrivelmente robusto, com uma capacidade muito maior do que a de um broker de mensagens comum. Discutimos a funcionalidade que ela utiliza para alcan\u00e7ar esse objetivo e revisamos brevemente a arquitetura das aplica\u00e7\u00f5es que fornecem essa funcionalidade. No pr\u00f3ximo cap\u00edtulo, abordaremos os problemas comuns que precisam ser resolvidos pelas aplica\u00e7\u00f5es baseadas em troca de mensagens e discutiremos estrat\u00e9gias para sua resolu\u00e7\u00e3o. Encerramos o cap\u00edtulo delineando como pensar sobre tecnologias de troca de mensagens em geral, para que voc\u00ea possa avaliar sua adequa\u00e7\u00e3o para seus cen\u00e1rios de uso.<\/p>\n<p>Parte anterior traduzida: <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/466385\/\">Compreendendo Brokers de Mensagens. Estudando a mec\u00e2nica do interc\u00e2mbio de mensagens com ActiveMQ e Kafka. Cap\u00edtulo 1<\/a><\/noindex><\/p>\n<p><b> Tradu\u00e7\u00e3o realizada: <noindex><a rel=\"nofollow\" href=\"http:\/\/tele.gg\/middle_java\">tele.gg\/middle_java<\/a><\/noindex><\/b><\/p>\n<p><i>Continua\u2026<\/i><\/p>\n<p class=\"for_users_only_msg\">Apenas usu\u00e1rios registrados podem participar da pesquisa. <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/auth\/login\/\">Entre<\/a><\/noindex>, por favor.<\/p>\n<h2 class=\"default-block__polling-title\">O Kafka \u00e9 usado em sua organiza\u00e7\u00e3o?<\/h2>\n<ul class=\"content-list content-list_polling\">\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Sim<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    N\u00e3o<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Era usado, mas n\u00e3o \u00e9 mais<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Planejamos usar<\/p>\n<\/li>\n<\/ul>\n<p>    38 usu\u00e1rios votaram. 8 usu\u00e1rios se abstiveram.<br \/>\n<br \/>Fonte: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/466585\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043a\u043d\u0438\u0433\u0438: \u00abUnderstanding Message Brokers\u00bb, \u0430\u0432\u0442\u043e\u0440: Jakub Korab, \u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e: O&#8217;Reilly Media, Inc., \u0434\u0430\u0442\u0430 \u0438\u0437\u0434\u0430\u043d\u0438\u044f: June 2017, ISBN: 9781492049296. \u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043d\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c: \u041f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0431\u0440\u043e\u043a\u0435\u0440\u043e\u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u0418\u0437\u0443\u0447\u0435\u043d\u0438\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0438 \u043e\u0431\u043c\u0435\u043d\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c ActiveMQ \u0438 Kafka. \u0413\u043b\u0430\u0432\u0430 1. \u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0413\u041b\u0410\u0412\u0410 3 Kafka Kafka \u0431\u044b\u043b\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u0430 \u0432 LinkedIn \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u043e\u0439\u0442\u0438 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0431\u0440\u043e\u043a\u0435\u0440\u043e\u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-38172","post","type-post","status-publish","format-standard","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.3 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043a\u043d\u0438\u0433\u0438: \u00abUnderstanding Message Brokers\u00bb, \u0430\u0432\u0442\u043e\u0440: Jakub Korab, \u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e: O&#039;Reilly Media, Inc., \u0434\u0430\u0442\u0430 \u0438\u0437\u0434\u0430\u043d\u0438\u044f: June 2017, ISBN: 9781492049296. \u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043d\u043d\u0430\u044f.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/ponimanie-brokerov-soobshhenij-izuchenie-mehaniki-obmena-soobshheniyami-posredstvom-activemq-i-kafka-glava-3-kafka\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"pt_PT\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0431\u0440\u043e\u043a\u0435\u0440\u043e\u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u0418\u0437\u0443\u0447\u0435\u043d\u0438\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0438 \u043e\u0431\u043c\u0435\u043d\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c ActiveMQ \u0438 Kafka. \u0413\u043b\u0430\u0432\u0430 3. Kafka | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043a\u043d\u0438\u0433\u0438: \u00abUnderstanding Message Brokers\u00bb, \u0430\u0432\u0442\u043e\u0440: Jakub Korab, \u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e: O&#039;Reilly Media, Inc., \u0434\u0430\u0442\u0430 \u0438\u0437\u0434\u0430\u043d\u0438\u044f: June 2017, ISBN: 9781492049296. \u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043d\u043d\u0430\u044f.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/ponimanie-brokerov-soobshhenij-izuchenie-mehaniki-obmena-soobshheniyami-posredstvom-activemq-i-kafka-glava-3-kafka\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:22:05+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:22:05+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Compreendendo brokers de mensagens. Estudando a mec\u00e2nica da troca de mensagens atrav\u00e9s do ActiveMQ e Kafka. Cap\u00edtulo 3. Kafka | ProHoster","description":"Continua\u00e7\u00e3o da tradu\u00e7\u00e3o de um pequeno livro: 'Understanding Message Brokers', autor: Jakub Korab, editora: O'Reilly Media, Inc., data de publica\u00e7\u00e3o: Junho de 2017, ISBN: 9781492049296. Anteriormente traduzido.","canonical_url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/ponimanie-brokerov-soobshhenij-izuchenie-mehaniki-obmena-soobshheniyami-posredstvom-activemq-i-kafka-glava-3-kafka","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pt_PT","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0431\u0440\u043e\u043a\u0435\u0440\u043e\u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u0418\u0437\u0443\u0447\u0435\u043d\u0438\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0438 \u043e\u0431\u043c\u0435\u043d\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c ActiveMQ \u0438 Kafka. \u0413\u043b\u0430\u0432\u0430 3. Kafka | ProHoster","og:description":"\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043a\u043d\u0438\u0433\u0438: \u00abUnderstanding Message Brokers\u00bb, \u0430\u0432\u0442\u043e\u0440: Jakub Korab, \u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e: O'Reilly Media, Inc., \u0434\u0430\u0442\u0430 \u0438\u0437\u0434\u0430\u043d\u0438\u044f: June 2017, ISBN: 9781492049296. \u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043d\u043d\u0430\u044f.","og:url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/ponimanie-brokerov-soobshhenij-izuchenie-mehaniki-obmena-soobshheniyami-posredstvom-activemq-i-kafka-glava-3-kafka","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:22:05+00:00","article:modified_time":"2019-10-31T19:22:05+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"38172","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-23 20:46:00","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 15:34:26","updated":"2026-01-23 20:46:00","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/38172","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/comments?post=38172"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/38172\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media?parent=38172"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/categories?post=38172"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/tags?post=38172"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}