这是我参与「第五届青训营 」伴学笔记创作活动的第 14 天
一、本堂课重点内容:
- 消息队列-Kafka
- 消息队列-BMQ
- 消息队列-RocketMQ
二、详细知识点介绍:
四个场景,如何解决?
- 系统崩溃
2. 服务处理能力有限
3. 链路耗时长尾
4. 日志如何处理
解决方案
- 系统崩溃(解耦)
- 服务处理能力有限(削峰)
- 链路耗时长尾(异步)
- 日志处理
什么是消息队列?
消息队列(MQ),指保存消息的一个容器,本质是个队列,但这个队列呢,需要支持高吞吐,高并发,并且高可用。
业界消息队列对比
Kafka
使用场景
如何使用 Kafka
第一步:首先需要创建一个Kafka集群
第二步:需要在这个集群中创建一个Topic,并且设置好分片数量
第三步:引入对应语言的SDK,配置好集群和Topic等参数,初始化一个生产者,调用Send方法,将你的Hello World发送出去
第四步:引入对应语言的SDK,配置好集群和Topic等参数,初始化一个消费者,调用Poll方法,你将收到你刚刚发送的Hello World
基本概念
- Topic:Kakfa中的逻辑队列,可以理解成每一个不同的业务场景就是一个不同的topic,对于这个业务来说,所有的数据都存储在这个topic中
- Cluster:Kafka的物理集群,每个集群中可以新建多个不同的topic
- Producer:顾名思义,也就是消息的生产端,负责将业务消息发送到Topic当中
- Consumer:消息的消费端,负责消费已经发送到topic中的消息
- Partition:通常topic会有多个分片,不同分片直接消息是可以并发来处理的,这样提高单个Topic的吞吐
Offset
Offset:消息在 partition 内的相对位置信息,可以理解为唯一ID,在 partition 内部严格递增。
Replica
每个分片有多个Replica,Leader Replica 将从 ISR 中选出。
数据复制
下面这幅图代表着Kafka中副本的分布图。途中Broker代表每一个Kafka的节点,所有的Broker节点最终组成了一个集群。整个图表示,图中整个集群,包含了4个Broker机器节点,集群有两个Topic,分别是Topic1和Topic2,Topic1有两个分片,Topic2有1个分片,每个分片都是三副本的状态。这里中间有一个Broker同时也扮演了Controller的角色,Controller是整个集群的大脑,负责对副本和Broker进行分配
Kafka 架构
而在集群的基础上,还有一个模块是ZooKeeper,这个模块其实是存储了集群的元数据信息,比如副本的分配信息等等,Controller计算好的方案都会放到这个地方
帮助Kafka提高吞吐或稳定性的功能
- Producer:批量发送、数据压缩
- Broker:顺序写,消息索引,零拷贝
- Consumer:Rebalance
Kafka在使用中遇到问题
通过前面的介绍我们可以知道,对于Kafka来说,每一个Broker上都有不同topic分区的不同副本,而每一个副本,会将其数据存储到该Kafka节点上面,对于不同的节点之间,通过副本直接的数据复制,来保证数据的最终一致性,与集群的高可用。
如果我们对一个机器进行重启,首先,我们会关闭一个Broker,此时如果该Broker上存在副本的Leader,那么该副本将发生leader切换,切换到其他节点上面并且在ISR中的Follower副本,可以看到图中是切换到了第二个Broker上面
而此时,因为数据在不断的写入,对于刚刚关闭重启的Broker来说,和新Leader之间一定会存在数据的滞后,此时这个Broker会追赶数据,重新加入到ISR当中
当数据追赶完成之后,我们需要回切leader,这一步叫做prefer leader,这一步的目的是为了避免,在一个集群长期运行后,所有的leader都分布在少数节点上,导致数据的不均衡
通过上面的一个流程分析,我们可以发现对于一个Broker的重启来说,需要进行数据复制,所以时间成本会比较大,比如一个节点重启需要10分钟,一个集群有1000个节点,如果该集群需要重启升级,则需要10000分钟,那差不多就是一个星期,这样的时间成本是非常大的。
有同学可能会说,老师可以不可以并发多台重启呀,问的好,不可以。为什么呢,在一个两副本的集群中,重启了两台机器,对某一分片来讲,可能两个分片都在这台机器上面,则会导致该集群处于不可用的状态。这是更不能接受的。
如果是替换,和刚刚的重启有什么区别,其实替换,本质上来讲就是一个需要追更多数据的重启操作,因为正常重启只需要追一小部分,而替换,则是需要复制整个leader的数据,时间会更长 扩容呢,当分片分配到新的机器上以后,也是相当于要从0开始复制一些新的副本 而缩容,缩容节点上面的分片也会分片到集群中剩余节点上面,分配过去的副本也会从0开始去复制数据 以上三个操作均有数据复制所带来的时间成本问题,所以对于Kafka来说,运维操作所带来的时间成本是不容忽视的
总结:
- 运维成本高
- 对于负载不均衡的场景,解决方案复杂
- 没有自己的缓存,完全依赖 Page Cache
- Controller 和 Coordinator 和 Broker 在同一进程中,大量 IO 会造成其性能下降
BMQ
兼容 Kafka 协议,存算分离,云原生消息队列
Producer -> Consumer -> Proxy -> Broker
-> HDFS -> Controller -> Coordinator -> Meta
着重强调一下Proxy和Broker无状态
运维操作对比
薄纱了
HDFS 写文件流程
随机选择一定数量的 DataNode 进行写入
通过前面的介绍,我们知道了,同一个副本是由多个segment组成,我们来看看BMQ对于单个文件写入的机制是怎么样的,首先客户端写入前会选择一定数量的DataNode,这个数量是副本数,然后将一个文件写入到这三个节点上,切换到下一个segment之后,又会重新选择三个节点进行写入。这样一来,对于单个副本的所有segment来讲,会随机的分配到分布式文件系统的整个集群中
BMQ文件结构
对于Kafka分片数据的写入,是通过先在Leader上面写好文件,然后同步到Follower上,所以对于同一个副本的所有Segment都在同一台机器上面。就会存在之前我们所说到的单分片过大导致负载不均衡的问题,但在BMQ集群中,因为对于单个副本来讲,是随机分配到不同的节点上面的,因此不会存在Kafka的负载不均问题
Broker-Partition 状态机
保证对于任意分片在同一时刻只能在一个 Broker上存活
首先,Controller做好分片的分配之后,如果在该Broker分配到了Broker,首先会start这个分片,然后进入Recover状态,这个状态主要有两个目的获取分片写入权利,也就是说,对于hdfs来讲,只会允许我一个分片进行写入,只有拿到这个权利的分片我才能写入,第二一个目的是如果上次分片是异常中断的,没有进行save checkpoint,这里会重新进行一次save checkpoint,然后就进入了正常的写流程状态,创建文件,写入数据,到一定大小之后又开始建立新的文件进行写入。
Broker-写文件流程
数据校验:CRC , 参数是否合法
校验完成后,会把数据放入Buffer中
通过一个异步的Write Thread线程将数据最终写入到底层的存储系统当中
Proxy
BMQ-高级特性
Databus
Mirror
Index
Parquet
RocketMQ
使用场景
基本概念
Producer,Consumer,Broker这三个部分,Kafka和RocketMQ是一样的,而Kafka中的Partition概念在这里叫做ConsumerQueue
存储模型
对于一个Broker来说所有的消息的会append到一个CommitLog上面,然后按照不同的Queue,重新Dispatch到不同的Consumer中,这样Consumer就可以按照Queue进行拉取消费,但需要注意的是,这里的ConsumerQueue所存储的并不是真实的数据,真实的数据其实只存在CommitLog中,这里存的仅仅是这个Queue所有消息在CommitLog上面的位置,相当于是这个Queue的一个密集索引
高级特性
事务场景
事务消息
延迟发送
延迟消息
消费重试和死信队列
三、课后个人总结:
本节课的知识量比较大,但是讲师讲的不错。把消息队列这个抽象的技术给我们呈现的很直观,让我们得以窥探其细节。能感觉到,消息队列的底层细节还是蛮复杂的。