创造一个分布式的实时流处理平台,也正是因为这个原因,Kafka选择了将日志分区和消费者群组模型。
日志的持久化依赖于文件系统,而文件系统的处理速度,在往常的观念里,应该是相当慢的。但是依赖于pagecache-centric design,文件系统的持久化获得了极大的提升。并且Kafka的日志是顺序读写,对于磁盘的定位速度也远远大于随机读写的速度,同样也因为如此,对于传统的AMQP消息系统使用B树实现queue的持久化,也是因为忽略了磁盘的随机读写会很慢,通过日志的方式则不会block写和读,也可以做到O(1)的读写效率(从日志最后读)。
影响消息系统处理效率的主要有两个因素:
对于太多小的IO操作,Kafka会把一定时间内的消息先聚合内存中(“message set”),再一起写入,而不是来一条消息写一次日志。 对于过多的字节级复制,Kafka选择消费者,生产者和broker共享同一套二进制消息格式,使得操作系统可以直接将文件丢入network而不需要buffer。(zero-copy optimization,在具体的实现则是Linux中的sendfile system call方法) 此外,Kafka也提供了GZIP, Snappy and LZ4等协议压缩数据。
Kafka的生产者模型选择了生产者将数据直接发送给Topic的Master,而不是像Rabbit MQ一样需要路由(为了实现这,Kafka借助了Zookeeper,并且将元数据存储在Zookeeper之上)。除了此,Kafka将负载均衡的任务交给了客户端,客户端可以选择将消息发送到Topic中具体的哪个partition上。对于一些轻一致性,追求效率的场景,Kafka提供了异步发送的机制。
Kafka没有选择和AMQP消息系统一样,由消息系统将队列里的消息推送给消费者,而是让消费者自己将Kafka的数据根据offset拉下来。相对于push的方式,Kafka认为pull会给与消费者更大的自由权,这样消费者也可以从任意的offset开始消费(自然也方便失败重试),也无需担心数据会遗漏丢失(只要消息不过期)。Kafka会使用长连接池阻塞的方式,来解决消息未到时消费者连接问题。Kafka也会保存每个消费的消费过的offset元数据,以此来提高消费者的效率。
Kafka提供了三种消息确认机制:
Kafka在0.11.0.0开始通过给生产者的每条消息赋予全局ID,来保证消息不会被重复发送。