消息队列 | 青训营笔记

85 阅读8分钟

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

一、本堂课重点内容:

  1. 消息队列-Kafka
  1. 消息队列-BMQ
  1. 消息队列-RocketMQ

二、详细知识点介绍:

四个场景,如何解决?

  1. 系统崩溃

image.png 2. 服务处理能力有限

image.png 3. 链路耗时长尾

image.png 4. 日志如何处理

解决方案

  1. 系统崩溃(解耦)

image.png

  1. 服务处理能力有限(削峰)

image.png

  1. 链路耗时长尾(异步)

image.png

  1. 日志处理

image.png

什么是消息队列?

消息队列(MQ),指保存消息的一个容器,本质是个队列,但这个队列呢,需要支持高吞吐,高并发,并且高可用

image.png

业界消息队列对比

image.png

Kafka

使用场景

image.png

如何使用 Kafka

第一步:首先需要创建一个Kafka集群
第二步:需要在这个集群中创建一个Topic,并且设置好分片数量
第三步:引入对应语言的SDK,配置好集群和Topic等参数,初始化一个生产者,调用Send方法,将你的Hello World发送出去
第四步:引入对应语言的SDK,配置好集群和Topic等参数,初始化一个消费者,调用Poll方法,你将收到你刚刚发送的Hello World

image.png

基本概念

  • Topic:Kakfa中的逻辑队列,可以理解成每一个不同的业务场景就是一个不同的topic,对于这个业务来说,所有的数据都存储在这个topic中
  • Cluster:Kafka的物理集群,每个集群中可以新建多个不同的topic
  • Producer:顾名思义,也就是消息的生产端,负责将业务消息发送到Topic当中
  • Consumer:消息的消费端,负责消费已经发送到topic中的消息
  • Partition:通常topic会有多个分片,不同分片直接消息是可以并发来处理的,这样提高单个Topic的吞吐
Offset

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

image.png

Replica

每个分片有多个Replica,Leader Replica 将从 ISR 中选出。

image.png

数据复制

下面这幅图代表着Kafka中副本的分布图。途中Broker代表每一个Kafka的节点,所有的Broker节点最终组成了一个集群。整个图表示,图中整个集群,包含了4个Broker机器节点,集群有两个Topic,分别是Topic1和Topic2,Topic1有两个分片,Topic2有1个分片,每个分片都是三副本的状态。这里中间有一个Broker同时也扮演了Controller的角色,Controller是整个集群的大脑,负责对副本和Broker进行分配

image.png

Kafka 架构

image.png 而在集群的基础上,还有一个模块是ZooKeeper,这个模块其实是存储了集群的元数据信息,比如副本的分配信息等等,Controller计算好的方案都会放到这个地方

帮助Kafka提高吞吐或稳定性的功能

  • Producer:批量发送、数据压缩
  • Broker:顺序写,消息索引,零拷贝
  • Consumer:Rebalance

Kafka在使用中遇到问题

image.png 通过前面的介绍我们可以知道,对于Kafka来说,每一个Broker上都有不同topic分区的不同副本,而每一个副本,会将其数据存储到该Kafka节点上面,对于不同的节点之间,通过副本直接的数据复制,来保证数据的最终一致性,与集群的高可用。

image.png 如果我们对一个机器进行重启,首先,我们会关闭一个Broker,此时如果该Broker上存在副本的Leader,那么该副本将发生leader切换,切换到其他节点上面并且在ISR中的Follower副本,可以看到图中是切换到了第二个Broker上面 而此时,因为数据在不断的写入,对于刚刚关闭重启的Broker来说,和新Leader之间一定会存在数据的滞后,此时这个Broker会追赶数据,重新加入到ISR当中 当数据追赶完成之后,我们需要回切leader,这一步叫做prefer leader,这一步的目的是为了避免,在一个集群长期运行后,所有的leader都分布在少数节点上,导致数据的不均衡 通过上面的一个流程分析,我们可以发现对于一个Broker的重启来说,需要进行数据复制,所以时间成本会比较大,比如一个节点重启需要10分钟,一个集群有1000个节点,如果该集群需要重启升级,则需要10000分钟,那差不多就是一个星期,这样的时间成本是非常大的。 有同学可能会说,老师可以不可以并发多台重启呀,问的好,不可以。为什么呢,在一个两副本的集群中,重启了两台机器,对某一分片来讲,可能两个分片都在这台机器上面,则会导致该集群处于不可用的状态。这是更不能接受的。

