这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天
消息队列kafka
使用场景
Metrics数据:在程序运行期间采集的程序状态数据
如何使用kafka
- 创建集群
- 新建Topic
- 编写生产者逻辑
- 编写消费者逻辑
基本概念
- Partition:Topic内部的分区,Partition之间可并发处理
- 对同一个Topic,不同消费组之间互不干涉
Offset
Replica (副本)
In-Sync Replicas(ISR):Leader与Follower间差距过大时(差距可设置),Follower将被踢出同步ISR
- 以前是按offset差距判断,现在是按时间差距判断
- 若Leader所在副本的机器宕机,则从ISR中选择一个Follower作为新的Leader
数据复制
每个Broker为一个节点,所有的Broker节点构成集群
Controller:负责对集群中的副本及Broker进行分配
由Controller计算出各个topic及分片的Leader所属Broker
Kafka架构
一条消息的自述
思考:若每发送一条消息,等其成功后再发一条会有什么问题
Producer-批量发送
思考:如果消息量很大,网络带宽不够用,如何解决
数据压缩
Broker-数据的存储
消息文件结构
副本最终会以日志形式写入磁盘,而消息有过期机制
- 每个日志会切分为不同的日志段LogSegment
- 每个日志段有4个部分
- .log日志部分
- 存储真实的日志数据
- .index 消息偏移量索引文件
- offset 与数据在真实数据文件具体位置的映射
- .timeindex 时间戳索引文件
- 通过时间戳表示索引
- 其他文件
- .log日志部分
Broker-磁盘结构
顺序写可减少寻道带来的时间成本
kafka采用顺序写以提高写入效率
采用末尾添加的方式添加消息
Broker-如何找到消息
偏移量索引文件
目标:寻找offset=28
broken内采用稀疏索引方式进行索引的构建
- 二分找到小于目标offset的最大文件(例子中找到的是26)
- 取出相应的Batch,通过遍历的方式找到offset为28的数据
时间戳索引文件
二分找到小于目标时间戳的最大索引位置,再通过寻找offset的方式找到最终数据
数据拷贝
-
传统数据拷贝
磁盘->Read Buffer->Socket buffer->NIC Buffer-> 消费者进程
2. 零拷贝(读)
在内核态直接将数据拷贝给网卡
-
零拷贝(写)
在用户态进行写之后,直接拷贝到磁盘而不经过内核态(利用mmap)
Consumer-消息的接收端
-
手动分配
- 生产者启动时,在代码里配置好不同Consumer拉取哪些Partition
- 缺陷
- 当某个Consumer宕机后,其对应的Partition数据流将断掉(不能自动容灾)
- 当有新的Consumer(无新的Partition)时,必须停掉部分现有Consumer与Partition的连接,为新Consumer配置Partition(带来机器的启动与停止,引起数据中断)
- 优点:快(提前配置好)
2. 自动分配
- 在Broker集群中,选择其中一个Broker当Coordinator(协调者),帮助该group内的consumer自动分配分片(partition)(分配过程称为rebalance)
- 当某个consumer宕机时,会自动将其原持有的分片分配给其他consumer
- 当新增consumer时,重新计算每个consumer持有的分片
Rebalance
- Consumer向负载较低的Broker发送FindCoordinatorRequest请求,以获取Broker中Coordinator的信息
- Consumer向Coordinator发送JoinGroupRequest表示想要加入整个group
- Coordinator收到请求后,从Consumer中选取一个Leader,由Leader计算分配策略(虽然kafka有默认分配策略,但有时业务会有特殊分配需求,故提供方法供业务自己实现分配方式)
- 通常选取Group中的第一个Consumer作为Leader,向所有Consumer发送JoinGroupResponse,对Leader额外附加 id.leader=true
- Consumer向Coordinator发送SyncGroupRequest,Leader发送的请求还会额外附加上分配方案。随后Coordinator向每个Consumer发送该分配方案
- 每个Consumer向Coordinator定期发送心跳(HeartBeatRequest)。某Consumer未及时发送心跳,将被认为出现故障,触发Rebalance重新进行分配
总结:Kafka用于提高吞吐或稳定性的功能
- Producer:批量发送、数据压缩
- Broker:顺序写、消息索引、零拷贝
- Consumer:Rebalance
kafka缺点
数据复制问题
重启、替换、扩容与缩容等都会因数据复制带来额外的时间成本
- 重启操作
- 当旧Leader重启时,将会选用新的Leader
- 待重启完毕,因在此期间仍然不断要接收新的数据,旧Leader需要不断追赶与新Leader间的数据差异
- 待数据同步完成后,旧Leader将重新获得Leader身份(Leader回切)
- 若没有回切操作,待陆续重启后,所有的Leader都将集中于最后的Broker上,带来数据压力,引起负载均衡问题
- 当Broker数量多时,陆续重启将花费很长的时间
- 并发重启可能导致该分片不可用
负载不均衡
当某个Partition数据较多时,该Partition将被迁至更合适的Broker中以达到负载均衡
(迁走前)
(迁走后)
- 对Partition进行迁移是为了通过负载均衡降低IO负担。
- 而迁走后又会引入进行数据复制问题,加重IO负担,带来死循环(引入的IO问题)
- 故需要权衡两者利弊,设计复杂的负载均衡问题
Kafka问题总结
- 运维成本高
- 对于负载不均衡场景,解决方案复杂
- 没有自己的缓存,完全依赖Page Cache
- Controller和Coordinator和Broker在同一进程中,大量IO会造成其性能下降