Ⅲ.kafka
一、定义
基于消息发布与订阅的消息队列中间件。
二、作用
解耦:实现生产端与消费端的解耦
削峰:消息峰值时可做缓存,处理生产>消费的情况
异步:消费端可以异步消费
三、模式
一对一、点对点模式:消费者主动拉取消息,消息收到后清除
问题:处理多消费者麻烦

一对多、发布订阅模式:一条消息发送给多数人,消息不会清除

包括消费者拉取与队列推送两种模式。
kafka采取消费者拉取模式,优势是可以基于消费者速度自定义拉取速度,不会造成消费者崩溃或资源浪费;缺点是需要花费资源确认队列中是否有新消息,维护长轮询。
四、架构

- 主题topic:用于存放不同的消息,相当于文件夹
- 分区:负载均衡,提升消息读写速度
- 备份:消息备份,提升topic可靠性,当leader宕机时,follower会升级代替称为主节点
- 消费者:同一消费者组只能消费不同分区的同主题,因此最优情况为消费者组内消费者数量=同一主题的分区数
- zookeeper:分布式协调中心,用于kafka集群管理,以及在0.9版本前的消费记录,当消费者宕机恢复后,可以继续之前的消费
五、部署
主题操作
列出主题
bin/kafka-topics.sh --list --zookeeper ip:port
创建主题
bin/kafka-topics.sh --create --zookeeper ip:port --topic name --partitions 2 --replication-factor 2
删除主题
bin/kafka-topics.sh --delete --zookeeper ip:port --topic name
主题详情
bin/kafka-topics.sh --describe --zookeeper ip:port --topic name
生产消费操作
生产者
bin/kafka-console-producter.sh --topic name --broker-list ip:port
消费者(0.9以前模式)
bin/kafka-console-consumer.sh --topic name --zookeeper ip:port
断点消费
bin/kafka-console-consumer.sh --topic name --zookeeper ip:port --from-beginning
消费者(0.9以后模式)
bin/kafka-console-consumer.sh --topic name --bootstrap-server ip:port
六、详细工作流程
偏移量依赖分区而存在,同一TOPIC的不同分区拥有不同的偏移量。
偏移量在生产者写入数据时同步记录,kafka只保证同一分区内有序。
七、文件存储
文件名:主题名-分区名
topic=(partition1+partition2+......)
partition=(segment1+segment2+......)
segment=.log+.index
kafka的数据存储采取分片+索引机制,将一个partition分为多个segment片段,每一个segment又由log(数据)与index(索引)两部分组成。
index 数据定位,记录当前log中每一条消息对应的起始偏移量位置信息,索引根据二分查找法查询
log 数据存储(只存数据,别的都没有),每个log最大1G数据,log由若干message组成,并由索引定位
timeindex 写入时间
八、生产者
8.1 分区策略
- topic+partition:直接将数据放入指明的partition中
- topic+key+value:将key的hash与partition数取余得到partition
- topic+value:第一次调用随机生成一个整数,以后每次调用在这个整数的基础上自增,与partition取余得到partion值,round-robin算法
8.2 数据可靠性
在半数以上副本完成同步与全部完成同步之间,kafka选择了后者。原因是:
- 要容忍n台故障,前者需要2n+1台保障,后者需要n+1台保障
- kafka中网络延迟影响较小
8.3 ISR
kafka第二种同步方案的缺点是如果有一个副本同步非常慢会导致全局无法完成同步,follower无法给leader发送ack,为解决这种问题,kafka采用ISR策略。
以时间为阈值保留一部分副本,阈值时间内的副本设置为ISR,阈值时间外的不做强制要求。leader选举时只在ISR中选择。
8.4 ACK
ack保证生产数据不丢失,acks参数配置
0:producer不等待broker的ack,broker故障时会丢数据
1:只等待leader的ack,如果在leader接受完成后,follower完成同步前,leader故障,会丢数据
-1:等待broker的ack,partition的leader与ISR-follower全部完成同步后,才返回ack
在leader完成同步却没完成发送ack时leader故障,选举上来的follower会接受重复数据。
8.5 故障处理
HW保证消费者数据的一致性
LEO:每个副本中最大的offset
HW:所有副本中最小的LEO,HW之前的数据才对consumer可见
数据截取保证集群存储的一致性
follower发生故障时,会被暂时踢出ISR,恢复后会读取本地磁盘记录的HW,并将log中高于HW的数据截掉,从HW开始向leader同步,等到follower中的leo大于等于leader时,就可以重新加入ISR;
leader发生故障时,会从ISR中选取新的leader,为保证多副本存储一致性,其余所有副本会根据HW进行截取,如果此时副本数据少于leader,会根据leader进行同步。数据截取不能保证数据不丢失或者不重复。
8.6 Exactly Once
ack=0会引起数据丢失(at Most Once)
ack=-1会引起数据重复(at Least Once)
为保证一些非常重要的信息既不丢失,也不重复,kafka0.11版本引入幂等性,可以直接去重。
幂等性+at Least Once = Exactly Once
启用幂等性:将producer中参数enable.idompotence设置为true
对于每个producer分配一个pid(producerID),发往同一partition的消息会附带sequence number,broker会对<pid partition seqnumber>做缓存,当具有相同主键的消息提交时,broker只会提交一条。
幂等性只能处理单个会话中单个分区的数据重复问题。
9. 消费者
9.1 拉取策略
为防止集群中没有数据的时候,消费者会一直拉取数据的情况。kafka在消费数据时会传入超时参数timeout,如果当前没有数据可消费,消费者会等待timeout。
9.2 分区分配策略
RoundRobin(轮询)
只适用于消费者消费单一主题。

多主题时将同一消费者组的多个主题作为一个整体,对每个分区取hash值排序,再进行轮询分配。

缺点非常明显,同组内分别消费不同的topic会引起消息交叉,一般不采用。

Range
多主题时按主题单独进行划分,默认的多主题方式
缺点时会引起消费者消费数据不对等


当消费者组的消费者个数发生变化时会触发重新分配,对所有消费者的分区分配做重新分配。
9.3 offset
offset在zookeeper按照消费者组保存 (组+主题+分区)
0.9以后,kafka将offset保存在一个内置topic(_consumer_offsets)中
10 生产者API
消息的发送由main与sender两个线程完成,主线程负责对消息序列化,过滤,分区选择并送到RecordAccumulator中,由sender线程推送消息到kafka集群中。

11 消费者API