知识卡片
基于日志的消息代理:分区、偏移量与传统代理的权衡
内容
[[消息代理与数据库的四点本质差异]]揭示了AMQP/JMS风格代理”处理完即删除”的破坏性本质:不能像文件或数据库那样任意添加新消费者、重读久远的历史数据。基于日志的消息代理(如Kafka、Kinesis Streams、DistributedLog)用一个更简单的结构解决了这个矛盾:日志是磁盘上仅追加写入的记录序列,生产者把消息追加到日志末尾,消费者顺序读取,读到末尾就等待新消息通知(类似tail -f);为突破单磁盘吞吐量上限,日志按[[分区的目标是均匀分布负载偏斜与热点是核心风险]]中的原则做分区,不同分区独立托管在不同机器上,每个分区内消息严格有序并被分配单调递增的偏移量(分区之间不保证顺序)。这种设计天然支持扇出——多个消费者各自独立读日志、互不干扰,因为读取不会删除消息;负载均衡则改为把整个分区分配给消费者组内的某个节点(而非单条消息任意分配),代价是共享消费一个主题的节点数上限就是分区数,且某条消息处理慢会阻塞该分区后续所有消息(行首阻塞)。因此:处理代价高、希望逐条并行、顺序不重要时更适合传统JMS/AMQP代理;吞吐量高、处理快、顺序重要时更适合基于日志的方案。
结构图:
flowchart TD
A[生产者] -->|追加写入| B[主题=多个分区的仅追加日志]
B --> C[分区0: 偏移量0,1,2...]
B --> D[分区1: 偏移量0,1,2...]
C --> E[消费者组1的节点a 独占该分区]
D --> F[消费者组1的节点b 独占该分区]
C -.扇出,独立读取互不影响.-> G[消费者组2]
D -.扇出.-> G
参考来源
- 位置:《数据密集型应用系统设计》第十一章《流处理》"分区日志""使用日志进行消息存储""日志与传统的消息传递相比"(源文件:_epub-src/ch11_split_000.html)
- 结论依据:原文描述基于日志的消息代理如何用仅追加日志+分区+单调递增偏移量实现消息存储,说明其天然支持扇出、负载均衡改为按分区分配,并对比其与传统消息代理在共享节点数上限与行首阻塞方面的取舍,直接支撑本卡片的结构图与解释。
- 原始内容:日志只是磁盘上简单的仅追加记录序列……为了伸缩超出单个磁盘所能提供的更高吞吐量,可以对日志进行分区……基于日志的方法天然支持扇出式消息传递……共享消费主题工作的节点数,最多为该主题中的日志分区数。