最近几天把kafka的论文看了几遍,虽然是linkedin 2011发的论文,但是设计理论是可以总结和学习的。介绍和比较kafka的文章网上已经有很多,这里就是记录一下几点阅读笔记。
kafka的设计初衷是适用于大规模日志收集系统,所以其最主要的理念是强调高吞吐,弱化可靠性、交付保证(delivery guarantee)。听上去很宏观,需要从每个小细节着手去实现,这在论文中有部分阐述。
高吞吐
Produce
1. 区别于传统MQ,如ActiveMq, RadditMQ,最主要的一点是对batch messag的支持。这很好理解,producer可以积累多个消息,然后批量地发送给broker,吞吐当然可以成倍的涨。
2. Producer不需要等待broker的ACK,可以连续不断地发送消息。
3. broker对消息的持久化是顺序写磁盘模式,新的消息总是被append到文件的末尾,达到O(1)复杂度。
Consume
1. broker采用sendfile方式将消息从file channel直接拷贝到socket channel,而不需要经过用户态。
2. broker不记录任何消息的消费状态(比如每个consumer group的读偏移量),所以在交付消息时对broker不需要产生额外的记录状态操作。相反,消费状态信息由consumer去维护。
可靠性
1. 由于producer在发送消息时不会等待broker的ACK,无法保证每一条发送到message都被broker接收且持久化。存在消息丢失的可能性。P.S. 当然,论文中提到计划在将来提供解决方案,以满足critical data的要求。
2. 由于没有replication,如果其中一台broker down掉,存储在它里面的所有消息将丢失。P.S. 同样,论文中提到奖金会增加replication的支持。参考最新的文档:https://cwiki.apache.org/confluence/display/KAFKA/Kafka+Replication
交付保证
1. at-least-once交付,可能会出现重复交付的情况,需要consumer做去重处理。
2. 在一个partition里保证消息顺序交付,但是多个partition的消息相互不保证顺序。举个简单例子,消息a先被提交到partition 1,随后消息b被提交到partition 2,那么消息b有可能先于消息a交付。
消费模型
1. 采用pull消费模型,使得consumer按需消费,不会出现over load的情况。当然,这就要求broker具有很强的消息积压能力,即消息大量堆积时,不会严重降低系统性能。
2. 对每个topic消费的最小单位是partition,任意时刻,一个partition只能被consumer group里的一个consumer消费,但多个consumer group可以同时消费同一个partition。kafka将尽量保证partition被均匀地分配给consumer group里的每个consumer。所以当broker或consumer group发生变动时,需要做一个rebalance,对partition重新分配一次。
3. 由于partition是并发消费的最小单位,所以一个partition不能太大。最极端的例子,一个topic只有一个partition,但是订阅它的group有2个consumer,这将导致始终同时只有一个consumer能读topic的消费,没有任何并发可言。
集群支持
1. producer,broker,consumer都可以是分布式集群,通过zookeeper来协调。
2. 对于broker,zk用来记录broker列表,由producer从zk拉取broker列表,然后根据一定的策略(hashing)选择其中一个broker发送消息。
3. 对于consumer,zk用来维护管理consumer group,将topic的各个partition均匀地分配给每个group里的每个consumer。zk还用来记录partition被每个consumer消费的偏移量,当group其中一个consumer挂掉后,可以重新分配给其他consumer,新的consumer将从最后记录的偏移量开始继续消费。