image.png

如果是替换,和刚刚的重启有什么区别,其实替换,本质上来讲就是一个需要追更多数据的重启操作,因为正常重启只需要追一小部分,而替换,则是需要复制整个leader的数据,时间会更长 扩容呢,当分片分配到新的机器上以后,也是相当于要从0开始复制一些新的副本 而缩容,缩容节点上面的分片也会分片到集群中剩余节点上面,分配过去的副本也会从0开始去复制数据 以上三个操作均有数据复制所带来的时间成本问题,所以对于Kafka来说,运维操作所带来的时间成本是不容忽视的

image.png

总结:

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

BMQ

兼容 Kafka 协议,存算分离,云原生消息队列

image.pngProducer -> Consumer -> Proxy -> Broker -> HDFS -> Controller -> Coordinator -> Meta 着重强调一下Proxy和Broker无状态

运维操作对比

image.png 薄纱了

HDFS 写文件流程

随机选择一定数量的 DataNode 进行写入

image.png 通过前面的介绍,我们知道了,同一个副本是由多个segment组成,我们来看看BMQ对于单个文件写入的机制是怎么样的,首先客户端写入前会选择一定数量的DataNode,这个数量是副本数,然后将一个文件写入到这三个节点上,切换到下一个segment之后,又会重新选择三个节点进行写入。这样一来,对于单个副本的所有segment来讲,会随机的分配到分布式文件系统的整个集群中

BMQ文件结构

image.png 对于Kafka分片数据的写入,是通过先在Leader上面写好文件,然后同步到Follower上,所以对于同一个副本的所有Segment都在同一台机器上面。就会存在之前我们所说到的单分片过大导致负载不均衡的问题,但在BMQ集群中,因为对于单个副本来讲,是随机分配到不同的节点上面的,因此不会存在Kafka的负载不均问题

Broker-Partition 状态机

image.png 保证对于任意分片在同一时刻只能在一个 Broker上存活
首先,Controller做好分片的分配之后,如果在该Broker分配到了Broker,首先会start这个分片,然后进入Recover状态,这个状态主要有两个目的获取分片写入权利,也就是说,对于hdfs来讲,只会允许我一个分片进行写入,只有拿到这个权利的分片我才能写入,第二一个目的是如果上次分片是异常中断的,没有进行save checkpoint,这里会重新进行一次save checkpoint,然后就进入了正常的写流程状态,创建文件,写入数据,到一定大小之后又开始建立新的文件进行写入。

Broker-写文件流程

image.png 数据校验:CRC , 参数是否合法 校验完成后,会把数据放入Buffer中 通过一个异步的Write Thread线程将数据最终写入到底层的存储系统当中

Proxy

image.png

image.png

BMQ-高级特性

image.png

Databus

image.png

Mirror

image.png

Index

image.png

Parquet

image.png

image.png

image.png

RocketMQ

使用场景

image.png

基本概念

image.png

image.pngProducer,Consumer,Broker这三个部分,Kafka和RocketMQ是一样的,而Kafka中的Partition概念在这里叫做ConsumerQueue

存储模型

image.png 对于一个Broker来说所有的消息的会append到一个CommitLog上面,然后按照不同的Queue,重新Dispatch到不同的Consumer中,这样Consumer就可以按照Queue进行拉取消费,但需要注意的是,这里的ConsumerQueue所存储的并不是真实的数据,真实的数据其实只存在CommitLog中,这里存的仅仅是这个Queue所有消息在CommitLog上面的位置,相当于是这个Queue的一个密集索引

高级特性

事务场景

image.png

事务消息

image.png

延迟发送

image.png

image.png

延迟消息

image.png

消费重试和死信队列

image.png

三、课后个人总结:

本节课的知识量比较大,但是讲师讲的不错。把消息队列这个抽象的技术给我们呈现的很直观,让我们得以窥探其细节。能感觉到,消息队列的底层细节还是蛮复杂的。

四、引用参考:

消息队列前世今生 - 掘金 (juejin.cn)

消息队列-Kafka - 掘金 (juejin.cn)

消息队列- BMQ - 掘金 (juejin.cn)

消息队列- RocketMQ - 掘金 (juejin.cn)