前言:这是我参与「第三届青训营-后端场」笔记创作活动的第3篇笔记。这篇笔记记录了「走进消息队列」这一节的后半部分内容。
一、重点内容
1、消息队列的基本概念(见上一篇)
2、三大消息队列
- Kafka(见上一篇)
- BMQ
- RocketMQ
二、详细知识点介绍
1 BMQ
ByteMQ(BMQ)是一个兼容Kafka协议,存算分离,云原生的消息队列。
1.1 BMQ与Kafka进行对比
由表格可以看出,BMQ在重启、替换、扩容、缩容这些运维操作上的效率十分高,这得益于其架构的设计。实际上对于所有节点的变更操作,都仅仅只是集群元数据的变化,通常情况下都能秒级完成,而真正的数据存储在下层分布式文件存储系统中,因此才不需要考虑数据复制带来的时间成本。这与Kafka相比,是架构上的先进之处,也是云原生的体现。
1.2 BMQ的架构
从架构图上可以看到,由于BMQ是兼容Kafka协议的,因此Producer和Consumer Group部分与Kafka是类似的。因为有着存算分离的特性,在底层也存在着一个分布式文件系统提供消息存储支持,采用的是HDFS。Meta Storage System负责存储集群元信息,功能上与Kafka的ZooKeeper是类似的。
从消息流来看,当Producer提供数据给Proxy后,Proxy会将数据交给Broker来写入到HDFS中。而Consumer获取数据时,则是直接由Proxy从HDFS中拿取。
上文中也有所提到,Proxy与Broker本身并不存储数据,是无状态的,因此在节点变更时,只需要调整部分元信息,例如路由信息等即可,不用再考虑数据复制的问题。
从BMQ的文件结构上来看,得益于HDFS,数据均匀分散在不同的节点上,不会出现像Kafka一样的单分片过大导致负载不均衡的问题。
1.3 BMQ的读写流程
1.3.1 Broker-Partition 写入状态机
对于写入逻辑来说,存在状态机机制,用于保证不会出现同一个分片在两个Broker上同时启动的情况,同时也能保证一个分片的正常运行。
1.3.2 Broker-写文件流程
当接收到一条消息,首先通过CRC校验,查看数据是否合法。校验完成后,会先将数据存入Buffer中,通过一个异步的Writer线程将数据最终写入到底层的存储系统中。Writer线程的具体逻辑:首先会将Buffer中的数据取出来,调用底层写入逻辑,在一定的时间周期上flush,flush完成后开始建立Index,也就是和Kafka类似的偏移量索引和时间戳索引用于查找消息的具体位置。Index建立完成后,会保存一次checkpoint,这表示checkpoint后的数据是可以被消费的。
1.3.3 Broker-写文件 Failover
建立一个新的文件时,会随机挑选与副本数量相当的数据节点进行写入,如果此时挑选的节点中有节点出现了问题,导致不能正常写入。解决方法也很简单,就是重新寻找正常的节点创建新的文件进行写入,保证了写入的可用性。
1.3.4 Proxy-读文件流程
从流程图中可以看到,在Consumer发送了获取消息的请求后,并不会直接返回,而是经历一个Wait流程。这是因为如果一个Topic一直没有数据写入,那Consumer就会一直发送请求,如果数量达到一定规模,服务器会崩溃。因此,如果没有获取到指定大小的数据,等待机制降低了请求的IO次数。等待流程过后,先去缓存中寻找,找不到,再去存储系统中寻找。
1.4 BMQ的高级特性
1.4.1 泳道
该特性主要是为了应对大型企业,在开发测试流程中存在的不便之处,例如:有多人需要测试不同测试场景时,需要排队,无法并行测试,搭建多套相同配置的Topic,成本又太高。
泳道Topic解决了主干泳道流量隔离问题以及泳道资源重复创建问题。
1.4.2 Databus
该特性主要为了解决一下问题:1)客户端配置较为复杂;2)不支持动态配置,更改配置需要停掉服务;3)对于latency不是很敏感的业务,batch效果不佳。
Databus组件简化了消息队列客户端复杂度,解耦业务与Topic,缓解集群压力,提高吞吐。
1.4.3 Mirror
Mirror通过最终一致的方式,解决跨Region读写问题。
1.4.4 Index
Index主要为了解决一些特殊查询的需求,即通过某些业务字段进行消息的查询。该组件可以直接在BMQ中将数据结构化,配置索引DDL,异步构建索引后,通过Index Query服务读出数据。
1.4.5 Parquet
Apache Parquet是Hadoop生态圈中一种新型列式存储格式,它可以兼容Hadoop生态圈中大多数计算框架(Hadoop、Spark等),被多种查询引擎支持(Hive、Impala、Drill等)。
2、RocketMQ
RocketMQ具有低延迟、强一致、高性能、高可靠、万亿级容量和灵活的可扩展性,在一些实时场景中运用较广。
2.1 RocketMQ的使用场景
针对电商业务线,其业务涉及广泛,如注册、订单、库存、物流等。同时,也会涉及许多业务峰值时刻,如秒杀活动、周年庆、定期特惠等。
2.2 RocketMQ的基本概念
Producer、Consumer、Broker这三个部分,Kafka和RocketMQ是一样的,而Kafka中的Partition概念在这里叫做Consumer Queue。
2.3 RocketMQ的架构
数据也是通过Producer发送给Broker集群,再由Consumer进行消费。Broker节点为主从式设计。NameServer为集群提供轻量级服务发现和路由。
2.4 RocketMQ的高级特性
2.4.1 事务消息
RocketMQ提供了事务消息来保证一些需要事务的场景。例如,电商常见的下单流程。
在该场景下,需要保证库存记录减一,订单记录+1,通知商家这几个操作作为一个事务共同执行。
2.4.2 延迟发送
该特性能够帮助我们完成一些定时任务。
2.4.3 消息重试和死信队列
该特性主要为了解决消息处理失败的情况。
三、课后个人总结
这节课,不仅对消息队列的概念进行了详细的介绍,而且还选取了市面上主流的几款消息队列产品进行分析,透彻讲述了它们的原理和工作方式。涉及了不少底层架构知识,还需要慢慢消化。每一款消息队列都有它的应用场景,它们自身的架构特性决定了能胜任哪一种场景。没有哪一款消息队列可以面面俱到,在今后的开发过程中,应该根据应用场景的需求,选取适合的消息队列使用。在课中,也提到了不少消息队列的高级特性。这些特性针对了特定的场景进行了优化,在基础使用中可能不会用到,但在大型企业中,确实十分重要的。希望在今后的学习工作中,能够慢慢接触,细细领悟。