消息队列 2 | 青训营笔记

113 阅读4分钟

消息队列

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

3 消息队列—BMQ

3.1 BMQ介绍

兼容 Kafka 协议,存算分离,云原生消息队列,下图是BMQ架构图:

image.png

3.2 运维操作对比

image.png

3.3 HDFS写文件流程

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

image.png

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

3.4 BMQ文件结构

image.png

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

3.5 Broker-Partition 状态机

image.png

其实对于写入的逻辑来说,我们还有一个状态机的机制,用来保证不会出现同一个分片在两个Broker上同时启动的情况,另外也能够保证一个分片的正常运行。首先,Controller做好分片的分配之后,如果在该Broker分配到了Broker,首先会start这个分片,然后进入Recover状态,这个状态主要有两个目的获取分片写入权利,也就是说,对于hdfs来讲,只会允许我一个分片进行写入,只有拿到这个权利的分片我才能写入,第二一个目的是如果上次分片是异常中断的,没有进行save checkpoint,这里会重新进行一次save checkpoint,然后就进入了正常的写流程状态,创建文件,写入数据,到一定大小之后又开始建立新的文件进行写入。

3.6 Broker 写文件流程

image.png

数据校验:CRC,参数是否合法

校验完成后,会把数据放入Buffer中 通过一个异步的Write Thread线程将数据最终写入到底层的存储系统当中

这里有一个地方需要注意一下, 就是对于业务的写入来说,可以配置返回方式,可以在写完缓存之后直接返回, 另外我也可以数据真正写入存储系统后再返回, 对于这两个来说前者损失了数据的可靠性, 带来了吞吐性能的优势, 因为只写入内存是比较快的,但如果在下一次flush前发生宕机了, 这个时候数据就有可能丢失了,后者的话, 因为数据已经写入了存储系统, 这个时候也不需要担心数据丢失,相应的来说吞吐就会小一些

我们再来看看Thread的具体逻辑,首先会将Buffer中的数据取出来,调用底层写入逻辑,在一定的时间周期上去flush,flush完成后开始建立Index,也就是offset和timestamp对于消息具体位置的映射关系

Index建立好以后,会save一次checkpoint,也就表示,checkpoint后的数据是可以被消费的辣,我们想一下,如果没有checkpoint的情况下会发生什么问题,如果flush完成之后宕机,index还没有建立,这个数据是不应该被消费的,最后当文件到达一定大小之后,需要建立一个新的segment文件来写入

4 消息队列 — RocketMQ

4.1 RocketMQ基本概念

image.png

4.2 RocketMQ架构

image.png

4.3 高级特性—事务场景

image.png

先看一下我们最开始说的这个场景,正常情况下,这个下单的流程应该是这个样子,首先我保证库存足够能够顺利-1,这个时候再消息队列让我其他系统来处理,比如订单系统和商家系统,但这里有个比较重要的点,我库存服务和消息队列必须要是在同一个事务内的,大家还记不记得事务的基本特性是什么。ACID, 这里库存记录和往消息队列里面发的消息这两个事情,是需要有事务保证的,这样不至于发生,库存已经-1了,但我的订单没有增加,或者商家也没有收到通知要发货。因此RocketMQ提供事务消息来保证类似的场景,我们来看看其原理是怎么样的。