Kafka:日志模型、可靠性、消费语义与积压治理¶
目标:能够从一条消息的生产、落盘、复制、消费、提交 offset 到故障恢复完整推演 Kafka;能够解释顺序性、消息丢失、重复消费、消费组、Rebalance、ISR、积压和 Exactly-Once 的边界;能够根据指标判断瓶颈位于 Producer、Broker、Consumer 还是下游系统。
1. Kafka 解决的核心问题¶
一个服务直接调用另一个服务时,双方在时间和容量上强耦合。订单服务每产生一个事件就同步调用库存、通知、风控和数据分析,只要其中一个下游变慢,调用链延迟就会逐层传回来;某个下游暂时不可用时,上游还要决定重试、超时和降级。消息队列在两者之间保存事件,使生产者完成“把消息可靠地交给中间件”之后即可结束当前调用,下游按照自己的处理速度消费。
Kafka 特别适合持续、高吞吐的事件流。它把消息组织成可追加、可保留、可重复读取的日志。消费者读取某条消息之后,消息不会因为“被取走”就立即从 Kafka 消失,Kafka 根据保留策略独立决定什么时候删除数据;消费者通过 offset 记录自己的读取位置。因此同一份日志可以被多个独立消费组按照不同进度读取,例如模型任务事件可以同时被状态服务、计费服务和离线分析服务订阅。
Kafka 的三个常见业务价值可以概括为异步解耦、流量削峰和事件分发。异步解耦降低上游对下游实时可用性的依赖;削峰把瞬时高峰转化为一段时间内持续消费;事件分发让多个逻辑订阅者共享同一份事件记录。引入 Kafka 同时增加了新的工程问题,包括消息重复、积压、顺序、分区规划、故障恢复和运维成本,因此它适合存在明确异步边界或流式数据需求的场景。
2. Topic、Partition、Record 与 Offset¶
Kafka 中的 Topic 是逻辑上的消息类别,例如 generation_job_event 可以保存生成任务状态变化。Topic 会进一步切分为多个 Partition。Partition 是 Kafka 中非常关键的物理并行单位:生产者最终把每条 Record 写到某个 Partition,Broker 保存 Partition 的日志,消费组也以 Partition 为单位分配消费任务。
每个 Partition 内部是一条有序追加日志。记录写入后会获得该 Partition 内的 offset,可以把 offset 理解成这条记录在该分区日志中的位置。offset 只在单个 Partition 内有意义,因此 partition-0 offset=100 和 partition-1 offset=100 指向两条不同的记录。
假设一个 Topic 有三个 Partition:
Kafka 可以保证单个 Partition 内记录的顺序。不同 Partition 由不同 Broker、不同网络请求和不同 Consumer 并行推进,所以 Topic 全局没有天然总顺序。如果业务要求同一 job_id 的状态严格按照 SUBMITTED -> RUNNING -> SUCCEEDED 处理,常见做法是使用 job_id 作为消息 key,使同一个 key 稳定映射到同一个 Partition,然后在该 Partition 内获得顺序保证。
Partition 数量还决定消费组的最大直接并行度。一个 Partition 在同一 Consumer Group 的同一时刻只交给一个 Consumer 成员消费,因此一个 Topic 有 12 个 Partition 时,同一个组启动 20 个 Consumer,最多只有 12 个成员能获得 Partition,其余成员处于空闲状态。增加 Consumer 能否提高吞吐,需要先看 Partition 数量和实际瓶颈。
3. Producer 从 send 到 Broker 的完整路径¶
Producer 调用 send(record) 时,消息通常不会立刻对应一次独立网络请求。客户端先对 key/value 序列化,根据 Topic 元数据和分区策略确定目标 Partition,然后把记录追加到该 Partition 对应的内存批次。后台 Sender 线程把已经达到大小条件或等待条件的批次发送给目标 Broker。
批处理是 Kafka 高吞吐的重要来源。假设每条消息只有 500 B,如果每条消息单独发送,请求头、系统调用和网络往返会占据很大比例;把几百条记录组成一个 batch 后,可以用一次请求传输更多有效数据。batch.size 控制批次容量,linger.ms 允许 Producer 在批次尚未装满时短暂等待更多记录。等待时间增加会改善批处理机会,同时会引入额外排队延迟,因此在线低延迟事件和日志吞吐型场景的参数取舍不同。
压缩通常也发生在 Record Batch 级别。多条结构相似的 JSON、Protobuf 或日志记录放在一个 batch 中,重复字段模式可以获得较好的压缩率。压缩降低网络带宽和 Broker 磁盘占用,同时消耗 Producer 和 Broker/Consumer 的 CPU。Kafka 支持 gzip、snappy、lz4、zstd 等算法,选择时要结合消息大小、吞吐和 CPU 预算。
Producer 的分区策略会直接影响顺序和负载。如果指定 key,客户端通常根据 key 的哈希选择 Partition,同一个 key 稳定进入同一个 Partition;未指定 key 时,现代 Producer 会尽量通过粘性分区等策略提高批处理效率。业务设计里最重要的是明确“什么维度需要保持局部顺序”,然后用该维度设计 key,避免把所有消息都压到一个 Partition 形成热点。
4. Kafka 为什么能做到高吞吐¶
Kafka 的存储模型与它的工作负载高度匹配。Broker 对 Partition 日志主要执行尾部追加,磁盘访问更接近顺序写;Producer 和 Consumer 都大量使用批处理,一次系统调用和一次网络请求可以承载多条记录;多个 Partition 可以分布到多个 Broker,在磁盘、CPU 和网络层形成并行度。
Kafka 充分依赖操作系统 Page Cache。Broker 写入日志时,数据通常先进入操作系统页缓存,由操作系统负责后续刷盘;Consumer 读取热点日志时,也可能直接命中页缓存,避免真实磁盘读取。Kafka 没有把所有数据再复制进一个巨大的 JVM 业务缓存,因此操作系统可以统一管理文件页缓存,Broker 堆内存压力也更可控。
Kafka 的网络发送路径在适合的场景下可以利用零拷贝能力,把文件页缓存中的数据更直接地交给网络栈,减少在内核空间和用户空间之间复制大块消息数据。常见的“Kafka 为什么快”应该落到顺序追加、批处理、压缩、Page Cache、分区并行和减少数据复制这些机制,并进一步说明每个机制解决了哪种成本。
高吞吐不代表单条消息一定拥有最低延迟。linger.ms、批量拉取、复制确认和刷盘策略都会影响延迟。Kafka 的设计目标更偏向持续吞吐、持久日志和水平扩展,所以性能讨论应同时观察吞吐、p99、批次大小、磁盘和网络利用率。
5. Broker 的日志、Segment 与索引¶
一个 Partition 的日志不会永远放在单个无限增长的文件里。Kafka 会把它切成多个 Log Segment,每个 Segment 包含一段连续 offset 范围的记录,并配套稀疏 offset 索引和时间索引。活跃 Segment 持续接受追加,旧 Segment 关闭后主要用于读取和保留策略处理。
稀疏索引不保存每条消息到文件位置的精确映射。Kafka 可以先通过索引找到接近目标 offset 的物理位置,再在日志文件中顺序扫描一小段记录。这样的索引体积较小,能够留在 Page Cache 的概率更高,也符合 Kafka 以批量顺序读写为主的访问模式。
Kafka 常见两类数据保留方式。普通 retention 根据时间或总大小删除旧 Segment,适合事件历史和日志;log compaction 会针对相同 key 保留较新的值,适合保存“某个 key 当前状态的变化日志”。两者服务的需求不同,设计 Topic 时需要明确消息是完整历史事件,还是可按 key 折叠的状态更新。
6. Leader、Follower、ISR 与提交边界¶
为了容忍 Broker 故障,Partition 可以配置多个 Replica。某一时刻其中一个 Replica 是 Leader,Producer 和 Consumer 的主要读写路径围绕 Leader 进行;其他 Replica 作为 Follower 从 Leader 拉取数据并维护自己的日志副本。当 Leader 所在 Broker 故障时,Kafka 可以从满足条件的副本中选举新的 Leader。
ISR 是 In-Sync Replicas,表示当前被认为与 Leader 保持足够同步的一组副本。它是动态集合,Follower 长时间无法跟上 Leader 时会被移出 ISR,恢复同步后可以重新进入。Kafka 通过 ISR 把“需要等待哪些副本确认”与“所有配置副本”区分开,从而避免一个长期故障或严重落后的副本永久阻塞正常写入。
理解复制时需要区分 Log End Offset 与 High Watermark。每个副本都有自己的日志末端位置,可以理解为它已经拥有的数据边界;High Watermark 表示对消费者可见的已提交边界,只有已经满足复制提交条件的数据才会推进到这个位置。Leader 可能已经接收到更靠后的记录,但在复制状态尚未达到提交条件时,这些记录不能当作稳定提交的数据暴露给普通消费者。
生产可靠性经常通过 acks 与 min.insync.replicas 联合控制。acks=0 时 Producer 不等待 Broker 确认;acks=1 时 Leader 接收成功即可返回;acks=all 会要求当前 ISR 中满足提交条件的副本完成确认。min.insync.replicas 给出了允许成功写入时 ISR 至少需要有多少副本,防止集群已经退化到只有单副本时仍继续接受“看似成功、实际冗余已经消失”的写入。
例如某 Topic 的 replication.factor=3、min.insync.replicas=2,Producer 使用 acks=all。当 Leader 加一个 Follower 仍在 ISR 时,写入仍可以成功;如果 ISR 最终只剩 Leader,一个新的写请求会失败,让上游感知当前持久性条件已经不满足。这个机制体现了可用性和数据安全之间的明确取舍。
7. Producer 重试、幂等性与顺序¶
网络系统存在一种常见的不确定状态:Broker 已经成功写入消息,但 ACK 在返回途中丢失。Producer 只看到超时,无法仅凭超时判断 Broker 到底有没有写成功。如果它直接重试,同一业务消息可能再次进入日志,这就是生产侧重复的基本来源。
Kafka 的幂等 Producer 为 Producer 分配身份,并为发送到各 Partition 的批次维护序列号。Broker 可以根据 Producer 身份和序列检测重试批次,从而抑制由 Producer 自动重试造成的重复写入。现代 Kafka Client 在没有冲突配置时默认启用幂等性,并要求与 acks=all、重试和 max.in.flight.requests.per.connection 等参数满足兼容关系。
顺序问题也和重试有关。假设同一个 Partition 先发送 batch A,再发送 batch B;A 暂时失败而 B 已成功,如果客户端允许多个未确认请求并关闭幂等保护,A 后续重试成功后可能排在 B 后面。启用兼容配置的 idempotence 后,Kafka 利用序列号机制维持同一 Producer 到同一 Partition 的记录顺序。
Producer 幂等性只覆盖 Kafka 写入链路的一部分。业务代码如果在应用层主动重复调用两次 send(),并且两次调用被视为两条新的业务消息,Broker 没有足够信息判断它们逻辑上是否重复。端到端幂等仍需要业务事件 ID、业务唯一键或状态机约束。
8. Consumer 的拉取模型与两种 offset¶
Kafka Consumer 主动向 Broker Fetch 数据。Consumer 会一次拉取一批 Record,在本地依次交给业务处理逻辑。拉取模型让消费者可以根据自己的处理能力控制节奏,也方便批量读取和批量处理。
需要区分 Consumer 当前读取位置和 committed offset。当前 position 表示这个 Consumer 实例已经拉取到哪里;committed offset 是消费组持久记录的恢复位置。Consumer 重启、发生 Rebalance 或 Partition 被交给另一个实例时,新实例会根据 committed offset 继续消费。
这个差异直接决定消息语义。假设 Consumer 拉到 offset 100,先提交 offset,再执行业务写库;如果提交成功后进程崩溃,新的 Consumer 会从更后的位置继续,offset 100 对应业务可能永远没有执行,这接近 at-most-once。反过来,先完成业务处理,再提交 offset;如果业务已经成功但提交前崩溃,重启后 offset 100 会再次投递,这形成 at-least-once。
后端系统最常使用 at-least-once 加业务幂等。原因很实际:重复通常可以通过唯一键、事件 ID、状态版本等方式消除,真正丢掉一条不可恢复的业务事件往往代价更高。消费代码应明确“业务副作用完成”与“offset 提交”之间的顺序,并设计崩溃点后的恢复行为。
9. Consumer Group 与 Partition 分配¶
多个 Consumer 使用相同 group.id 时组成 Consumer Group。同一个 Topic 的 Partition 会在组内成员之间分配,每个 Partition 同一时刻只由组内一个成员消费。这样同一个业务订阅可以通过增加 Consumer 实例提高并行处理能力,同时避免多个实例重复处理同一个 Partition 的正常流量。
不同 Consumer Group 彼此独立。例如 billing-group 和 analytics-group 都订阅 generation_job_event,一条消息会分别被两个组消费;billing-group 内部如果有多个实例,这条消息只会交给其中负责对应 Partition 的一个实例。这个模型同时提供“组间发布订阅”和“组内负载均衡”。
当 Consumer 加入、退出、失联,或者订阅 Topic 的 Partition 数量变化时,Kafka 需要重新决定 Partition 属于哪个成员,这个过程称为 Rebalance。旧的 classic 协议可能在 Rebalance 时让较多 Partition 暂停和重新分配;Kafka 4.0 起新的 Consumer Rebalance Protocol 已经 GA,通过增量式协调降低全局停顿和大规模重新分配的成本。理解 Rebalance 的核心影响即可:消费会发生所有权变化,客户端必须在撤销 Partition 前处理好未提交进度和本地状态。
Consumer 的存活检测和处理能力也需要区分。心跳与 session timeout 用于判断成员是否还活着;max.poll.interval.ms 约束业务两次 poll 之间允许的最长处理时间。某条消息处理 20 分钟,而 max.poll.interval.ms 只有 5 分钟时,即使进程还在运行,协调器也可能认为它无法按要求持续消费并触发重新分配,随后出现重复处理或积压扩大。
10. 顺序消费的真实边界¶
Kafka 的基础顺序保证是 Partition 内顺序。同一个业务实体需要顺序时,可以用实体 ID 作为 key,使相关事件进入同一个 Partition。分区数增加后,不同实体仍然可以并行消费,而单个实体的事件保持局部顺序。
Consumer 收到有序消息后,应用自己的并发模型仍可能破坏处理完成顺序。例如 Consumer 从一个 Partition 连续拿到 A、B、C,然后把三条消息扔进通用线程池,三个任务执行时间分别是 300 ms、20 ms、10 ms,最终业务副作用可能按 C、B、A 完成。Kafka 只负责把记录按顺序交给 Consumer;业务需要顺序完成时,还要让同一 Partition 或同一 key 的任务在应用内部保持串行或可控的有序执行。
全局顺序可以通过单 Partition 获得,但这会把 Topic 的直接消费并行度限制在 1。多数业务真正需要的是“同一订单、同一任务、同一用户”的局部顺序,因此 key 设计比追求整个 Topic 全局顺序更重要。
11. 消息丢失与重复:分阶段定位¶
讨论“Kafka 会不会丢消息”时,先确定问题发生在哪一段。生产阶段可能出现 Producer 未等待确认、消息发送失败后应用忽略错误、可靠性参数不足;Broker 阶段可能遇到副本数不足、ISR 退化仍允许低保证写入、磁盘或集群故障;消费阶段最典型的是 offset 提交早于业务处理完成。
重复也要分来源。Producer 因 ACK 丢失重试可能造成生产重复,幂等 Producer 可以处理这一类;Consumer 在业务成功后、offset 提交前崩溃会造成重新投递,这属于 at-least-once 的正常结果;业务上游本身也可能重复发出同一个事件。可靠系统通常给事件一个稳定 event_id 或业务唯一键,让消费端副作用具有幂等性,例如数据库唯一约束、条件更新或独立去重状态。
幂等处理需要围绕真正的业务副作用设计。假设消息要求“给账户余额加 10”,简单重复执行会产生错误;如果消息表达“把订单 123 的状态版本 8 更新为 PAID”,消费端可以使用订单 ID 和版本做条件更新,让重复事件不会产生第二次状态跃迁。说明“用 Redis SETNX 去重”时,还需要继续解释去重记录丢失、过期、Redis 与业务数据库原子性等边界。
12. Exactly-Once 能保证到哪里¶
Kafka 的幂等 Producer 解决同一个 Producer 会话内由重试引发的重复写入。Kafka Transaction 可以进一步把多个 Partition 的写入,以及“消费输入 Topic 后提交 offset + 写输出 Topic”放到一个 Kafka 事务中。配合 Consumer 的 read_committed,Kafka-to-Kafka 的流式处理可以得到很强的 Exactly-Once 语义。
当消费结果要写 MySQL、调用支付接口或请求其他外部系统时,Kafka Transaction 无法自动把这些外部副作用纳入同一个 Kafka 原子事务。此时真正的问题是“业务结果”和“消费进度”如何一致。常见方案包括让业务写入天然幂等、用唯一事件 ID 防重、把事件状态与业务数据放进同一个数据库事务,或者设计可靠的事务消息/Outbox 流程。回答 Exactly-Once 时需要明确系统边界,避免把 Kafka 内部事务能力扩大成所有外部系统都能自动 exactly once。
13. Lag、消息积压与吞吐瓶颈¶
Consumer Lag 表示消费组的进度落后于 Partition 最新数据的位置。可以把某 Partition 的 lag 粗略理解为 log end offset - committed offset。Lag 持续上升说明生产速度长期高于该消费组的有效处理速度,或者 Consumer 正在经历故障、Rebalance、下游阻塞等问题。
排查积压时先观察它的形态。所有 Partition 的 lag 均匀上升,通常意味着整个消费组能力不足或公共下游变慢;只有少量 Partition 明显积压,重点检查 key 分布、热 Partition 和负责这些 Partition 的 Consumer;lag 周期性尖峰并很快恢复,可能与定时任务、批处理、流量周期或 Rebalance 有关。
扩 Consumer 之前要看 Partition 数量。如果 24 个 Partition 已经有 24 个正常工作的 Consumer,再增加到 48 个不会直接得到 2 倍并行度。此时可以优化单条处理耗时、批量写下游、提高 Partition 数量,或者拆分热点 key。增加 Partition 会改变 key 到 Partition 的映射,并带来 Rebalance 和运维成本,因此它属于容量设计动作。
应用内部增加工作线程可以提高处理并发,但会引入顺序和 offset 管理问题。Consumer 线程如果 poll 一批消息后立即提交 offset,再把任务丢给后台线程,进程崩溃时会丢掉尚未执行的任务;等所有后台任务完成后统一提交,又可能被最慢任务拖住,并且需要处理不同 Partition 的独立进度。高并发消费设计要同时考虑吞吐、顺序和可恢复性。
14. Rebalance 为什么会导致抖动¶
Rebalance 会改变 Partition 所有权。某个 Consumer 停止、扩容一个新 Consumer、订阅关系变化,都可能触发重新分配。重新分配期间,部分 Partition 会暂时停止消费;如果业务处理时间过长导致 Consumer 频繁超过 poll 间隔,就会形成“处理慢 -> Rebalance -> 暂停消费 -> lag 更大 -> 处理更慢”的恶性循环。
排查频繁 Rebalance 时,应检查组成员变化、心跳超时、max.poll.interval.ms、单批消息处理耗时和下游接口延迟。仅仅把 timeout 调得很大可能掩盖真正的慢处理问题,并让真实故障成员更久才能被替换。参数调整应该和单批大小、处理时间分布、故障恢复目标一起考虑。
Kafka 4.x 的新 Consumer 协议减少了 classic 协议中全局同步和大范围撤销带来的停顿,但应用仍需正确处理 Partition 被撤销和重新获得时的状态。理解 Rebalance 的重点是 ownership、offset 和恢复过程,而不是背协调协议中的每个 RPC 名称。
15. KRaft 与现代 Kafka 元数据管理¶
Kafka 早期依赖 ZooKeeper 保存和协调集群元数据。Kafka 4.0 起只支持 KRaft 模式,ZooKeeper 模式已经移除。KRaft 使用 Kafka 自己的 Controller Quorum 管理元数据,Controller 之间通过 Raft 风格的元数据日志达成一致,Broker 从 Controller 获取 Topic、Partition、Replica、Leader 等集群状态。
KRaft 把“数据日志”和“集群元数据日志”分成不同职责。普通 Broker 负责业务 Topic 的消息读写;Controller Quorum 负责集群元数据和控制面决策,例如 Broker 注册、Partition Leader 变化和元数据更新。Controller 发生主节点切换时,新的 Active Controller 可以根据已经复制的元数据日志恢复控制状态。
现代 Kafka 的元数据管理应以 KRaft 为主线理解。Kafka 4.0 已进入纯 KRaft 时代;ZooKeeper 主要用于理解旧版本架构和历史迁移背景,不应再作为新集群设计的默认组成部分。
16. 可靠消费的业务设计¶
假设 generation_job_event 中有一条:
计费 Consumer 需要把 3.7 元费用记入账单。消费流程如果先更新数据库,再提交 offset,进程可能在数据库提交后崩溃,消息随后再次投递。因此数据库侧需要能识别 evt-8192 已经处理。例如建立 processed_event(event_id UNIQUE),在同一个数据库事务里插入事件处理记录并完成账单更新;重复消息再次到来时唯一约束会阻止重复副作用。
这种设计把 Kafka 的 at-least-once 和数据库事务组合成可恢复的业务语义。关键点在于“处理结果”和“去重状态”由同一个事务提交,避免发生账单已经增加、去重标记还没写成功的中间状态。如果业务操作本身可以通过状态机或版本号做到天然幂等,也可以减少单独去重表的维护成本。
对外部 HTTP 调用则更复杂。下游 API 如果支持 idempotency key,可以直接传递稳定 event_id;如果不支持,消费者很难从网络超时判断远端是否已经成功执行副作用,这时需要从业务协议层补充幂等能力或状态查询能力。
17. 监控 Kafka 应该看哪些证据¶
Producer 侧首先关注发送速率、错误率、重试率、请求延迟、batch size、compression ratio 和 buffer 等待情况。重试突然升高通常意味着 Broker、网络或超时开始出现问题;batch 很小且请求数很高,说明吞吐可能被请求开销限制;buffer 长时间耗尽说明 Producer 产生速度超过 Sender 能够发送的速度。
Broker 侧需要看请求延迟、磁盘吞吐与等待、网络吞吐、Under-Replicated Partitions、ISR shrink/expand、Offline Partitions、请求队列等指标。Under-Replicated Partition 增多说明 Follower 长期跟不上 Leader;ISR 频繁缩小和扩大说明复制链路不稳定;磁盘和网络打满会同时影响生产和消费。
Consumer 侧最重要的是按 Partition 观察 lag,同时看消费速率、poll 频率、单批处理耗时、Rebalance 次数和下游依赖延迟。只看 Topic 总 lag 可能掩盖单个热 Partition,例如 23 个 Partition 几乎没有 lag,只有 1 个 Partition 积压 500 万条,总体平均值会弱化真正的热点问题。
18. 一个完整故障推演¶
假设某 Topic 有 12 个 Partition、Replication Factor 为 3、min.insync.replicas=2,Producer 使用 acks=all。消费组有 6 个 Consumer,每个实例正常情况下负责两个 Partition。业务处理完成后手动提交 offset。
如果一个 Consumer 进程退出,它原来负责的两个 Partition 会经过组协调重新分配给剩余 Consumer。已经提交的 offset 决定新 Consumer 从哪里恢复;上一实例已经完成业务但尚未提交的最后一小段消息可能再次被消费,所以业务副作用需要幂等。
如果某 Partition 的一个 Follower Broker 故障,只要 Leader 和另一个同步副本仍满足 ISR 与 min.insync.replicas=2,Producer 的 acks=all 写入仍能成功。如果继续丢失副本导致 ISR 只剩一个,新的写入会失败,Producer 根据重试和超时配置处理错误。这个行为保护了数据冗余条件,同时牺牲故障期间的一部分写可用性。
如果某个业务 key 占据 50% 的消息量,同 key 会集中进入一个 Partition。即使消费组还有多个空闲 Consumer,这个 Partition 也只能由其中一个成员直接消费,单 Partition 会成为吞吐上限。此时需要重新审视业务顺序范围和 key 设计,而不能只继续添加 Consumer。
19. 容易混淆的结论¶
Kafka 的顺序保证范围是 Partition;同 key 能否保持业务顺序还取决于分区策略和 Consumer 内部并发处理。acks=all 代表等待 ISR 中满足提交条件的复制确认,它需要和 min.insync.replicas、Replication Factor 一起讨论。Producer idempotence 主要解决重试重复,不会自动消除业务层重复发送和 Consumer 重复处理。
Consumer Group 的并行度受 Partition 数限制;增加 Consumer 只在存在可重新分配的 Partition 且消费侧确实是瓶颈时有效。Lag 是结果指标,需要结合每个 Partition、处理耗时、下游依赖和 Rebalance 分析原因。Kafka Transaction 可以很好地覆盖 Kafka 内部的 read-process-write 流程,涉及 MySQL 或外部 HTTP 副作用时还需要业务侧一致性设计。
参考资料¶
Apache Kafka 官方文档:Introduction、Design、Producer Configs、Consumer Rebalance Protocol、Kafka 4.0 Upgrade。