这是我参与「第五届青训营 」伴学笔记创作活动的第13天
前言
本文具体介绍了消息队列的概念,并具体讲解了Kafka、BMQ、RocketMQ这三种消息队列,并进行了相互间的对比。本文目前只是简单的科普,具体实践还需要大家自己学习。
1.案例引入
1.系统崩溃
- 解决方案:解耦
2.服务处理能力优先
- 解决方案:削峰
3.链路耗时长尾
- 解决方案:异步
4.日志如何处理
- 解决方案:多级方法处理
2.消息队列概念
- 指保存消息的一个容器,本质是个队列。但这个队列呢,需要支持高吞吐,高并发,高可用。
1.发展历史
2.消息队列对比
- Kafka:分布式的、分区的、多副本的日志提交服务,常用在高吞吐场景下
- RocketMQ:低延迟、强一致、高性能、高可靠,常用在实时场景下
- Pulsar:集消息、存储、轻量化函数式计算为一体,采用存算分离的架构设计
- BMQ:类似Pulsar,存算分离,替换Kafka
3.Kafka
1.使用场景
2.使用流程
- 创建集群
- 新增Topic
- 编写生产者逻辑
- 编写消费者逻辑
3.基本概念
-
Topic:逻辑队列,不同 Topic 可以建立不同的 Topic
-
Cluster:物理集群,每个集群中可以建立多个不同的 Topic
-
Producer:生产者,负责将业务消息发送到 Topic 中
-
Consumer:消费者,负责消费 Topic 中的消息
-
ConsumerGroup:消费者组,不同组 Consumer 消费进度互不干涉
-
Offset :消息在partition内的相对位置信息,可以理解为唯一ID,在partition内部严格递增。
-
Replica:每个分片有多个Replica, Leader Replica将会从ISR中选出。
4.数据复制流程
各个Topic的leader在不同的Broker中,每个Broker有不同Topic的不同副本
5.架构
其中,ZooKeeper负责存储集群元信息,包括分区分配信息等
6.Producer(消息发送端)
- 批量发送(减少IO次数,加强发送能力,但受网络宽带限制)
- 数据压缩(减少消息大小,支持Snappy、 Gzip、 174、 ZSTD压缩算法)
7.Broker(数据存储)
- 消息文件结构
- 磁盘结构
- 方法:移动磁头找到对应磁道,磁盘转动,找到对应扇区,最后写入。但寻道成本比较高,因此可以减少寻道所带来的时间成本。
- 采用顺序写的方式写入,提高写入效率
- 查找消息办法
- 偏移量索引文件(二分找到小于目标时间戳最大的索引位置)
- 时间戳索引文件(二分找到小于目标时间戳最大的索引位置,再通过寻找offset的方式找到最终数据)
- 数据拷贝类型
- 传统数据拷贝
- 零拷贝(Reader Buffer直接给NIC Buffer)
8.Consumer(消息接收端)
- 接收方式
- Low Level(手动分配):当增减consumer时,会影响Partition消费
- High Level(自动分配):引入Coordinator,实现Rebalance
- Rebalance流程
- Consumer选出Group Coordinator
- Group Coordinator选出Consumer Leader
- Consumer Leader发给Group Coordinator分配方案
下图是整体流程:
9.重启操作
- Leader关闭,重启
- Leader切换,追赶数据
- 数据同步完成
- Leader回切
替换、扩容、缩容
- 替换,一个需要追更多数据的重启操作,需要复制整个leader的数据,时间会更长
- 扩容,当分片分配到新的机器上以后,从0开始复制一些新的副本
- 缩容,分片分配到集群中剩余节点上面,也得从0开始去复制数据
以上三个操作均有数据复制所带来的时间成本问题,所以对于Kafka来说,运维操作所带来的时间成本是不容忽视的
10.问题
- 运维成本高。数据需要复制
- 对负载不均衡场景,解决方案复杂
- 没缓存,完全依赖Page Cache
- Controller、Coordinator、Broker 在同一进程中,Broker中大量IO会造成其性能下降
4.BMQ
兼容Kafka,存算分离,云原生消息队列
1.架构图
与Kafka运维对比
- HDFS文件写入:随机选择一定数量的DataNode写入
2.文件结构
- 对于单个队列,随机分配到不同节点上,解决了负载不均衡的问题
3.Broker
Partition状态机
流程如下:
- 保证对于任意分片在同一时刻只能在一个Broker上存活
写文件流程
- 当写入失败时,不能进行等节点恢复,而是重新找正常的节点写入
4.Proxy
本质是一种等待机制,降低了fetch请求IO的次数
5.多机房部署
- 防止单机故障
- 防止机房级故障,如网络故障等
6.高级特性
- 泳道
- Databus
- Mirror
- Index
- Parquet
7.泳道消息
-
开发流程:开发->BOE->PPE->Prod
- BOE是一套完全独立的线下机房环境
- PPE是产品预览环境
-
原因:
- 在BOE测试中,只有一个Topic时,多人同时测试需要等待上一人测试完;多条主干时,每个测试人员都需要重新搭建一个配置相同的Topic,造成资源浪费
- 在PPE测试中,只有一个Topic,资源没有生产环境多,无法承受生产环境的流量
-
框架
解决了主干泳道流量隔离问题和通道资源重复创建问题
8.Databus
- 原生SDK缺点
- 客户端配置复杂
- 不支持动态配置,更改配置需要停掉服务
- 对于 latency 不是很敏感的业务,batch 效果不佳
- 框架
- 优点
- 简化消息队列客户端复杂度
- 解耦业务与Topic
- 缓解集群压力,提高吞吐量
9.Mirror
通过最终一致的方式,解决跨Region读写问题
10.Index
直接在 BMQ 中将数据结构化,配置索引 DDL,异步构建索引后,通过 Index Query 服务读出数据。
11.Parquet
Apache Parquet是Hadoop生态圈中一种新型列式存储格式,它可以兼容 Hadoop 生态圈中大多数计算框架(Hadoop、Spark等),被多种查询引擎支持(Hive、Impala、Drill等)。
- 框架
直接在 BMQ 中将数据结构化,通过 Parquet Engine,可以使用不同的方式构建 Parquet格式文件。
5.RocketMQ
1.基本概念
引入了标签、生产者集群,分区命名为ConsumerQueue,集群控制器命名为NameServer
2.架构
- 先说数据流也是通过Producer发送给Broker集群,再由Consumer进行消费
- Broker节点有Master和Slave的概念
- NameServer为集群提供轻量级服务发现和路由
3.存储模型
Broker中所有的消息的会anpend到一个Commitlog上面->按照不同的Queue重新Dispatch到不同的Consumer中->Consumer按照Queue进行拉取消费
注意:ConsumerQueue所存储的并不是真实的数据,存的是Queue所有消息在CommitLog上面的位置(Queue的一个密集索引),真实的数据只存在CommitLog中
4.高级特性
- 事务场景(比如库存记录-1和消息队列要成为一个事务,进而有了事务保证)
- 事务消息(有回滚,并能查询状态)
- 延迟发送(将定时任务改为消息队列)
- 延迟消息(增加延时服务)
- 消费重试和死信队列
小结
本文主要介绍了三种消息队列的性质、框架和一些高级特性,具体实操还是需要查找相应的资料。通过攥写本文,小编对消息队列的理解也加深了,大家也要多多总结
参考
- 字节跳动走进消息队列教程