消息队列Kafka | 青训营笔记

120 阅读5分钟

这是我参与「第五届青训营」伴学笔记创作活动的第20天

消息队列的前世今生

消息队列:是保存消息的一个容器,本质是一个队列,但有高吞吐、高并发、高可用的特点

消息队列的作用

  1. 解耦:将存储服务与事件解耦
  2. 削峰
  3. 异步:消息队列异步发送给不同的服务
  4. 日志处理:日志先发到消息队列,消息队列再发给搜索引擎等展示,避免因本地服务崩溃导致本地日志不可察

image.png

消息队列发展历程

image.png

业界消息队列对比

  1. Kafka:分布式、分区、多副本的日志提交服务,在高吞吐场景发挥出色
  2. RocketMQ:低延迟、高性能、该可靠、万亿计容量和灵活的可扩展性,在实时场景运用较广
  3. Pulsar:下一代云原生分布式消息流平台,集消息、存储、轻量化函数计算为一体、采用存算分离的架构设计
  4. BMQ:字节研发和Pulsar架构类似,存算分离,初期定位是承接高吞吐的离线业务场景,逐步替换对应的kafka集群

消息队列-Kafka

使用场景

一般在离线消息应用场景较多:日志信息、Metrics数据、用户行为等

基本概念

  1. Topic:逻辑队列,不同的topic可以建立不同的topic
  2. Cluster:物理集群,每个集群中可以建立多个不同的Topic
  3. Producer:生产者,负责将业务消息发送到Topic中
  4. Consumer:消费者,负责消费Topic中的消息
  5. ConsumerGroup:消费者组,不同组的消费进度互不干涉
  6. Partition:Topic的分区,不同分区的消息可以并发处理

image.png 7. Offset:在partition内的相对位置信息,可以理解为唯一ID,在partition内部严格递增

image.png

  1. Leader:对外的写入(生产者)和读取(消费者)
  2. Flower:不断将Leader的数据拉取下来,努力与Leader保持一致,
  3. ISR(In-Sync Replicas):如果Flower与Leader差距过大,则不许Flower再去拉数据,而将其提出,如果Leader所在机器发生宕机,则选择一个Flower作为Leader
    1. 差距过大版本根据Offset判别
    2. 版本根据时间判别

image.png

  1. Broker:副本的节点,所有节点组成一个集群
  2. Controller:集群大脑,对集群的Leader进行分配

image.png 13. Zookeeper:与Controler配合,存储集群的运输局信息、分区分配信息

image.png

Producer:消息发送

  • 批量发送:一个Batch 包含多个message,减少IO次数,加强发送能力
  • 压缩:减少消息大小,防止因消息太大导致带宽不够
    • 压缩算法:Snappy(默认)、Gzip、LZ4、ZSTD(性能优秀)

image.png

Broker:数据存储与查找

消息存储

Brocker将一个个Batch存入磁盘

  1. 消息都是以Log的形式写入磁盘的
  2. 每一个Log分为LogSegment,每个LogSegment又分为四个部分
  3. 每个LogSegmengt使用该Segmengt内部第一条消息Offset作为文件名

image.png 4. 顺序写:提高写入效率,在磁盘的扇区末尾添加,减少磁盘的寻道时间(因为不会像数据库需要对消息进行修改

如何找到消息

Offset索引:

  1. 首先根据Offset二分找到该Log在哪个文件
    1. 找到小于目标Offset的最大索引位置(稀疏索引)
  2. 顺序读取Batch,找到消息

时间索引:

  1. 类似,就是加了一个时间的二级索引
  2. 二分找到小于目标时间的最大索引位置
  3. 再通过寻找offset的方式找到最终数据

image.png

内存拷贝

零拷贝技术:减少了三次拷贝,直接从内核态拷到网卡 mmap技术:再用户态写入不同先写进内核空间,而是直接写到磁盘

image.png

Consumer:消息的接收端

每一个ConsumerGroup都是一个独立的整体,即需要拉取一个Topic中的全部数据,那么哪个Consumer拉取哪个Partition呢?

手动分配:LowLevel

先在代码中分配好,每个consumer就是一个进程

image.png

缺点

  1. 不能容灾:如果consumer3挂掉,则partition7和partiton8就会拉取不到
  2. 数据中断:若consumer1,2性能不够,需要加一个consumer4,**如何重新分配?**必须有一个进程的启停

优点:快

自动分配:HighLevel

对于不同的ConsumerGroup都会从Broker中选取一个作为Coordinator:帮助Consumer自动分配,该过程被叫做Reblance

Reblance

  1. ConsumerGroup中的Consumer像Broker集群发起询问,选一个负载最低的Broker作为Coordinator
  2. Coordinator会从当前Consumer中选取一个Leader
  3. Coordinator向Consumer同步分配方案
  4. Consumer会定时向Coordinator发送心跳,以避免突然宕机

image.png

问题

数据复制问题

  1. 如果某个Leader重启
  2. Leader切换,原Broker重启会疯狂的追赶数据:相当耗时
  3. 数据同步完成
  4. Leader回切(方式1-99个Broker全部重启导致所有Leader全部到一个Broker上)

image.png 简而言之对于kafka集群,只要有任何节点的变动(替换、扩容、缩容)就会引起数据复制所带来的时间成本问题,导致时间成本、运维成本很高

负载不均衡问题

  1. 将partition3迁移到controller,以降低Broker的IO负载
  2. 但是迁走partition3又会导致数据复制问题,从而使得IO变高,
  3. 死循环

image.png

总结

  1. 运维成本高
  2. 对于负载不均衡的场景,解决方案复杂
  3. 没有自己的缓存,依赖Page Cache
  4. Controler、Coordinator、Broker在同一个进程中,大量IO会导致性能下降