<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Kafka on 追风笔记</title><link>https://4f0a9a3b.wangpeng.pages.dev/tech/kafka/</link><description>Recent content in Kafka on 追风笔记</description><generator>Hugo</generator><language>zh</language><lastBuildDate>Tue, 25 Aug 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://4f0a9a3b.wangpeng.pages.dev/tech/kafka/index.xml" rel="self" type="application/rss+xml"/><item><title>Kafka 存储与消费模型</title><link>https://4f0a9a3b.wangpeng.pages.dev/tech/kafka/storage-consumer/</link><pubDate>Tue, 25 Aug 2026 00:00:00 +0000</pubDate><guid>https://4f0a9a3b.wangpeng.pages.dev/tech/kafka/storage-consumer/</guid><description>&lt;p&gt;Kafka 的高性能依赖于「分区日志 + 顺序写 + 批量拉取」的设计。理解存储与消费模型，才能合理配置并行度与避免重复消费。&lt;/p&gt;&#10;&lt;h2 id="topic-与-partition"&gt;Topic 与 Partition&#10;&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;topic&lt;/strong&gt; 是逻辑主题，&lt;strong&gt;partition&lt;/strong&gt; 是物理并行单位，消息只追加写入分区末尾。&lt;/li&gt;&#10;&lt;li&gt;每个分区是一个有序、不可变的日志，由多个 segment 文件组成，并维护 offset（分区内唯一递增）。&lt;/li&gt;&#10;&lt;li&gt;分区数决定了消费的并行上限：一个分区同一时刻只被 group 内一个消费者消费。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="offset-与消费位移"&gt;Offset 与消费位移&#10;&lt;/h2&gt;&#10;&lt;p&gt;消费者处理完消息后提交的位移称为 &lt;strong&gt;offset&lt;/strong&gt;，Kafka 将其保存在内部 topic &lt;code&gt;__consumer_offsets&lt;/code&gt; 中：&lt;/p&gt;&#10;&lt;div class="td-code td-code--untitled" id="td-code-de365f5c-fence-0" data-td-code data-td-code-auto-id&#10; data-td-language="text" data-td-line-count="4"&gt;&#10; &lt;div class="td-code__viewport" id="td-code-de365f5c-fence-0-viewport" data-td-code-viewport&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Producer -&amp;gt; [partition-0: 0,1,2,3 ...]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ^&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | committed offset (group A)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Consumer group A 从 offset=4 继续拉取&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;位移提交方式影响可靠性：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;自动提交&lt;/strong&gt;：间隔提交，可能丢失（提交后未处理崩溃）或重复（处理中崩溃未提交）。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;手动提交&lt;/strong&gt;：处理成功后再提交，配合幂等可实现至少一次/精确一次。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="consumer-group-与-rebalance"&gt;Consumer Group 与 Rebalance&#10;&lt;/h2&gt;&#10;&lt;p&gt;同一 group 内的消费者共同消费 topic 的全部分区，分区在成员间均衡分配。当成员加入/退出时触发 &lt;strong&gt;rebalance&lt;/strong&gt;，重新分配分区。频繁 rebalance 会暂停消费，应控制 &lt;code&gt;session.timeout&lt;/code&gt; 与 &lt;code&gt;heartbeat.interval&lt;/code&gt; 并避免消费耗时过长。&lt;/p&gt;</description></item><item><title>Kafka 可靠性与精确一次</title><link>https://4f0a9a3b.wangpeng.pages.dev/tech/kafka/reliability/</link><pubDate>Tue, 25 Aug 2026 00:00:00 +0000</pubDate><guid>https://4f0a9a3b.wangpeng.pages.dev/tech/kafka/reliability/</guid><description>&lt;p&gt;Kafka 的可靠性需要在 producer、broker、consumer 三端协同配置。下面从「不丢、不重、有序」三个目标展开。&lt;/p&gt;&#10;&lt;h2 id="producer-端的可靠性"&gt;Producer 端的可靠性&#10;&lt;/h2&gt;&#10;&lt;p&gt;通过 &lt;code&gt;acks&lt;/code&gt; 控制写入持久化级别：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;acks=0&lt;/code&gt;：发完即认为成功，可能丢消息，吞吐最高。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;acks=1&lt;/code&gt;：leader 写入即成功，leader 宕机可能丢。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;acks=all&lt;/code&gt;：ISR 全部同步才成功，最安全，配合 &lt;code&gt;min.insync.replicas&lt;/code&gt; 防单点。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;开启重试（&lt;code&gt;retries&lt;/code&gt;）可应对瞬时失败，但会带来&lt;strong&gt;重复&lt;/strong&gt;：网络抖动导致 producer 未收到 ack 而重试，同一条消息被写两次。&lt;/p&gt;&#10;&lt;h2 id="幂等-producer-与事务"&gt;幂等 Producer 与事务&#10;&lt;/h2&gt;&#10;&lt;p&gt;Kafka 提供 &lt;strong&gt;幂等 producer&lt;/strong&gt;（&lt;code&gt;enable.idempotence=true&lt;/code&gt;），broker 用 &lt;code&gt;producerId + 序列号&lt;/code&gt; 去重，保证单分区内不重不漏。需要跨分区、跨系统的原子写入时，使用&lt;strong&gt;事务&lt;/strong&gt;（&lt;code&gt;transactional.id&lt;/code&gt;）将多次 produce 与 offset 提交纳入一个事务：&lt;/p&gt;&#10;&lt;div class="td-code td-code--untitled" id="td-code-5a2edc9c-fence-0" data-td-code data-td-code-auto-id&#10; data-td-language="java" data-td-line-count="5"&gt;&#10; &lt;div class="td-code__viewport" id="td-code-5a2edc9c-fence-0-viewport" data-td-code-viewport&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initTransactions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;beginTransaction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;commitTransaction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;要么都成功&lt;/span&gt;&lt;span class="err"&gt;，&lt;/span&gt;&lt;span class="n"&gt;要么都不可见&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;h2 id="消费端去重与幂等"&gt;消费端去重与幂等&#10;&lt;/h2&gt;&#10;&lt;p&gt;即使 producer 幂等，consumer 在 rebalance 或位移提交时机不当时仍可能重复消费。消费端应保证&lt;strong&gt;业务幂等&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;用唯一键（订单号等）做去重表/唯一索引。&lt;/li&gt;&#10;&lt;li&gt;将「处理 + 提交位移」放在同一事务（如消费写 DB 同时记录 offset）。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="分区顺序性"&gt;分区顺序性&#10;&lt;/h2&gt;&#10;&lt;p&gt;Kafka 只保证&lt;strong&gt;单分区内有序&lt;/strong&gt;。需要全局顺序只能单分区（牺牲并行）；需要业务顺序则按 key（如用户 id）分区，使同一 key 落到同一分区，从而在该 key 维度保持顺序。精确一次（EOS）正是幂等 + 事务 + 消费幂等三者叠加的结果。&lt;/p&gt;</description></item></channel></rss>