<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4552765333886608132</id><updated>2025-08-24T17:23:30.314-07:00</updated><category term="Java"/><category term="Android"/><category term="Linux"/><category term="Messaging"/><category term="Kafka"/><category term="Desempenho"/><category term="APIs"/><category term="MariaDB"/><category term="Maven"/><category term="MySQL"/><category term="SQL Server"/><category term="JSON"/><category term="SVN"/><category term="Spring"/><category term="STOMP"/><category term="Tomcat"/><category term="Windows"/><category term="JBoss"/><category term="Kobo"/><category term="Memória"/><category term="Oracle"/><category term="Servidores"/><category term="Web services"/><category term="grep"/><category term="jQuery"/><category term="ActiveMQ"/><category term="Ajax"/><category term="Cache"/><category term="Continuous Integration"/><category term="Eclipse"/><category term="Gson"/><category term="HTTPS"/><category term="Jenkins"/><category term="Kotlin"/><category term="Nexus"/><category term="Rede"/><category term="Sonar"/><category term="Testes"/><category term="XSD"/><category term="iptables"/><category term="netcat"/><category term="Backup"/><category term="Cobertura"/><category term="Continuous Inspection"/><category term="Firebase"/><category term="IDE"/><category term="IntelliJ IDEA"/><category term="JMS"/><category term="JPA"/><category term="JUnit"/><category term="JavaScript"/><category term="Monitoramento"/><category term="Perl"/><category term="Schedule"/><category term="Spring Boot"/><category term="Stream"/><category term="Teste unitário"/><category term="Web"/><category term="WebSphere"/><category term="Wildfly"/><category term="curl"/><category term="AOP"/><category term="Admob"/><category term="Apache POI"/><category term="AspectJ"/><category term="Boas práticas"/><category term="CXF"/><category term="Checkstyle"/><category term="Cloud"/><category term="Criptomoeda"/><category term="Datasource"/><category term="Erlang"/><category term="Event-driven"/><category term="Excel"/><category term="Findbugs"/><category term="Firestore"/><category term="Google Cloud"/><category term="HP"/><category term="Hibernate"/><category term="IP"/><category term="JAX-RS"/><category term="JAX-WS"/><category term="JMX"/><category term="JSF"/><category term="Jackson"/><category term="Jetty"/><category term="Kindle"/><category term="Liferay"/><category term="PMD"/><category term="Patterns"/><category term="Postman"/><category term="Projeto"/><category term="Protótipos"/><category term="Qualidade"/><category term="REST"/><category term="RabbitMQ"/><category term="Reflection"/><category term="Requisito"/><category term="Ruby"/><category term="SOAP"/><category term="SSL"/><category term="Segurança"/><category term="Shell"/><category term="Spring Data JPA"/><category term="Spring MVC"/><category term="Vert.x"/><category term="View"/><category term="WSDL"/><category term="ZooKeeper"/><category term="bash"/><category term="epub"/><title type='text'>Thiago Colen |</title><subtitle type='html'>Posts para facilitar as jornadas repetidas.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>213</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-5158140743905324400</id><published>2024-12-27T16:11:00.000-08:00</published><updated>2024-12-27T16:11:22.448-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Firebase"/><title type='text'>Firebase Functions e Firestore: executando localmente (comandos úteis)</title><content type='html'>&lt;p&gt;Neste post irei mostrar alguns comandos úteis para rodar e usar localmente o Google Firebase.&lt;/p&gt;&lt;p&gt;Primeiro você precisa inicializar seu projeto:&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;$ firebase init&lt;/p&gt;&lt;p&gt;Em seguida, será questionado sobre quais emuladores deseja instalar (por exemplo: Functions, Firestore, PubSub...).&lt;/p&gt;&lt;p&gt;Uma vez configurado, você precisa iniciar os emuladores:&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;$ firebase emulators:start&lt;/p&gt;&lt;p&gt;Com os emuladores no ar, inclusive a UI, você terá apoio visual, como abaixo:&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjC9-mUGUjYLPP3xZeGTYVBfgbCjfg9KrHxIgrbrJHVwELGeWnhtc9N5PXAMXl8RMaSJA2safZtZY1jcKKito8t9de9YZsRH1kxtrbO0BgWrsinB2sHc4fH1PyIUTbui37liSKVj58ENmHVhCACOeg_aneWuDFncPQpIjBw-zhp4UK9DTS13mZIglNjiK0/s1038/Firebase%20emulators.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;808&quot; data-original-width=&quot;1038&quot; height=&quot;249&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjC9-mUGUjYLPP3xZeGTYVBfgbCjfg9KrHxIgrbrJHVwELGeWnhtc9N5PXAMXl8RMaSJA2safZtZY1jcKKito8t9de9YZsRH1kxtrbO0BgWrsinB2sHc4fH1PyIUTbui37liSKVj58ENmHVhCACOeg_aneWuDFncPQpIjBw-zhp4UK9DTS13mZIglNjiK0/s320/Firebase%20emulators.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;No print acima, nota-se que há três emuladores: Firestore, Functions e PubSub.&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;E se você quiser testar alguma function? Primeiro execute o comando abaixo:&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;$ firebase functions:shell&lt;/p&gt;&lt;p&gt;Em seguida, chame a sua função pelo nome:&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;firebase &amp;gt; suaFuncao()&lt;/p&gt;&lt;p&gt;Depois de testar as funções e também os acessos às coleções do Firestore, faça o deploy remoto (produção):&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;firebase deploy --only functions&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;firebase deploy --only firestore&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/5158140743905324400/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2024/12/firebase-functions-e-firestore.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/5158140743905324400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/5158140743905324400'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2024/12/firebase-functions-e-firestore.html' title='Firebase Functions e Firestore: executando localmente (comandos úteis)'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjC9-mUGUjYLPP3xZeGTYVBfgbCjfg9KrHxIgrbrJHVwELGeWnhtc9N5PXAMXl8RMaSJA2safZtZY1jcKKito8t9de9YZsRH1kxtrbO0BgWrsinB2sHc4fH1PyIUTbui37liSKVj58ENmHVhCACOeg_aneWuDFncPQpIjBw-zhp4UK9DTS13mZIglNjiK0/s72-c/Firebase%20emulators.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-938061585476018621</id><published>2024-01-05T16:29:00.000-08:00</published><updated>2024-01-05T18:16:51.079-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Kafka"/><title type='text'>Kafka Confluent REST Proxy</title><content type='html'>&lt;div style=&quot;text-align: justify;&quot;&gt;O Kafka da Confluent tem alguns extras interessantes. Um deles é o REST Proxy. Neste post mostro exemplos simples de como utilizá-lo.&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Como pré-requisito, você precisa do Kafka da Confluent instalado, e este outro post &lt;a href=&quot;https://thiagocolen.blogspot.com/2023/12/instalacao-on-premise-do-kafka-da.html&quot;&gt;aqui&lt;/a&gt; trata disso.&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Feita a instalação, você precisa executar os dois comandos abaixo:&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;sudo systemctl start confluent-schema-registry confluent-kafka-rest&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;sudo systemctl enable confluent-schema-registry confluent-kafka-rest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Isto irá iniciar o Schema Registry e também o REST Proxy.&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Para verificar se está tudo em ordem, execute:&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;sudo systemctl status confluent-schema-registry confluent-kafka-rest&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Com eles no ar, vamos criar um tópico para iniciar a demonstração:&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;&lt;b&gt;kafka-topics&lt;/b&gt; --bootstrap-server localhost:9092 --create &lt;b&gt;--topic authors&lt;/b&gt; --partitions 1 --replication-factor 1&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;E agora vem o primeiro uso do REST Proxy: postar uma mensagem no tópico authors criado acima:&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;curl -X POST -H &quot;Content-Type: application/vnd.kafka.json.v2+json&quot; \&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;-H &quot;Accept: application/vnd.kafka.v2+json&quot; \&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: courier; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;--data &#39;{&quot;records&quot;:[{&quot;key&quot;:&quot;EN&quot;,&quot;value&quot;:&quot;Robert Hugh Benson&quot;}]}&#39;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt; &quot;&lt;/span&gt;&lt;b style=&quot;color: #0b5394;&quot;&gt;http://localhost:8082/topics/authors&lt;/b&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Aqui é usado o o curl (com alguns headers), mas o principal é o endereço que estamos chamando (/topics/authors) e o payload com um autor (um json). Este é o primeiro uso do REST Proxy (/topics).&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Executar essa chamada irá retornar algo assim:&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;{&quot;offsets&quot;:[{&quot;partition&quot;:0,&quot;offset&quot;:0,&quot;error_code&quot;:null,&quot;error&quot;:null}],&quot;key_schema_id&quot;:null,&quot;value_schema_id&quot;:null}&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Note que há algumas informações no retorno, como partição e offset.&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Agora iremos consumir mensagens deste mesmo tópico. Este processo requer três etapas.&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: red;&quot;&gt;1) Criar um consumidor e uma instância deste consumidor:&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;curl -X POST -H &quot;Content-Type: application/vnd.kafka.v2+json&quot; \&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;&lt;b&gt;--data &#39;{&quot;name&quot;: &quot;consumer_authors_instance&quot;, &quot;format&quot;: &quot;json&quot;, &quot;auto.offset.reset&quot;: &quot;earliest&quot;}&lt;/b&gt;&#39; \&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;&lt;b&gt;http://localhost:8082/consumers/consumer_authors&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;O ponto importante acima é o endereço: /consumers/&amp;lt;nome_do_seu_consumidor&amp;gt;. No caso eu escolhi consumer_authors.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Além disso, o payload também é importante. Nele estamos definindo o nome da instância (consumer_authors_instance), o formato e de onde iremos ler tópico (&quot;auto.offset.reset&quot;: &quot;earliest&quot;).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Obs.:&lt;/b&gt; auto.offset.reset:earliest serve para ler as mensagens a partir do início do tópico. A opção default é latest, e significa que a leitura das mensagens não se dará do início, mas a partir das mensagens mais novas (escritas depois que o consumidor entrou no ar).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Neste ponto temos outro uso do REST Proxy: /consumers.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Quando este comando for executado, ele irá retornar algo assim:&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;{&quot;instance_id&quot;:&quot;consumer_authors_instance&quot;,&quot;&lt;b&gt;base_uri&lt;/b&gt;&quot;:&quot;http://localhost:8082/consumers/consumer_authors/instances/consumer_authors_instance&quot;}&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Repare bem no atributo base_uri acima, em negrito. Seu valor será usado daqui pra frente.&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: red;&quot;&gt;2) Se inscrever no tópico (subscribe):&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;curl -X POST -H &quot;Content-Type: application/vnd.kafka.v2+json&quot; \&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;&lt;b&gt;--data &#39;{&quot;topics&quot;:[&quot;authors&quot;]}&#39;&lt;/b&gt; \&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;http://localhost:8082/consumers/consumer_authors/instances/consumer_authors_instance/subscription&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Repare no comando acima que no payload informamos em qual tópico queremos nos inscrever. E depois, repare na url. É a &lt;b&gt;base_uri&lt;/b&gt; retornada anteriormente com a adição de /subscription. Em outras palavras, neste comando estamos dizendo que a instância do consumidor está associada ao tópico authors. Novamente estamos usando um endpoint do REST Proxy.&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: red;&quot;&gt;&lt;b&gt;3) Consumir as mensagens:&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;curl -X GET -H &quot;Accept: application/vnd.kafka.json.v2+json&quot; \&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;&lt;b&gt;http://localhost:8082/consumers/consumer_authors/instances/consumer_authors_instance/records&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Novamente aparece aqui a &lt;b&gt;base_uri&lt;/b&gt; com outro adendo: /records.&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Ao executar esta chamada, será retornado algo semelhante a isso, com as mensagens que estão no tópico:&lt;br /&gt;&lt;br /&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;[{&quot;topic&quot;:&quot;authors&quot;,&quot;key&quot;:&quot;EN&quot;,&quot;value&quot;:&quot;Robert Hugh Benson&quot;,&quot;partition&quot;:0,&quot;offset&quot;:0},{&quot;topic&quot;:&quot;authors&quot;,&quot;key&quot;:&quot;EN&quot;,&quot;value&quot;:&quot;G. K. Chesterton&quot;,&quot;partition&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;&quot;:0,&quot;offset&quot;:1}]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Quando não precisar mais do consumer, você deve deletá-lo:&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;curl -X DELETE -H &quot;Content-Type: application/vnd.kafka.v2+json&quot; \&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;http://localhost:8082/consumers/consumer_authors/instances/consumer_authors_instance&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Há muitos outros endpoints úteis. Dois exemplos:&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Para listar os tópicos existentes:&amp;nbsp;http://localhost:8082/topics. Isto retornará algo como:&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;[&quot;__confluent.support.metrics&quot;,&quot;_schemas&quot;,&quot;authors&quot;,&quot;rest-test-topic&quot;]&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Para obter informações sobre partições de um tópico:&amp;nbsp;http://localhost:8082/topics/authors/partitions. Isto retornará algo assim:&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;[{&quot;partition&quot;:0,&quot;leader&quot;:1,&quot;replicas&quot;:[{&quot;broker&quot;:1,&quot;leader&quot;:true,&quot;in_sync&quot;:true}]}]&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/938061585476018621/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2024/01/kafka-confluent-rest-proxy.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/938061585476018621'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/938061585476018621'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2024/01/kafka-confluent-rest-proxy.html' title='Kafka Confluent REST Proxy'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-2725351970841241992</id><published>2023-12-26T17:32:00.000-08:00</published><updated>2023-12-26T17:32:40.816-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Kafka"/><title type='text'>Instalação on-premise do Kafka da Confluent no Ubuntu (Systemd)</title><content type='html'>&lt;div style=&quot;text-align: justify;&quot;&gt;Este post será dividido em três partes: instalação, configuração e inicialização. E vai considerar um cluster / ensemble de três servidores / brokers.&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;i style=&quot;text-align: left;&quot;&gt;Obs.:&lt;/i&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&amp;nbsp;a maior parte dos passos descritos aqui devem ser executados nos N hosts do cluster.&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span style=&quot;color: red;&quot;&gt;Instalação&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Instale a chave pública da Confluent:&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;wget -qO - https://packages.confluent.io/deb/7.0/archive.key | sudo apt-key add -&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Adicione o repositório da Confluent:&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;add-apt-repository &quot;deb [arch=amd64] https://packages.confluent.io/deb/7.0 stable main&quot;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Instale a versão Community:&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;apt-get update &amp;amp;&amp;amp; sudo apt-get install -y openjdk-8-jre-headless confluent-community-2.13&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: red;&quot;&gt;Configuração&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Aqui serão consideradas as configurações do ZooKeeper e do Kafka.&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;A primeira coisa é definir o id do servidor ZooKeeper. Para isso, crie um arquivo chamado &lt;b&gt;myid&lt;/b&gt; no diretório&amp;nbsp;&lt;b&gt;/var/lib/zookeeper&lt;/b&gt;. Coloque neste arquivo o id, por exemplo 1. &lt;i&gt;Obs.:&lt;/i&gt; em cada um dos N hosts, este arquivo deverá ser criado e preenchido com seu respectivo id. Portanto, no primeiro host, 1; no segundo host, 2; no terceiro host, 3 (considerando que é um cluster de 3 nós).&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Depois, edite as configurações do ZooKeeper neste arquivo:&amp;nbsp;&lt;b&gt;/etc/kafka/zookeeper.properties&lt;/b&gt;.&amp;nbsp;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;tickTime=2000&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;dataDir=/var/lib/zookeeper/&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;clientPort=2181&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;initLimit=5&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;syncLimit=2&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;server.1=host1:2888:3888&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;server.2=&lt;/span&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: small;&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;2:2888:3888&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;server.3=&lt;/span&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: small;&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;3:2888:3888&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;O conteúdo acima pode conter mais ou menos propriedades e depende de vários fatores do seu ambiente e de seus requisitos. Segue uma breve explicação sobre os que foram usados aqui:&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;tickTime:&lt;/b&gt;&amp;nbsp;é uma unidade, usada com initLimit e syncLimit (uma variável, ver abaixo);&lt;/li&gt;&lt;li&gt;&lt;b&gt;dataDir:&lt;/b&gt;&amp;nbsp;local onde o arquivo myid se encontra;&lt;/li&gt;&lt;li&gt;&lt;b&gt;clientPort:&lt;/b&gt;&amp;nbsp;porta na qual os membros irão se conectar ao ensemble;&lt;/li&gt;&lt;li&gt;&lt;b&gt;initLimit:&lt;/b&gt;&amp;nbsp;tempo para os followers se conectarem com um líder (inicialização). Este valor é multiplicado pelo tickTime;&lt;/li&gt;&lt;li&gt;&lt;b&gt;syncLimit:&lt;/b&gt;&amp;nbsp;tempo que um follower pode ficar dessincronizado de um líder. Este valor é multiplicado pelo tickTime;&lt;/li&gt;&lt;li&gt;&lt;b&gt;server.N:&lt;/b&gt;&amp;nbsp;onde N é o id do servidor (membro do cluster). Em seguida você tem o host e duas portas. A primeira é a que será utilizada na comunicação entre os nós. Enquanto a segunda porta é usada durante a eleição do líder.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Agora vamos às configurações do Kafka. Edite o arquivo&amp;nbsp;&lt;b&gt;/etc/kafka/server.properties&lt;/b&gt; e faça as seguintes alterações:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;broker.id:&lt;/b&gt; defina um identificador único para o broker (único dentro do cluster);&lt;/li&gt;&lt;li&gt;&lt;b&gt;zookeeper.connect:&lt;/b&gt; host e porta do Zookeeper. Você pode especificar N, separando-os por vírgula. É onde os metadados do cluster serão buscados.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: red;&quot;&gt;Inicialização&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Execute estes comandos:&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;systemctl start confluent-zookeeper&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;systemctl enable confluent-zookeeper&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;systemctl start confluent-kafka&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;systemctl enable confluent-kafka&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Para verificar se os serviços estão rodando:&amp;nbsp;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;systemctl status confluent*&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Um outro teste útil, é listar os tópicos:&amp;nbsp;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;kafka-topics --list --bootstrap-server localhost:9092&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Isto deverá gerar uma saída com este valor:&amp;nbsp;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;_confluent.support.metrics&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Obs.: não fiz a configuração do Schema Registry aqui, mas farei em outra postagem futura.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/2725351970841241992/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2023/12/instalacao-on-premise-do-kafka-da.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/2725351970841241992'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/2725351970841241992'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2023/12/instalacao-on-premise-do-kafka-da.html' title='Instalação on-premise do Kafka da Confluent no Ubuntu (Systemd)'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-8373910473137633287</id><published>2023-10-16T19:42:00.003-07:00</published><updated>2023-11-15T14:47:10.610-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Kafka"/><title type='text'>Kafka: compactação de tópicos</title><content type='html'>&lt;div style=&quot;text-align: justify;&quot;&gt;O Kafka provê um meio para compactar tópicos. Na prática, é um mecanismo de retenção baseado na chave da mensagem -- não confundir com a &lt;a href=&quot;http://thiagocolen.blogspot.com/2023/05/kafka-retencao-de-mensagens-por-tempo.html&quot;&gt;retenção por tempo&lt;/a&gt;, nem com a&amp;nbsp;&lt;a href=&quot;http://thiagocolen.blogspot.com/2023/10/kafka-compressao-de-mensagens.html&quot;&gt;compressão&lt;/a&gt; de mensagens.&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;A compactação é útil em cenários onde você está interessado somente na mensagem / informação mais atualizada ou recente, por exemplo:&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;ul&gt;&lt;li&gt;Endereço postal ou eletrônico de um cliente;&lt;/li&gt;&lt;li&gt;Estado de uma aplicação ou de um registro / objeto de negócio;&lt;/li&gt;&lt;li&gt;Preços;&lt;/li&gt;&lt;li&gt;Geolocalização.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Para fazer isso o Kafka elimina todas as mensagens com chaves repetidas e mantém apenas a mais atual.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Existem duas situações onde a compactação é iniciada / disparada:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;Proporção:&lt;/b&gt; quando 50% do tópico contiver dados sujos, ou seja, dados ainda não analisados pelo processo de compactação. A partição é dividida em duas áreas (limpa e suja ou clean e dirty). A parte limpa é a que já não contém chaves repetidas (ou seja, onde o processo de compactação já rodou);&lt;/li&gt;&lt;li&gt;&lt;b&gt;Tempo máximo para compactação:&lt;/b&gt; através da propriedade&amp;nbsp;max.compaction.lag.ms é possível informar o tempo máximo, a partir do qual a compactação irá rodar, independente da proporção de dado sujo. Em outras palavras, é o tempo máximo entre a escrita da mensagem e ela estar disponível para compactação.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;Abaixo irei mostrar como fazer o segundo cenário (tempo máximo). A primeira coisa é alterar o server.properties e adicionar duas linhas:&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;log.cleanup.policy=compact&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;max.compaction.lag.ms=10000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A primeira linha acima indica que iremos usar a compactação (ela é habilitada) e a segunda linha indica que o tempo máximo é de 10 minutos.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: red;&quot;&gt;&lt;b&gt;Importante:&lt;/b&gt;&lt;/span&gt; somente segmentos fechados ou inativos são elegíveis para compactação (este post &lt;a href=&quot;http://thiagocolen.blogspot.com/2023/10/kafka-como-definir-o-tamanho-de-um-log.html&quot;&gt;aqui&lt;/a&gt; pode ajudar a entender o que é um log segment fechado).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Prosseguindo com a explicação, o próximo passo é postar mensagens com chaves repetidas. Após postar 25 mil mensagens (5 chaves diferentes, enviadas 5 mil vezes), os segmentos ficaram assim:&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;963K out 16 23:08 00000000000000000000.log&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;975K out 16 23:08 00000000000000009159.log&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;691K out 16 23:08 00000000000000018431.log&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Acima, o log segment aberto ou ativo é o final 18431.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Após 10 minutos, se olhar novamente a pasta do tópico e da partição, você verá os segmentos um pouco diferentes:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;0 out 16 23:08 00000000000000000000.log&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;599 out 16 23:08 00000000000000009159.log&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;691K out 16 23:08 00000000000000018431.log&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Nota-se agora que os dois primeiros segmentos mudaram de tamanho, estão mais vazios. O primeiro zerado e o segundo bem pequeno. Já o segmento ativo (final 18431 segue com o mesmo tamanho).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Se você acessar o segundo segmento, verá que ele possui apenas 5 mensagens (as 5 chaves diferentes que mencionei acima):&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;| offset: 46114 CreateTime: 1697509329848 keySize: 8 valueSize: 87 sequence: 21114 headerKeys: [] &lt;b&gt;key&lt;/b&gt;: Luke1,30 payload: Then the angel said to her, &quot;Do not be afraid, Mary, for you have found favor with God.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;| offset: 46115 CreateTime: 1697509329848 keySize: 8 valueSize: 94 sequence: 21115 headerKeys: [] &lt;b&gt;key&lt;/b&gt;: Luke1,26 payload: In the sixth month, the angel Gabriel was sent from God to a town of Galilee called Nazareth,&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;| offset: 46116 CreateTime: 1697509329848 keySize: 8 valueSize: 100 sequence: 21116 headerKeys: [] &lt;b&gt;key&lt;/b&gt;: Luke1,27 payload: to a virgin betrothed to a man named Joseph, of the house of David, and the virgin&#39;s name was Mary.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;| offset: 46117 CreateTime: 1697509329848 keySize: 8 valueSize: 71 sequence: 21117 headerKeys: [] &lt;b&gt;key&lt;/b&gt;: Luke1,28 payload: And coming to her, he said, &quot;Hail, favored one! The Lord is with you.&quot;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;| offset: 46118 CreateTime: 1697509329848 keySize: 8 valueSize: 96 sequence: 21118 headerKeys: [] &lt;b&gt;key&lt;/b&gt;: Luke1,29 payload: But she was greatly troubled at what was said and pondered what sort of greeting this might be.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Testado no Kafka 3.4.0.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/8373910473137633287/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2023/10/kafka-compactacao-de-topicos.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/8373910473137633287'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/8373910473137633287'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2023/10/kafka-compactacao-de-topicos.html' title='Kafka: compactação de tópicos'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-1795859818212664909</id><published>2023-10-16T13:16:00.002-07:00</published><updated>2023-10-16T13:26:30.528-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Kafka"/><title type='text'>Kafka: como definir o tamanho de um log segment</title><content type='html'>&lt;p style=&quot;text-align: justify;&quot;&gt;Log segment é um arquivo que armazena as mensagens no Kafka. O tamanho padrão dele é 1GB, mas você pode modificar isso através da propriedade&amp;nbsp;&lt;b&gt;log.segment.bytes&lt;/b&gt; (no arquivo server.properties). Ao definir o tamanho de&amp;nbsp;1.000.000 (~975K) ficará fácil ver N log segments no diretório da partição:&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;$pwd&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #38761d; font-family: courier; font-size: x-small;&quot;&gt;/tmp/kafka-logs/verses-0&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;$ls -lah *.log&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #38761d; font-family: courier; font-size: x-small;&quot;&gt;974K out 16 16:24 00000000000000000000.log&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #38761d; font-family: courier; font-size: x-small;&quot;&gt;975K out 16 16:24 00000000000000009267.log&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #38761d; font-family: courier; font-size: x-small;&quot;&gt;679K out 16 16:24 00000000000000018539.log&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Acima você pode ver que estamos no diretório &lt;b&gt;verses-0&lt;/b&gt;, ou seja, tópico verses, partição 0. Em seguida, aparecem 3 log segments. Os dois primeiros de ~975K (já fechados) e o segundo de um pouco menos.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;b&gt;Nota:&lt;/b&gt; estes números nos nomes dos arquivos são os offsets de início (starting offset). Por exemplo, o offset inicial do arquivo 00000000000000000000.log é 0. Já do arquivo&amp;nbsp;00000000000000009267.log é 9267 e por fim, do arquivo&amp;nbsp;&amp;nbsp;00000000000000018539.log é 18539.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: red;&quot;&gt;Alerta:&lt;/span&gt;&lt;/b&gt; definir um log segment muito pequeno reduzirá a performance, pois mais escritas serão necessárias, já que log segments serão fechados e alocados mais frequentemente.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Testado no Kafka 3.4.0.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/1795859818212664909/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2023/10/kafka-como-definir-o-tamanho-de-um-log.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/1795859818212664909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/1795859818212664909'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2023/10/kafka-como-definir-o-tamanho-de-um-log.html' title='Kafka: como definir o tamanho de um log segment'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-8412288237038605280</id><published>2023-10-13T20:30:00.001-07:00</published><updated>2023-10-13T20:30:28.191-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Kafka"/><title type='text'>Kafka: como visualizar as mensagens em uma partição (log segment)</title><content type='html'>&lt;p&gt;Para visualizar mensagens em uma partição, utilize o comando abaixo:&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;kafka-run-class.sh kafka.tools.DumpLogSegments --print-data-log --files /tmp/kafka-logs/comp-lz4-0/00000000000000000000.log&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;A flag print-data-log indica que você deseja ver o conteúdo da mensagem. Já a flag files indica qual arquivo será lido. Neste exemplo acima, comp-lz4-0 é o nome do tópico (comp-lz4) e 0 é a partição.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;A saída deste comando será algo assim:&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;| &lt;b&gt;offset&lt;/b&gt;: 0 CreateTime: 1697250280386 keySize: 1 valueSize: 71 sequence: 0 headerKeys: [] &lt;b&gt;key&lt;/b&gt;: a &lt;b&gt;payload&lt;/b&gt;: In principio erat Verbum, et Verbum erat apud Deum, et Deus erat Verbum&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Note que é exibido o offset, a key e o payload entre outras coisas.&lt;/p&gt;&lt;p&gt;Testado no Kafka 3.4.0.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/8412288237038605280/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2023/10/kafka-como-visualizar-as-mensagens-em.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/8412288237038605280'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/8412288237038605280'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2023/10/kafka-como-visualizar-as-mensagens-em.html' title='Kafka: como visualizar as mensagens em uma partição (log segment)'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-4818018231962180711</id><published>2023-10-13T20:04:00.006-07:00</published><updated>2023-10-13T20:04:31.086-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Desempenho"/><category scheme="http://www.blogger.com/atom/ns#" term="Kafka"/><title type='text'>Kafka: compressão de mensagens</title><content type='html'>&lt;div style=&quot;text-align: justify;&quot;&gt;Por que é bom comprimir mensagens? Porque isto reduz o uso da rede e também do disco. Portanto, faça isso se estes dois aspectos são motivos de preocupação para você.&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Isto pode ser feito através do parâmetro &lt;b&gt;compression.type&lt;/b&gt; e o padrão é sem compressão ou&amp;nbsp;uncompressed. Os tipos de compressão (algoritmos) disponíveis são: zstd, lz4, snappy e gzip.&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;div&gt;Lembrando que a mensagem é comprimida antes de ser enviada ao broker.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;No teste que fiz, postei 2.000 mensagens num tópico. O resultado da compressão ficou como abaixo:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEiv6iOBwmdCgtwWka1pt57sFVX4pQp9_Iud9cE5e3RvgfxFXqDE9EZvhffb8Uu0UoixEh6U5UWtx828Rv1chQMCoVDGEmSnoHyDL1MjrbrR4v-1RqVjGYHS55RvY9ScpOCkGmRxOuabU2MzLrHx8wT9YTsp8c_1edVFljBYr7gt-G1BhVXpvnfYR7aLAqQ&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;118&quot; data-original-width=&quot;291&quot; height=&quot;130&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEiv6iOBwmdCgtwWka1pt57sFVX4pQp9_Iud9cE5e3RvgfxFXqDE9EZvhffb8Uu0UoixEh6U5UWtx828Rv1chQMCoVDGEmSnoHyDL1MjrbrR4v-1RqVjGYHS55RvY9ScpOCkGmRxOuabU2MzLrHx8wT9YTsp8c_1edVFljBYr7gt-G1BhVXpvnfYR7aLAqQ&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Portanto, a opção que mais comprime é zstd, seguida de gzip, lz4 e snappy. A primeira opção -- zstd -- representa uma economia de 96%. Enquanto a última -- snappy -- economiza 88%.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Segue um exemplo de como definir a compressão na criação de um tópico:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;kafka-topics.sh --bootstrap-server localhost:9092 --create --replication-factor 1 --partitions 1 --config &lt;b&gt;compression.type=zstd&lt;/b&gt; --topic comp-zstd&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Para verificar o tamanho ocupado, basta verificar o diretório onde as mensagens são armazenadas (definido através da propriedade log.dirs no server.properties). Em seguida, basta acessar o diretório correspondente ao seu tópico (por exemplo: /tmp/kafka-logs/comp-snappy-0) e verificar o arquivo &lt;b&gt;.log&lt;/b&gt;:&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;18K out 13 23:26 00000000000000000000.log&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/4818018231962180711/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2023/10/kafka-compressao-de-mensagens.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/4818018231962180711'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/4818018231962180711'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2023/10/kafka-compressao-de-mensagens.html' title='Kafka: compressão de mensagens'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEiv6iOBwmdCgtwWka1pt57sFVX4pQp9_Iud9cE5e3RvgfxFXqDE9EZvhffb8Uu0UoixEh6U5UWtx828Rv1chQMCoVDGEmSnoHyDL1MjrbrR4v-1RqVjGYHS55RvY9ScpOCkGmRxOuabU2MzLrHx8wT9YTsp8c_1edVFljBYr7gt-G1BhVXpvnfYR7aLAqQ=s72-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-7467804551863500899</id><published>2023-10-13T19:17:00.005-07:00</published><updated>2023-10-13T20:05:46.497-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Kafka"/><title type='text'>Kafka: como deletar tópicos</title><content type='html'>&lt;p&gt;Para deletar um tópico, basta usar o comando abaixo:&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;kafka-topics.sh --bootstrap-server localhost:9092 --delete --topic topic1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Para deletar vários tópicos, basta separá-los por vírgula:&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;kafka-topics.sh --bootstrap-server localhost:9092 --delete --topic topic1,topic2,topic3&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left;&quot;&gt;Testado no Kafka 3.4.0.&lt;/p&gt;&lt;p style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/7467804551863500899/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2023/10/kafka-como-deletar-topicos.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/7467804551863500899'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/7467804551863500899'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2023/10/kafka-como-deletar-topicos.html' title='Kafka: como deletar tópicos'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-1606927417820715589</id><published>2023-09-13T17:23:00.002-07:00</published><updated>2023-09-13T17:25:27.223-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Kafka"/><title type='text'>Kafka: consultando configurações com AdminClient</title><content type='html'>&lt;p&gt;Aqui será mostrado como ler algumas configurações -- compressão e retenção -- com o AdminClient.&lt;/p&gt;&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 9,8pt;&quot;&gt;&lt;pre&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;Properties properties = &lt;span style=&quot;color: #cc7832;&quot;&gt;new &lt;/span&gt;Properties()&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;properties.put(AdminClientConfig.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;BOOTSTRAP_SERVERS_CONFIG&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;localhost:9092&quot;&lt;/span&gt;)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;AdminClient admin = AdminClient.&lt;span style=&quot;font-style: italic;&quot;&gt;create&lt;/span&gt;(properties)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;ConfigResource resource = &lt;span style=&quot;color: #cc7832;&quot;&gt;new &lt;/span&gt;ConfigResource(ConfigResource.Type.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;TOPIC&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;seila&quot;&lt;/span&gt;)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;DescribeConfigsResult result = admin.describeConfigs(Collections.&lt;span style=&quot;font-style: italic;&quot;&gt;singleton&lt;/span&gt;(resource))&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;Config configs = result.all().get().get(resource)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;ConfigEntry compression = configs.get(TopicConfig.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;COMPRESSION_TYPE_CONFIG&lt;/span&gt;)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;System.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;out&lt;/span&gt;.println(compression.name() + &lt;span style=&quot;color: #6a8759;&quot;&gt;&quot; &quot; &lt;/span&gt;+ compression.value() + &lt;span style=&quot;color: #6a8759;&quot;&gt;&quot; &quot; &lt;/span&gt;+ compression.source())&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;ConfigEntry retention = configs.get(TopicConfig.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;RETENTION_MS_CONFIG&lt;/span&gt;)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;System.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;out&lt;/span&gt;.println(retention.name() + &lt;span style=&quot;color: #6a8759;&quot;&gt;&quot; &quot; &lt;/span&gt;+ retention.value() + &lt;span style=&quot;color: #6a8759;&quot;&gt;&quot; &quot; &lt;/span&gt;+ retention.source())&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;No código acima, criamos um ConfigResource informando que se trata de um tópico, cujo nome é &quot;seila&quot;. Em seguida, o describeConfigs é chamado e as configurações são lidas e armazenadas no objeto configs. Por fim, lemos as configurações desejadas: compressão e retenção (respectivamente uma configuração de tópico e broker).&lt;/p&gt;&lt;p&gt;O tópico deste exemplo foi criado com esta linha de comando:&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;font-family: courier; font-size: x-small;&quot;&gt;kafka-topics.sh --bootstrap-server localhost:9092 --create --replication-factor 1 --partitions 1 --config &lt;b&gt;compression.type=gzip&lt;/b&gt; --topic seila&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Portanto, a saída do código Java acima é algo assim:&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier; font-size: x-small;&quot;&gt;compression.type gzip DYNAMIC_TOPIC_CONFIG&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier; font-size: x-small;&quot;&gt;retention.ms 604800000 DEFAULT_CONFIG&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;b&gt;Explicação:&lt;/b&gt; na criação do tópico foi definida a compressão gzip (como se vê na linha de comando acima e depois na primeira linha da saída do programa). Quanto ao valor&amp;nbsp;DYNAMIC_TOPIC_CONFIG retornado pelo método&amp;nbsp;compression.source(), ele indica que foi uma alteração manual / dinâmica e não uma configuração padrão. Já na segunda linha da saída (retenção), o valor retornado é o default (log.retention.hours=168) definido no server.properties do broker, pois 168 horas equivale a&amp;nbsp;604800000 milisegundos.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;Testado com o&amp;nbsp;kafka-clients 3.4.1 e Kafka 3.4.0.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/1606927417820715589/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2023/09/kafka-consultando-configuracoes-com.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/1606927417820715589'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/1606927417820715589'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2023/09/kafka-consultando-configuracoes-com.html' title='Kafka: consultando configurações com AdminClient'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-2770001994889726724</id><published>2023-09-07T15:44:00.000-07:00</published><updated>2023-09-07T15:44:02.120-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Kafka"/><category scheme="http://www.blogger.com/atom/ns#" term="Messaging"/><title type='text'>Kafka: consultando tópicos com AdminClient</title><content type='html'>&lt;p style=&quot;text-align: justify;&quot;&gt;Uma maneira de consultar informações sobre tópicos é usar o AdminClient (programaticamente). Aqui serão mostradas duas coisas: listar tópicos e descrever alguns detalhes deles.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;A primeira coisa a se fazer é criar um objeto AdminClient e passar para ele pelo menos a indicação dos brokers do seu cluster (aqui passo apenas um endereço). Feito isso, você já pode chamar o listTopics, como no código abaixo, que exibe os nomes dos tópicos:&lt;/p&gt;&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; font-family: &#39;JetBrains Mono&#39;,monospace; font-size: 9,8pt;&quot;&gt;&lt;pre&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;Properties properties = &lt;span style=&quot;color: #cc7832;&quot;&gt;new &lt;/span&gt;Properties()&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;properties.put(AdminClientConfig.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;BOOTSTRAP_SERVERS_CONFIG&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;localhost:9092&quot;&lt;/span&gt;)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;AdminClient admin = AdminClient.&lt;span style=&quot;font-style: italic;&quot;&gt;create&lt;/span&gt;(properties)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;ListTopicsResult topics = admin.listTopics()&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;topics.names().get().forEach(System.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;out&lt;/span&gt;::println)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;admin.close()&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Outra coisa que é possível fazer é descrever um tópico e obter informações como: número de partições, id do tópico, nome do tópico, informação do líder e algumas outras.&lt;/p&gt;&lt;p&gt;A criação do AdminClient também é necessária aqui, mas é feita da mesma forma como foi feita acima.&amp;nbsp;&lt;/p&gt;&lt;p&gt;Primeiro você chama o describeTopics passando uma lista de tópicos. Isto retornará um mapa e através dele é possível obter um TopicDescription. Mais abaixo você pode obter informações de partições.&lt;/p&gt;&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; font-family: &#39;JetBrains Mono&#39;,monospace; font-size: 9,8pt;&quot;&gt;&lt;pre&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;DescribeTopicsResult result = admin.describeTopics(List.&lt;span style=&quot;font-style: italic;&quot;&gt;of&lt;/span&gt;(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;topic-20230724-aa&quot;&lt;/span&gt;))&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;Map &amp;lt;String&lt;span style=&quot;color: #cc7832;&quot;&gt;, &lt;/span&gt;KafkaFuture&amp;lt;TopicDescription&amp;gt;&amp;gt; map = result.topicNameValues()&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;KafkaFuture&amp;lt;TopicDescription&amp;gt; futureDesc = map.get(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;topic-20230724-aa&quot;&lt;/span&gt;)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;TopicDescription desc = futureDesc.get()&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;System.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;out&lt;/span&gt;.println(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;Id: &quot; &lt;/span&gt;+ desc.topicId())&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;System.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;out&lt;/span&gt;.println(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;Nome: &quot; &lt;/span&gt;+ desc.name())&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;System.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;out&lt;/span&gt;.println(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;Interno? &quot; &lt;/span&gt;+ desc.isInternal())&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;List&amp;lt;TopicPartitionInfo&amp;gt; partitions = desc.partitions()&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;System.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;out&lt;/span&gt;.println(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;Partições: &quot; &lt;/span&gt;+ partitions.size())&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;for &lt;/span&gt;(TopicPartitionInfo info : partitions) {&lt;br /&gt;    System.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;out&lt;/span&gt;.println(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;Partição: &quot; &lt;/span&gt;+ info.partition())&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color: grey;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: grey;&quot;&gt;    &lt;/span&gt;System.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;out&lt;/span&gt;.println(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;Líder &quot; &lt;/span&gt;+ info.leader())&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;}&lt;/pre&gt;&lt;pre&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;É possível fazer algo semelhante via linha de comando (só pra lembrar):&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;kafka-topics.sh --bootstrap-server localhost:9092 --describe --topic topic-20230724-aa&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Testado com o&amp;nbsp;kafka-clients 3.4.1 e Kafka 3.4.0.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/2770001994889726724/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2023/09/kafka-consultando-topicos-com.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/2770001994889726724'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/2770001994889726724'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2023/09/kafka-consultando-topicos-com.html' title='Kafka: consultando tópicos com AdminClient'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-5277119901036265529</id><published>2023-07-24T16:30:00.003-07:00</published><updated>2023-07-24T16:30:36.750-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="Kafka"/><category scheme="http://www.blogger.com/atom/ns#" term="Messaging"/><title type='text'>Kafka: partitioner customizado</title><content type='html'>&lt;p style=&quot;text-align: justify;&quot;&gt;Se você precisa definir as partições de um tópico onde as mensagens serão gravadas, ou seja, se você precisa ter o controle disso, é preciso criar uma classe que implemente a interface Partitioner e no método partition implementar a sua lógica para determinar a partição.&lt;/p&gt;&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; font-family: &#39;JetBrains Mono&#39;,monospace; font-size: 9,8pt;&quot;&gt;&lt;pre&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;public class &lt;/span&gt;MyPartitioner &lt;span style=&quot;color: #cc7832;&quot;&gt;implements &lt;/span&gt;Partitioner {&lt;/pre&gt;&lt;pre&gt;&lt;br /&gt;&lt;div style=&quot;font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace;&quot;&gt;&lt;pre&gt;&lt;span style=&quot;color: #bbb529;&quot;&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;@Override&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;public int &lt;/span&gt;&lt;span style=&quot;color: #ffc66d;&quot;&gt;partition&lt;/span&gt;(String topic&lt;span style=&quot;color: #cc7832;&quot;&gt;, &lt;/span&gt;Object key&lt;span style=&quot;color: #cc7832;&quot;&gt;, byte&lt;/span&gt;[] bytes&lt;span style=&quot;color: #cc7832;&quot;&gt;,&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;                     &lt;/span&gt;Object value&lt;span style=&quot;color: #cc7832;&quot;&gt;, byte&lt;/span&gt;[] bytes1&lt;span style=&quot;color: #cc7832;&quot;&gt;, &lt;/span&gt;Cluster cluster) {&lt;/pre&gt;&lt;/div&gt;&lt;/pre&gt;&lt;pre&gt;        String k = (String) key&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;        if &lt;/span&gt;(topic.equals(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;topic-20230724-aa&quot;&lt;/span&gt;)) {&lt;br /&gt;            &lt;span style=&quot;color: #cc7832;&quot;&gt;if &lt;/span&gt;(k.equals(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;a&quot;&lt;/span&gt;)) {&lt;br /&gt;                &lt;span style=&quot;color: #cc7832;&quot;&gt;return &lt;/span&gt;&lt;span style=&quot;color: #6897bb;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;            &lt;/span&gt;} &lt;span style=&quot;color: #cc7832;&quot;&gt;else if &lt;/span&gt;(k.equals(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;b&quot;&lt;/span&gt;)) {&lt;br /&gt;                &lt;span style=&quot;color: #cc7832;&quot;&gt;return &lt;/span&gt;&lt;span style=&quot;color: #6897bb;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;            &lt;/span&gt;} &lt;span style=&quot;color: #cc7832;&quot;&gt;else if &lt;/span&gt;(k.equals(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;c&quot;&lt;/span&gt;)) {&lt;br /&gt;                &lt;span style=&quot;color: #cc7832;&quot;&gt;return &lt;/span&gt;&lt;span style=&quot;color: #6897bb;&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;            &lt;/span&gt;} &lt;span style=&quot;color: #cc7832;&quot;&gt;else  &lt;/span&gt;{&lt;br /&gt;                &lt;span style=&quot;color: #cc7832;&quot;&gt;return &lt;/span&gt;&lt;span style=&quot;color: #6897bb;&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;            &lt;/span&gt;}&lt;br /&gt;        } &lt;span style=&quot;color: #cc7832;&quot;&gt;else &lt;/span&gt;{&lt;br /&gt;            List&amp;lt;PartitionInfo&amp;gt; partitions = cluster.partitionsForTopic(topic)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;            int &lt;/span&gt;numPartitions = partitions.size()&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;            return &lt;/span&gt;Math.&lt;span style=&quot;font-style: italic;&quot;&gt;abs&lt;/span&gt;(Utils.&lt;span style=&quot;font-style: italic;&quot;&gt;murmur2&lt;/span&gt;(bytes)) % (numPartitions - &lt;span style=&quot;color: #6897bb;&quot;&gt;1&lt;/span&gt;)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;        &lt;/span&gt;}&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color: grey;&quot;&gt;// Outros métodos&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: grey;&quot;&gt;&lt;br /&gt;&lt;/span&gt;}&lt;/pre&gt;&lt;pre&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;No código acima, é aplicada uma regra para o tópico &quot;&lt;b&gt;topic-20230724-aa&lt;/b&gt;&quot; e outra para os demais tópicos. No primeiro caso (if), as mensagens cuja chave é &quot;a&quot; sempre vão para a partição 0, &quot;b&quot; para partição 1, &quot;c&quot; para a 2 e o restante para 3. Isto é apenas um exemplo.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Na prática os critérios podem ser os mais variados e complexos.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Para informar que você vai usar este Partitioner customizado, é preciso passar uma propriedade informando o mesmo para o KafkaProducer:&lt;/p&gt;&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; font-family: &#39;JetBrains Mono&#39;,monospace; font-size: 9,8pt;&quot;&gt;&lt;pre&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;kafkaProperties.put(&lt;br /&gt;        ProducerConfig.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;PARTITIONER_CLASS_CONFIG&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;,&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;partitioner.MyPartitioner&quot;&lt;/span&gt;)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;KafkaProducer producer = &lt;span style=&quot;color: #cc7832;&quot;&gt;new &lt;/span&gt;KafkaProducer&amp;lt;String&lt;span style=&quot;color: #cc7832;&quot;&gt;, &lt;/span&gt;String&amp;gt;(kafkaProperties)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Testado com o Kafka 3.4.0, Java 11 e kafka-clients 3.4.1.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/5277119901036265529/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2023/07/kafka-partitioner-customizado.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/5277119901036265529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/5277119901036265529'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2023/07/kafka-partitioner-customizado.html' title='Kafka: partitioner customizado'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-8939071358248787606</id><published>2023-07-22T19:31:00.004-07:00</published><updated>2023-07-22T19:33:28.936-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="Kafka"/><category scheme="http://www.blogger.com/atom/ns#" term="Messaging"/><title type='text'>Kafka: mensagens sem chave (key)</title><content type='html'>&lt;p style=&quot;text-align: justify;&quot;&gt;A chave/key é usada para determinar em qual partição a mensagem será escrita. Mensagens com a mesma chave são escritas na mesma partição.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;No código abaixo, só o tópico e o valor da mensagem são informados:&lt;/p&gt;&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 9,8pt;&quot;&gt;&lt;pre&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;ProducerRecord &amp;lt;String&lt;span style=&quot;color: #cc7832;&quot;&gt;, &lt;/span&gt;String&amp;gt; record = &lt;br /&gt;        &lt;span style=&quot;color: #cc7832;&quot;&gt;new &lt;/span&gt;ProducerRecord&amp;lt;&amp;gt;(&lt;br /&gt;                &lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;topic-20230722-c&quot;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;, &lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;test-&quot; &lt;/span&gt;+ &lt;span style=&quot;color: #cc7832;&quot;&gt;new &lt;/span&gt;Random().nextInt(&lt;span style=&quot;color: #6897bb;&quot;&gt;100&lt;/span&gt;))&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Quando uma mensagem é enviada sem especificar a chave/key, a partição é escolhida usando round-robin.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Você pode conferir este comportamento, verificando a quantidade de mensagens no tópico (uma linha / comando para cada partição):&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;$ kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list localhost:9092 --topic topic-20230722-c --partitions 0&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span style=&quot;color: #38761d; font-size: x-small;&quot;&gt;topic-20230722-c:0:10&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;$ kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list localhost:9092 --topic topic-20230722-c --partitions 1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;color: #38761d; font-family: courier; font-size: x-small;&quot;&gt;topic-20230722-c:1:5&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;$ kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list localhost:9092 --topic topic-20230722-c --partitions 2&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;color: #38761d; font-family: courier; font-size: x-small;&quot;&gt;topic-20230722-c:2:10&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Obs.: este outro post &lt;a href=&quot;http://thiagocolen.blogspot.com/2023/06/kafka-numero-de-mensagens-num-topico.html&quot; target=&quot;_blank&quot;&gt;aqui&lt;/a&gt; aborda o comando acima.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Como se nota, as mensagens vão sendo distribuídas entre as partições, respectivamente 10, 5 e 10 mensagens.&lt;/p&gt;&lt;p&gt;Também é possível verificar as mensagens nas partições através do kafka-console-consumer (basta mudar o número da partição no final):&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;$ kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic topic-20230722-c --from-beginning --partition 0&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Nota: se você rodar o consumer sem especificar a partição, todas as mensagens do tópico -- de todas as partições -- serão consumidas.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/8939071358248787606/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2023/07/kafka-mensagens-sem-chave-key.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/8939071358248787606'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/8939071358248787606'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2023/07/kafka-mensagens-sem-chave-key.html' title='Kafka: mensagens sem chave (key)'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-5969598540340616549</id><published>2023-06-24T11:05:00.007-07:00</published><updated>2023-07-22T19:14:11.228-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="Kafka"/><category scheme="http://www.blogger.com/atom/ns#" term="Messaging"/><title type='text'>Kafka: Producer Interceptor</title><content type='html'>&lt;div style=&quot;text-align: justify;&quot;&gt;Você pode criar um interceptor no contexto do Produtor Kafka. Para isso, basta implementar a interface&amp;nbsp;ProducerInterceptor. Os principais métodos desta interface são:&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;onSend&lt;/b&gt;: este método é chamado antes da mensagem ser serializada, ou seja, antes dela ser enviada ao Kafka. Ele é útil para capturar informações da mensagem e também modificá-la (headers, tratar informações sensíveis, ...);&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;b&gt;onAcknowledgement&lt;/b&gt;: é chamado quando o Kafka confirma o recebimento. É útil para obter informações da resposta.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Como se vê, é um recurso útil para monitoramento.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Segue uma implementação de exemplo:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; font-family: &#39;JetBrains Mono&#39;,monospace; font-size: 9,8pt;&quot;&gt;&lt;pre&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;public class &lt;/span&gt;MyProducerInterceptor&lt;br /&gt;        &lt;span style=&quot;color: #cc7832;&quot;&gt;implements &lt;/span&gt;ProducerInterceptor&amp;lt;String&lt;span style=&quot;color: #cc7832;&quot;&gt;, &lt;/span&gt;String&amp;gt; {&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color: #bbb529;&quot;&gt;@Override&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #bbb529;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;public &lt;/span&gt;ProducerRecord&amp;lt;String&lt;span style=&quot;color: #cc7832;&quot;&gt;, &lt;/span&gt;String&amp;gt; &lt;span style=&quot;color: #ffc66d;&quot;&gt;onSend&lt;/span&gt;(&lt;br /&gt;            ProducerRecord&amp;lt;String&lt;span style=&quot;color: #cc7832;&quot;&gt;, &lt;/span&gt;String&amp;gt; producerRecord) {&lt;br /&gt;&lt;br /&gt;        System.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;out&lt;/span&gt;.println(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;Mensagem enviada, vou modificar&quot;&lt;/span&gt;)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;        &lt;/span&gt;String valor = producerRecord.value()&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;        &lt;/span&gt;System.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;out&lt;/span&gt;.println(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;Valor original: &quot; &lt;/span&gt;+ valor)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;        return new &lt;/span&gt;ProducerRecord&amp;lt;&amp;gt;(&lt;br /&gt;                &lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;teste-purge3&quot;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;,&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;,&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;                &lt;/span&gt;valor + &lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;SOMETHING&quot;&lt;/span&gt;)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;    &lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color: #bbb529;&quot;&gt;@Override&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #bbb529;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;public void &lt;/span&gt;&lt;span style=&quot;color: #ffc66d;&quot;&gt;onAcknowledgement&lt;/span&gt;(RecordMetadata recordMetadata&lt;span style=&quot;color: #cc7832;&quot;&gt;,&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;                                  &lt;/span&gt;Exception e) {&lt;br /&gt;&lt;br /&gt;        System.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;out&lt;/span&gt;.println(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;Ack realizado&quot;&lt;/span&gt;)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;        &lt;/span&gt;System.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;out&lt;/span&gt;.println(recordMetadata.offset())&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;    &lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color: #bbb529;&quot;&gt;@Override&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #bbb529;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;public void &lt;/span&gt;&lt;span style=&quot;color: #ffc66d;&quot;&gt;close&lt;/span&gt;() {&lt;br /&gt;        System.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;out&lt;/span&gt;.println(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;Close&quot;&lt;/span&gt;)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;    &lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color: #bbb529;&quot;&gt;@Override&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #bbb529;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;public void &lt;/span&gt;&lt;span style=&quot;color: #ffc66d;&quot;&gt;configure&lt;/span&gt;(Map&amp;lt;String&lt;span style=&quot;color: #cc7832;&quot;&gt;, &lt;/span&gt;?&amp;gt; map) {&lt;br /&gt;        System.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;out&lt;/span&gt;.println(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;Configure&quot;&lt;/span&gt;)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;        &lt;/span&gt;Set&amp;lt;String&amp;gt; keys = map.keySet()&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;        for &lt;/span&gt;(String k : keys) {&lt;br /&gt;            System.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;out&lt;/span&gt;.println(k + &lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;: &quot; &lt;/span&gt;+ map.get(k))&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;        &lt;/span&gt;}&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Além dos dois método citados acima, como pode ser visto no código a interface também conta com o método configure. Ele é o primeiro a ser executado e você tem acesso a toda configuração do produtor (parâmetros). Útil também para fazer algum setup do seu lado.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Para este interceptor funcionar, na configuração do seu produtor, utilize:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 9,8pt;&quot;&gt;&lt;pre&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;kafkaProperties.put(&lt;br /&gt;        ProducerConfig.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;INTERCEPTOR_CLASSES_CONFIG&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;, &lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;xpto.interceptor.MyProducerInterceptor&quot;&lt;/span&gt;)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/5969598540340616549/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2023/06/kafka-producer-interceptor.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/5969598540340616549'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/5969598540340616549'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2023/06/kafka-producer-interceptor.html' title='Kafka: Producer Interceptor'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-4873845297038520594</id><published>2023-06-21T16:56:00.002-07:00</published><updated>2023-06-21T16:56:27.242-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Kafka"/><category scheme="http://www.blogger.com/atom/ns#" term="Messaging"/><title type='text'>Kafka: buffer.memory VS batch.size</title><content type='html'>&lt;p style=&quot;text-align: justify;&quot;&gt;Estes dois parâmetros dos produtores Kafka podem ser confundidos. Segue abaixo a diferença entre eles.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Quando enviamos mensagens (através do método send), é utilizado um buffer. O tamanho dele é controlado através do parâmetro &lt;b&gt;buffer.memory&lt;/b&gt;. Em outras palavras, é um espaço relativo à mensagens que estão esperando para serem enviadas aos brokers. Se este buffer estiver cheio, o produtor bloqueia pelo tempo definido em outro parâmetro: &lt;b&gt;max.block.ms&lt;/b&gt;. Se durante este tempo o buffer não ficar livre, uma exceção será lançada.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Já &lt;b&gt;batch.size&lt;/b&gt; é usado num contexto diferente. As mensagens que são enviadas para a mesma partição são agrupadas no mesmo lote ou batch e ocupam um espaço. Este parâmetro trata deste espaço (em bytes). &lt;b&gt;Atenção:&lt;/b&gt; configurar um batch muito pequeno provocará overhead, pois causará envios mais frequentes.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/4873845297038520594/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2023/06/kafka-buffermemory-vs-batchsize.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/4873845297038520594'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/4873845297038520594'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2023/06/kafka-buffermemory-vs-batchsize.html' title='Kafka: buffer.memory VS batch.size'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-8175442610057430015</id><published>2023-06-17T18:00:00.009-07:00</published><updated>2023-06-24T10:26:14.794-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="Kafka"/><category scheme="http://www.blogger.com/atom/ns#" term="Messaging"/><title type='text'>Kafka: produtor síncrono</title><content type='html'>&lt;div style=&quot;text-align: justify;&quot;&gt;A primeira coisa ao criar um produtor que envia mensagens para o Kafka, é instanciar um KafkaProducer. Ele espera um Properties com algumas informações obrigatórias:&lt;/div&gt;&lt;div&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li style=&quot;text-align: justify;&quot;&gt;&lt;b&gt;Lista de brokers Kafka (host e porta):&lt;/b&gt; não precisa ser a lista completa, pois o produtor consegue obter mais informações após se conectar, mas é recomendável que seja pelo menos dois;&lt;/li&gt;&lt;li style=&quot;text-align: justify;&quot;&gt;&lt;b&gt;Key serializer:&lt;/b&gt; as chaves das mensagens são serializadas, portanto você precisa especificar um serializador. Você pode criar o seu próprio (se necessário), bastando para isto implementar org.apache.kafka.common.serialization.Serializer. Há vários serializadores comuns, como por exemplo, StringSerializer (usado aqui);&lt;/li&gt;&lt;li style=&quot;text-align: justify;&quot;&gt;&lt;b&gt;Value serializer:&lt;/b&gt; a ideia é a mesma do anterior, mas agora com relação ao valor.&lt;/li&gt;&lt;/ul&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 9,8pt;&quot;&gt;&lt;pre&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span&gt;Properties kafkaProperties = &lt;span style=&quot;color: #cc7832;&quot;&gt;new &lt;/span&gt;Properties()&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;kafkaProperties.put(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;bootstrap.servers&quot;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;localhost:9092&quot;&lt;/span&gt;)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;kafkaProperties.put(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;key.serializer&quot;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;org.apache.kafka.common.serialization.StringSerializer&quot;&lt;/span&gt;)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;kafkaProperties.put(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;value.serializer&quot;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;org.apache.kafka.common.serialization.StringSerializer&quot;&lt;/span&gt;)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;KafkaProducer producer = &lt;span style=&quot;color: #cc7832;&quot;&gt;new &lt;/span&gt;KafkaProducer&amp;lt;String&lt;span style=&quot;color: #cc7832;&quot;&gt;, &lt;/span&gt;String&amp;gt;(kafkaProperties)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Feito isso, você pode criar uma mensagem / record (ProducerRecord).&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 9,8pt;&quot;&gt;&lt;pre&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span&gt;ProducerRecord &amp;lt;String&lt;span style=&quot;color: #cc7832;&quot;&gt;, &lt;/span&gt;String&amp;gt; record = &lt;span style=&quot;color: #cc7832;&quot;&gt;new &lt;/span&gt;ProducerRecord&amp;lt;&amp;gt;(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;topic-xpto&quot;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;value&quot;&lt;/span&gt;)&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;span&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Em seguida, faz o envio deste record, através do método send.&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Um Future será retornado e por meio dele você pode obter os metadados (RecordMetadata).&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 9,8pt;&quot;&gt;&lt;pre&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span&gt;Future &amp;lt;RecordMetadata&amp;gt; future = producer.send(record)&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;RecordMetadata metadata = future.get()&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;System.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;out&lt;/span&gt;.println(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;Sucesso ---&amp;gt;&amp;gt;&amp;gt; &quot; &lt;/span&gt;+ metadata.offset())&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;A biblioteca utilizada aqui foi:&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 9,8pt; text-align: left;&quot;&gt;&lt;pre&gt;&lt;span style=&quot;color: #e8bf6a;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span&gt;&lt;span style=&quot;color: #e8bf6a;&quot;&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #e8bf6a;&quot;&gt;    &amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.kafka&lt;span style=&quot;color: #e8bf6a;&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #e8bf6a;&quot;&gt;    &amp;lt;artifactId&amp;gt;&lt;/span&gt;kafka-clients&lt;span style=&quot;color: #e8bf6a;&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #e8bf6a;&quot;&gt;    &amp;lt;version&amp;gt;&lt;/span&gt;3.4.1&lt;span style=&quot;color: #e8bf6a;&quot;&gt;&amp;lt;/version&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #e8bf6a;&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style=&quot;color: #e8bf6a;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/8175442610057430015/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2023/06/kafka-produtor-sincrono.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/8175442610057430015'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/8175442610057430015'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2023/06/kafka-produtor-sincrono.html' title='Kafka: produtor síncrono'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-5461251375238375184</id><published>2023-06-16T20:39:00.007-07:00</published><updated>2023-06-17T17:19:02.309-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="Kafka"/><category scheme="http://www.blogger.com/atom/ns#" term="Messaging"/><title type='text'>Kafka: produtor assíncrono (callback)</title><content type='html'>&lt;p style=&quot;text-align: justify;&quot;&gt;Naturalmente as mensagens são produzidas no Kafka de modo assíncrono, pois ao fazer o envio é retornado um Future.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Aqui será mostrado como fazer o envio usando um callback.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Para isso você precisa implementar a interface&amp;nbsp;org.apache.kafka.clients.producer.Callback. Ela pode ser encontrada &lt;b&gt;kafka-clients&lt;/b&gt;:&lt;/p&gt;&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 9,8pt;&quot;&gt;&lt;pre&gt;&lt;span style=&quot;color: #e8bf6a;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style=&quot;color: #e8bf6a;&quot;&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #e8bf6a;&quot;&gt;    &amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.kafka&lt;span style=&quot;color: #e8bf6a;&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #e8bf6a;&quot;&gt;    &amp;lt;artifactId&amp;gt;&lt;/span&gt;kafka-clients&lt;span style=&quot;color: #e8bf6a;&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #e8bf6a;&quot;&gt;    &amp;lt;version&amp;gt;&lt;/span&gt;3.4.1&lt;span style=&quot;color: #e8bf6a;&quot;&gt;&amp;lt;/version&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #e8bf6a;&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style=&quot;color: #e8bf6a;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Basta implementar o método&amp;nbsp;&lt;b&gt;onCompletion&lt;/b&gt;:&lt;/p&gt;&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 9,8pt;&quot;&gt;&lt;pre&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;public class &lt;/span&gt;MyFirstCallback &lt;span style=&quot;color: #cc7832;&quot;&gt;implements &lt;/span&gt;Callback {&lt;br /&gt;&lt;br /&gt;    &lt;span style=&quot;color: #bbb529;&quot;&gt;@Override&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #bbb529;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;public void &lt;/span&gt;&lt;span style=&quot;color: #ffc66d;&quot;&gt;onCompletion&lt;/span&gt;(RecordMetadata recordMetadata&lt;span style=&quot;color: #cc7832;&quot;&gt;, &lt;/span&gt;Exception e) {&lt;br /&gt;        &lt;span style=&quot;color: #cc7832;&quot;&gt;if &lt;/span&gt;(e == &lt;span style=&quot;color: #cc7832;&quot;&gt;null&lt;/span&gt;) {&lt;br /&gt;            System.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;out&lt;/span&gt;.println(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;Sucesso: &quot; &lt;/span&gt;+ recordMetadata.offset())&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;        &lt;/span&gt;} &lt;span style=&quot;color: #cc7832;&quot;&gt;else &lt;/span&gt;{&lt;br /&gt;            System.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;err&lt;/span&gt;.println(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;A casa caiu: &quot; &lt;/span&gt;+ e.getMessage())&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;        &lt;/span&gt;}&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;pre&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Feito isso, basta instanciar este callback e passar como segundo parâmetro do método send do seu producer (um org.apache.kafka.clients.producer.KafkaProducer):&lt;/p&gt;&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 9,8pt;&quot;&gt;&lt;pre&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;producer.send(record&lt;span style=&quot;color: #cc7832;&quot;&gt;, new &lt;/span&gt;MyFirstCallback())&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Também é possível fazer com Lambda:&lt;/p&gt;&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6; font-family: &amp;quot;JetBrains Mono&amp;quot;, monospace; font-size: 9,8pt;&quot;&gt;&lt;pre&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre&gt;producer.send(record&lt;span style=&quot;color: #cc7832;&quot;&gt;, &lt;/span&gt;(r&lt;span style=&quot;color: #cc7832;&quot;&gt;, &lt;/span&gt;e) -&amp;gt; {&lt;br /&gt;    &lt;span style=&quot;color: #cc7832;&quot;&gt;if &lt;/span&gt;(e == &lt;span style=&quot;color: #cc7832;&quot;&gt;null&lt;/span&gt;) {&lt;br /&gt;        System.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;out&lt;/span&gt;.println(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;Sucesso:: &quot; &lt;/span&gt;+ r.offset())&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;    &lt;/span&gt;} &lt;span style=&quot;color: #cc7832;&quot;&gt;else &lt;/span&gt;{&lt;br /&gt;        System.&lt;span style=&quot;color: #9876aa; font-style: italic;&quot;&gt;err&lt;/span&gt;.println(&lt;span style=&quot;color: #6a8759;&quot;&gt;&quot;A casa caiu: &quot; &lt;/span&gt;+ e.getMessage())&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;    &lt;/span&gt;}&lt;br /&gt;})&lt;span style=&quot;color: #cc7832;&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;b&gt;Obs.:&lt;/b&gt; se o Kafka retornar algum erro, o parâmetro do tipo Exception no onCompletion será diferente de nulo.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/5461251375238375184/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2023/06/kafka-produtor-assincrono-callback.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/5461251375238375184'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/5461251375238375184'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2023/06/kafka-produtor-assincrono-callback.html' title='Kafka: produtor assíncrono (callback)'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-726095402216771805</id><published>2023-06-10T19:41:00.003-07:00</published><updated>2023-06-10T19:48:37.134-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Kafka"/><category scheme="http://www.blogger.com/atom/ns#" term="Messaging"/><title type='text'>Kafka: número de mensagens num tópico</title><content type='html'>&lt;p style=&quot;text-align: justify;&quot;&gt;Para saber a quantidade de mensagens que um tópico do Kafka já recebeu, utilize o comando:&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list localhost:9092 --topic basic-teste --partitions 0&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Segue uma breve explicação dele:&amp;nbsp;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;/p&gt;&lt;ul&gt;&lt;li style=&quot;text-align: left;&quot;&gt;&lt;b&gt;kafka-run-class.sh&lt;/b&gt;: está localizado na pasta bin do seu Kafka;&lt;/li&gt;&lt;li style=&quot;text-align: left;&quot;&gt;&lt;b&gt;GetOffsetShell&lt;/b&gt;: é um utilitário relacionado a offSets;&lt;/li&gt;&lt;li style=&quot;text-align: left;&quot;&gt;&lt;b&gt;broker-list&lt;/b&gt;: é a lista de brokers literalmente;&lt;/li&gt;&lt;li style=&quot;text-align: left;&quot;&gt;&lt;b&gt;topic&lt;/b&gt;: o nome do tópico;&lt;/li&gt;&lt;li style=&quot;text-align: left;&quot;&gt;&lt;b&gt;partitions&lt;/b&gt;: lista com os ids da partições que você deseja.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Isto irá retornar algo assim:&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;basic-teste:0:18&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;A saída acima tem três partes (separadas por dois pontos). A primeira parte é o tópico, a segunda é o id da partição e a terceira o offset. É justamente ele que nos diz quantas mensagens este tópico já recebeu (incluindo as mensagens que já foram deletadas por conta da configuração de retenção).&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Podemos simplificar ainda mais, acrescentando o comando &lt;b&gt;cut&lt;/b&gt; do Linux:&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list localhost:9092 --topic basic-teste --partitions 0 | cut -d &#39;:&#39; -f 3&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;O cut permite manipular linhas. Acima estamos dizendo que o delimitador é : (dois pontos, com a opção -d) e que queremos apenas a última parte, a terceira parte, ou field (-f). Rodar este comando retorna: 18.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Observações:&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;O offset é um inteiro que é incrementado a cada mensagem produzida.&lt;/li&gt;&lt;li&gt;Para saber a quantidade corrente (atual, ainda não deletada) de mensagens num tópico, é preciso usar o ksqlDB, mas isso eu ainda preciso estudar melhor para escrever aqui.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/726095402216771805/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2023/06/kafka-numero-de-mensagens-num-topico.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/726095402216771805'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/726095402216771805'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2023/06/kafka-numero-de-mensagens-num-topico.html' title='Kafka: número de mensagens num tópico'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-701033919474647328</id><published>2023-06-08T18:41:00.000-07:00</published><updated>2023-06-08T18:41:58.877-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Desempenho"/><category scheme="http://www.blogger.com/atom/ns#" term="Kafka"/><category scheme="http://www.blogger.com/atom/ns#" term="Messaging"/><title type='text'>Tuning Kafka: armazenamento dos logs segments (reduzir escritas)</title><content type='html'>&lt;p style=&quot;text-align: justify;&quot;&gt;É recomendável que o ponto de montagem que armazena os log segments (mensagens) do Kafka, seja configurado com a opção &lt;b&gt;noatime&lt;/b&gt;. Isto está relacionado com os atributos de timestamp do Linux. Resumidamente, o Linux tem um metadado relacionado a última vez em que um arquivo foi acessado (&lt;b&gt;atime&lt;/b&gt;). Isso acaba gerando muitas atualizações, ou seja, muitas escritas no disco, pois as mensagens estão sendo lidas a todo momento.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Portanto, para diminuir o número de escritas, deve-se utilizar o &lt;b&gt;noatime&lt;/b&gt;. Para entender melhor isso, e também como fazer na prática, veja este post &lt;a href=&quot;http://thiagocolen.blogspot.com/2023/06/linux-performance-e-file-timestamps.html&quot; target=&quot;_blank&quot;&gt;aqui&lt;/a&gt;.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Podemos usar o &lt;b&gt;noatime&lt;/b&gt; com segurança, pois o Kafka não utiliza essa informação.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/701033919474647328/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2023/06/tuning-kafka-armazenamento-dos-logs.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/701033919474647328'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/701033919474647328'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2023/06/tuning-kafka-armazenamento-dos-logs.html' title='Tuning Kafka: armazenamento dos logs segments (reduzir escritas)'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-7681227864210313467</id><published>2023-06-08T16:26:00.004-07:00</published><updated>2023-06-08T18:20:51.742-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Desempenho"/><category scheme="http://www.blogger.com/atom/ns#" term="Linux"/><title type='text'>Linux: performance e file timestamps</title><content type='html'>&lt;p style=&quot;text-align: justify;&quot;&gt;Todos os arquivos no Linux possuem alguns timestamps. Eis alguns deles:&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li style=&quot;text-align: justify;&quot;&gt;&lt;b&gt;atime&lt;/b&gt;: é atualizado sempre que um arquivo é acessado (accessed);&lt;/li&gt;&lt;li style=&quot;text-align: justify;&quot;&gt;&lt;b&gt;mtime&lt;/b&gt;: é atualizado sempre que o conteúdo de um arquivo é modificado (modified);&lt;/li&gt;&lt;li style=&quot;text-align: justify;&quot;&gt;&lt;b&gt;ctime&lt;/b&gt;: é atualizado&amp;nbsp;sempre que o conteúdo ou os atributos (alterar o nome, mudar permissões...) de um arquivo são alterados (changed).&lt;/li&gt;&lt;/ul&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Por conta de constantes atualizações -- pense, arquivos são acessados a todo instante -- deixar o atime habilitado causa uma queda de performance, pois ocorrem muitas escritas/atualizações no atime. Portanto, se você ou sua aplicação / servidor, não precisa do atime, desligue-o! Mesmo rodando com SSD.&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Para desligar o &lt;b&gt;atime&lt;/b&gt;, você precisa editar o &lt;b&gt;/etc/fstab&lt;/b&gt; e acrescentar &lt;b&gt;noatime&lt;/b&gt; na linha do ponto de montagem, como abaixo:&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;UUID=7b32eca9-e795-4506-8ece-a789a9f53a06 /&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;ext4&amp;nbsp; &amp;nbsp; errors=remount-ro,&lt;b&gt;noatime&lt;/b&gt; 0&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Depois de reiniciar a máquina, utilize este comando para ter certeza que o &lt;b&gt;noatime&lt;/b&gt; foi habilitado:&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;cat /proc/mounts | grep &quot; / &quot;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;text-align: justify;&quot;&gt;A saída será:&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;/dev/nvme0n1p4 / ext4 rw,&lt;b&gt;noatime&lt;/b&gt;,errors=remount-ro 0 0&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;b&gt;Obs.:&lt;/b&gt; existe um meio termo para não ficar sem o &lt;b&gt;atime&lt;/b&gt;: é o &lt;b&gt;relatime&lt;/b&gt;. Com essa opção, o &lt;b&gt;atime&lt;/b&gt; só é atualizado se ele for anterior ao &lt;b&gt;mtime&lt;/b&gt; ou &lt;b&gt;ctime&lt;/b&gt; atual (corrente), ou seja, o acesso é atualizado somente quando o arquivo sofre alguma modificação. Esse comportamento já é melhor que o original (quando o acesso é sempre atualizado) e oferece também compatibilidade. O &lt;b&gt;relatime&lt;/b&gt; está disponível como default desde o Kernel 2.6.30. Mas se você quiser ser &quot;radical&quot; e&amp;nbsp; precisar do extremo da performance, use &lt;b&gt;noatime &lt;/b&gt;(neste caso precisa ter certeza de que seu ambiente não precisa do atime).&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;Para ter certeza que o &lt;b&gt;relatime&lt;/b&gt; tá habilitado, utilize o comando:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;cat /proc/mounts | grep &quot; / &quot;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;No meu caso a saída foi (olha o relatime aí):&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;/dev/nvme0n1p4 / ext4 rw,&lt;b&gt;relatime&lt;/b&gt;,errors=remount-ro 0 0&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/7681227864210313467/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2023/06/linux-performance-e-file-timestamps.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/7681227864210313467'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/7681227864210313467'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2023/06/linux-performance-e-file-timestamps.html' title='Linux: performance e file timestamps'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-2515472512145083180</id><published>2023-05-29T19:41:00.002-07:00</published><updated>2023-05-29T19:41:17.450-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Kafka"/><category scheme="http://www.blogger.com/atom/ns#" term="Messaging"/><title type='text'>Kafka: retenção de mensagens por tempo</title><content type='html'>&lt;p style=&quot;text-align: justify;&quot;&gt;Por default o Kafka retém mensagens por 168 horas, ou seja, 7 dias. Isto é definido através da propriedade&amp;nbsp;&lt;b&gt;log.retention.hours&lt;/b&gt; no arquivo &lt;b&gt;server.properties&lt;/b&gt;&amp;nbsp;do diretório &lt;b&gt;config&lt;/b&gt; da instalação do Kafka.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Há outras duas opções: milissegundos (&lt;b&gt;log.retention.ms&lt;/b&gt;) e minutos (&lt;b&gt;log.retention.minutes&lt;/b&gt;). Recomenda-se a utilização de milissegundos, pois é a menor unidade e a menor sempre tem precedência sobre as outras (caso mais de uma seja especificada).&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Testado no Kafka 3.4.0.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/2515472512145083180/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2023/05/kafka-retencao-de-mensagens-por-tempo.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/2515472512145083180'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/2515472512145083180'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2023/05/kafka-retencao-de-mensagens-por-tempo.html' title='Kafka: retenção de mensagens por tempo'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-3417108153444569105</id><published>2023-05-22T18:19:00.004-07:00</published><updated>2023-05-22T18:47:04.089-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Desempenho"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="Kafka"/><title type='text'>Tuning Kafka: Qual é o melhor Garbage Collector (GC) para o Kafka?</title><content type='html'>&lt;p style=&quot;text-align: justify;&quot;&gt;Se você usa uma JVM 1.8 ou superior, o melhor é usar o &lt;b&gt;G1GC&lt;/b&gt; (Garbage First Garbage Collector).&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Mas por que? Resumidamente, o G1GC tem alta performance, suporta grandes volumes de memória e se ajusta automaticamente ao processamento que precisa fazer, ou seja, ele se adapta à circunstância (dinamismo). Suas pausas são consistentes, pois ele segmenta a memória em zonas menores, o que faz com que não percorra (varra / colete) toda a memória em cada pausa, logo executa em menor tempo. Ele também foca nas zonas onde há mais objetos que podem ser descartados (sem referência, que não estão sendo usados), logo libera espaço considerável.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Há dois parâmetros / opções úteis neste contexto:&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;/p&gt;&lt;ul&gt;&lt;li style=&quot;text-align: justify;&quot;&gt;&lt;b&gt;MaxGCPauseMillis&lt;/b&gt;: indica o tempo &lt;b&gt;aproximado&lt;/b&gt; em que o G1GC vai rodar (pode exceder). Seu valor default é 200 milisegundos. O algoritmo faz uma previsão de quantas zonas coletar / processar para atingir o tempo especificado aqui.&lt;/li&gt;&lt;li&gt;&lt;b&gt;InitiatingHeapOccupancyPercent&lt;/b&gt;: indica qual o percentual da memória (new e old juntas) deverá estar em uso para que o G1GC inicie a execução. O default aqui é 45.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Em termos práticos, você faz essa configuração através desta variável:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: courier; font-size: x-small;&quot;&gt;export &lt;b&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;KAFKA_JVM_PERFORMANCE_OPTS&lt;/span&gt;&lt;/b&gt;=&quot;-server -Xmx4g -Xms4g -&lt;span style=&quot;color: red;&quot;&gt;&lt;b&gt;XX:UseG1GC&lt;/b&gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;&lt;b&gt;-XX:MaxGCPauseMillis=50&lt;/b&gt;&lt;/span&gt; &lt;span style=&quot;color: red;&quot;&gt;&lt;b&gt;-XX:InitiatingHeapOccupancyPercent=40&lt;/b&gt;&lt;/span&gt; ...&quot;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/3417108153444569105/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2023/05/tuning-kafka-qual-e-o-melhor-garbage.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/3417108153444569105'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/3417108153444569105'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2023/05/tuning-kafka-qual-e-o-melhor-garbage.html' title='Tuning Kafka: Qual é o melhor Garbage Collector (GC) para o Kafka?'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-7425620244731432101</id><published>2023-05-06T18:11:00.006-07:00</published><updated>2023-05-06T18:53:24.638-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Kafka"/><category scheme="http://www.blogger.com/atom/ns#" term="Messaging"/><category scheme="http://www.blogger.com/atom/ns#" term="Stream"/><title type='text'>Kafka (standalone): subindo e testando</title><content type='html'>&lt;p style=&quot;text-align: justify;&quot;&gt;No post &lt;a href=&quot;http://thiagocolen.blogspot.com/2023/05/kafka-standalone-subindo-e-testando-o.html&quot; target=&quot;_blank&quot;&gt;anterior&lt;/a&gt;, mostrei como configurar minimamente o ZooKeeper como pré-requisito para rodar o Kafka standalone.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Agora o foco é o Kafka. A versão utilizada aqui é a 3.4.0.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Com as configurações padrão, a primeira coisa a fazer é o comando abaixo (para dar o start):&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;kafka-server-start.sh -daemon /SEU_DIRETORIO&lt;/span&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;/kafka_2.13-3.4.0/config/server.properties&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Agora para testar, faremos 4 coisas (tudo pela linha de comando):&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Criar um tópico;&lt;/li&gt;&lt;li&gt;Pedir detalhes deste tópico;&lt;/li&gt;&lt;li&gt;Produzir mensagens;&lt;/li&gt;&lt;li&gt;Consumir mensagens.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Criação de um tópico chamado teste-simples:&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;kafka-topics.sh --bootstrap-server localhost:9092 --create --replication-factor 1 --partitions 1 --topic teste-simples&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Para ver detalhes deste tópico:&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;kafka-topics.sh --bootstrap-server localhost:9092 --describe --topic teste-simples&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Para produzir mensagens:&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;kafka-console-producer.sh --bootstrap-server localhost:9092 --topic teste-simples&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Para consumir mensagens:&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic teste-simples --from-beginning&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/7425620244731432101/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2023/05/kafka-standalone-subindo-e-testando.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/7425620244731432101'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/7425620244731432101'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2023/05/kafka-standalone-subindo-e-testando.html' title='Kafka (standalone): subindo e testando'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-1093254863221387473</id><published>2023-05-06T15:34:00.011-07:00</published><updated>2023-05-06T16:56:48.045-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Kafka"/><category scheme="http://www.blogger.com/atom/ns#" term="Messaging"/><category scheme="http://www.blogger.com/atom/ns#" term="Stream"/><category scheme="http://www.blogger.com/atom/ns#" term="ZooKeeper"/><title type='text'>Kafka (standalone): subindo e testando o ZooKeeper</title><content type='html'>&lt;p style=&quot;text-align: justify;&quot;&gt;O ZooKeeper é um pré-requisito para rodar o Kafka, pois ele armazena os metadados do(s) broker(s) (cluster).&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Neste exemplo, estou utilizando o ZooKeeper 3.8.1.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;A primeira coisa a se fazer é a configuração básica (standalone). Para isto, na pasta &lt;b&gt;conf&lt;/b&gt; do ZooKeeper, crie um arquivo de configuração chamado &lt;b&gt;zoo.cfg&lt;/b&gt; e coloque as linhas abaixo nele:&lt;/p&gt;&lt;div style=&quot;background-color: #1e1e1e; color: #d4d4d4; font-family: &amp;quot;Droid Sans Mono&amp;quot;, &amp;quot;monospace&amp;quot;, monospace; font-size: 14px; line-height: 19px; white-space: pre;&quot;&gt;&lt;div&gt;&lt;span style=&quot;color: #6a9955;&quot;&gt;# The number of milliseconds of each tick&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;tickTime&lt;/span&gt;=2000&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #6a9955;&quot;&gt;# The directory where the snapshot is stored&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;dataDir&lt;/span&gt;=/work/tools/kafka/zookeeper-data&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #6a9955;&quot;&gt;# The port at which the clients will connect&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;clientPort&lt;/span&gt;=2181&lt;/div&gt;&lt;/div&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Acima, as duas coisas mais importantes neste momento são: o diretório onde os dados serão armazenados e a porta para os clientes.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Feito isso, é hora de iniciar o ZooKeeper. Utilize este comando (localizado na basta bin do seu ZooKeeper):&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier;&quot;&gt;zkServer.sh start&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;As linhas abaixo serão exibidas:&lt;/p&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;ZooKeeper JMX enabled by default&lt;br /&gt;Using config: /work/tools/kafka/apache-zookeeper-3.8.1-bin/bin/../conf/zoo.cfg&lt;br /&gt;Starting zookeeper ... STARTED&lt;/span&gt;&lt;/div&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Para testar e ter certeza que o ZooKeeper está no ar, faça o telnet na porta configurada acima:&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier;&quot;&gt;telnet localhost 2181&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Quando conectar, digite: srvr. Serão exibidas algumas informações do servidor ZooKeeper:&lt;/p&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;color: #0b5394; font-family: courier; font-size: x-small;&quot;&gt;Zookeeper version: 3.8.1-74db005175a4ec545697012f9069cb9dcc8cdda7, built on 2023-01-25 16:31 UTC&lt;br /&gt;Latency min/avg/max: 0/0.0/0&lt;br /&gt;Received: 1&lt;br /&gt;Sent: 0&lt;br /&gt;Connections: 1&lt;br /&gt;Outstanding: 0&lt;br /&gt;Zxid: 0x8d&lt;br /&gt;Mode: standalone&lt;br /&gt;Node count: 134&lt;/span&gt;&lt;/div&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Pronto, ZooKeeper no ar!&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/1093254863221387473/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2023/05/kafka-standalone-subindo-e-testando-o.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/1093254863221387473'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/1093254863221387473'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2023/05/kafka-standalone-subindo-e-testando-o.html' title='Kafka (standalone): subindo e testando o ZooKeeper'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-8969166107881963627</id><published>2023-03-08T19:00:00.000-08:00</published><updated>2023-03-08T19:00:54.435-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JSON"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server"/><title type='text'>SQL Server: ler objeto de um JSON (JSON_QUERY)</title><content type='html'>&lt;p style=&quot;text-align: justify;&quot;&gt;Este post pode ser considerado uma continuação deste &lt;a href=&quot;http://thiagocolen.blogspot.com/2022/12/sql-server-ler-um-atributo-especifico.html&quot; target=&quot;_blank&quot;&gt;outro&lt;/a&gt;. Nele eu mostrei como ler um atributo simples (scalar value). Agora é um pouco diferente, o atributo que será lido contém um objeto, outro JSON.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Basicamente, ao invés de usar JSON_VALUE, basta usar JSON_QUERY:&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;select json_query(campo, &#39;$.education&#39;) from tabela&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;O valor retornado será: {&quot;name&quot;:&quot;xpto&quot;, &quot;year&quot;:&quot;2005&quot;}.&lt;/p&gt;&lt;p style=&quot;text-align: justify;&quot;&gt;Testado no SQL Server 2017.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/8969166107881963627/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2023/03/sql-server-ler-objeto-de-um-json.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/8969166107881963627'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/8969166107881963627'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2023/03/sql-server-ler-objeto-de-um-json.html' title='SQL Server: ler objeto de um JSON (JSON_QUERY)'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4552765333886608132.post-8957424444778134014</id><published>2023-03-02T02:39:00.001-08:00</published><updated>2023-03-02T02:39:40.550-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JSON"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server"/><title type='text'>SQL Server: query que gera JSON</title><content type='html'>&lt;p&gt;Para fazer sua query gerar um JSON, utilize o &lt;b&gt;for json path&lt;/b&gt;.&lt;/p&gt;&lt;blockquote style=&quot;border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;&quot;&gt;&lt;p&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;select top 1 id as id, name as nome&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;from tabela&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;for json path&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;A saída conterá um JSON assim: [{&quot;id&quot;:1, &quot;nome&quot;:&quot;Fiodor&quot;}]&lt;/p&gt;&lt;p&gt;Testado no SQL Server 2017.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://thiagocolen.blogspot.com/feeds/8957424444778134014/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://thiagocolen.blogspot.com/2023/03/sql-server-query-que-gera-json.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/8957424444778134014'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4552765333886608132/posts/default/8957424444778134014'/><link rel='alternate' type='text/html' href='http://thiagocolen.blogspot.com/2023/03/sql-server-query-que-gera-json.html' title='SQL Server: query que gera JSON'/><author><name>Thiago Colen</name><uri>http://www.blogger.com/profile/14430372588698989741</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>