1.相关概念
1.1.topic:消息发布和订阅的基本单位
1.2.partition:topic与partition是一对多的包含关系,partition中的message由三部分组成:offset、messageSize、data,其中offset为long型,messageSize为int32类型,data为message的具体内容
1.3.message:Kafka 的数据单元,由key、value组成,key作为元数据,是可选的,value即为消息的内容。key和value,都是由字节数组构成,其数据格式完全由客户端控制。其中key的作用之一就是确定消息的partition所在,默认情况下, kafka 采用的是 hash 取模的分区算法。如果Key 为 null,则会随机分配一个分区。这个随机是在这个参数”metadata.max.age.ms”的时间范围内随机选择一个。对于这个时间段内,如果 key 为 null,则只会发送到唯一的分区。简单来说就是:hash(key) % partitions.size。
1.4.broker:kafka服务器
1.5.producer:生产者,负责发布message到kafka服务器,可以不指定partition,由kafka服务器自动指定,也可以指定发布的partition
1.6.consumer:消费者,从kafka服务器消费message,和生产者一样,可以选择是否指定partition
1.7.group:消费组,一个message只能被同一个group的consumer消费一次,可以被不同group多次消费
2.消息的重复消费和丢失
2.1.消息丢失
生产端:producer 生产数据默认是先写到内存中,定期 flush 到磁盘上。而kafka默认的消息确认级别是 request.required.acks = 0,生产者发送消息之后,不会等待 leader的确认。如果还没有flush到磁盘上,此时服务器发生宕机,就会丢失数据
消费端:消费端数据丢失的原因是 offset 的自动提交。如果将offset提交到服务器时,消息还没有消费完成,此时消费者宕机,也会造成消息丢失
解决办法:
生产端:修改默认的消息确认级别为需要leader确认
消费端:关闭自动提交,改成手动提交,每次数据处理完后,再提交offset
2.2.重复消费
还是offset自动提交的问题
2.2.1.如果消费者消费了message,但offset还未来得及提交,如果此时消费者宕机,在服务器看来,这些message就还没有被消费掉,会被分配给其它消费者消费
2.2.2.consumer的消费速度太慢,超过一个session周期,触发re-balance机制,kafka认为消费失败,造成重复消费
解决办法:
1.修改offset自动提交为手动提交
2.修改kafka.consumer.session.timeout的值(默认为30s)
3.保证消费者consumer消费消息的幂等性
3.高吞吐原理
3.1.顺序读写
kafka的消息是不断追加到文件中的,这个特性使kafka可以充分利用磁盘的顺序读写性能
顺序读写不需要硬盘磁头的寻道时间,只需很少的扇区旋转时间,所以速度远快于随机读写
3.2.零拷贝
在Linux kernel2.2 之后出现了一种叫做"零拷贝(zero-copy)"系统调用机制。
旧流程:磁盘 -> 内核空间 -> 用户空间 -> 内核空间 -> 网卡发送
零拷贝:磁盘 -> 内核空间 -> 内核空间(省去了用户空间的拷贝) -> 网卡发送
3.3.分区
比如有100条Message,它们的offset是从0到99。假设将数据文件分成5段,第一段为0-19,第二段为20-39,以此类推,每段放在一个单独的数据文件里面,数据文件以该段中最小的offset命名。这样在查找指定offset的message的时候,用二分查找就可以定位到该message在哪个段中。
3.4.批量发送与数据压缩
kafka允许进行批量发送消息,producter发送消息的时候,可以将消息缓存在本地,等到了消息条数达到一定数量,或固定的间隔时间,将消息压缩后发送到kafka,减少网络开销(虽然会增加cpu开销,但瓶颈主要在网络开销)