这是我参与「第五届青训营」伴学笔记创作活动的第 11 天,今天学习的内容是关于消息队列的前世今生、Kafka、BMQ、RocketMQ,根据课程内容整理学习笔记如下。
9 消息队列原理与实战
9.1 消息队列是什么
9.1.1 四个应用场景
- 解耦
- 削峰
- 异步
- 日志处理
9.1.2 消息队列定义
消息队列(MQ),指保存消息的一个容器,本质是个队列。但这个队列需要支持高吞吐,高并发与高可用。
9.2 消息队列的前世今生
9.2.1 消息队列发展历程
9.2.2 业界消息队列对比
9.3 消息队列 - Kafka
9.3.1 使用场景
- 业务日志
- 用户行为数据
- Metrics数据(程序运行中程序状态信息,QPS/程序写入耗时等)
9.3.2 使用方法
创建集群 => 新增Topic => 编写生产者逻辑 => 编写消费者逻辑
9.3.3 基本概念
- Topic:逻辑队列,不同业务场景可以建立不同的Topic
- Cluster:物理集群,每个集群中可以建立多个不同的Topic
- Producer:生产者,负责将业务消息发送到Topic中
- Consumer:消费者,负责消费Topic中的消息
- ConsumerGroup:消费者组,不同组Consumer消费进度互不干涉
- Partition:Topic分区,不同分区的消息可并发处理,以提高单个Topic消息吞吐能力
- Offset:消息在partition内的相对位置信息,可以理解为唯一ID,在partition内部严格递增
-
Replica:每个分片有多个Replica,Leader Replica将会从ISR中选出
ISR作用:如果leader副本所在机器发生宕机,可在剩余ISR中选择继续服务
9.3.4 数据复制
9.3.5 Kafka架构
9.3.6 一条消息的处理流程
整体概览
Kafka提高吞吐量/稳定性的方法:
Producer:批量发送、数据压缩
Broker:顺序写,消息索引,零拷贝
Consumer:Rebalance
Producer端逻辑
批量发送 - 减少IO次数,从而增强发送能力
数据压缩 - 通过压缩,减少消息大小,目前支持Snappy、Gzip、LZ4、ZSTD
Broker端逻辑
数据的存储
Broker消息文件结构
顺序写 - 采用顺序写的的方式进行写入,以提高写入效率
消息索引 - Consumer通过发送FetchRequest请求消息数据,Broker会将指定Offset处的消息,按照时间窗口和消息大小窗口发送给Consumer
偏移量索引 - 稀疏索引(二分找到小于目标offset的最大索引位置)
时间戳索引文件 - 二分找到小于目标时间戳最大的索引位置,再通过寻找offset的方式找到最终数据
传统数据拷贝(内核态&用户态) - 开销大
零拷贝(系统调用,读出后直接给网卡发送) - 减少了三次不必要的内存拷贝
Consumer端逻辑
消息接收端 - 需要解决Partition在Consumer Group中的分配问题(手动分配/自动分配)
手动分配 - Low Level(直接指定各个Consumer要拉取的Partition)
优点:速度快
缺点:当有Consumer出现问题,有部分消息无法被处理;当新增Consumer时,会存在数据中断问题
自动分配 - High Level(Rebalance)
Consumer Rabalance
9.3.7 kafka问题
数据复制问题
重启操作(时间成本问题)
替换、扩容、缩容(时间成本问题)
负载均衡问题 - 尝试解决带来IO问题(死循环)
问题总结
- 运维成本高
- 对于负载不均衡的场景,解决方案复杂
- 没有自己的缓存,完全依赖Page Cache
- Controller和Coordinator和Broker在同一进程中,大量IO会造成其性能下降
9.4 消息队列 - BMQ
9.4.1 BMQ简介
采用kafka协议,存算分离,云原生消息队列
9.4.2 BMQ架构
9.4.3 运维操作对比
9.4.4 HDFS写文件流程
随机选择一定数量的DataNode进行写入
9.4.5 BMQ文件结构
每个Partition分为多个Segment,存放在不同DataNode中
9.4.6 Broker-Partition状态机
保证对于任意分片在同一时刻只能在一个Broker上存活
9.4.7 Broker模块
Broker写文件流程
Broker写文件Failover(重新找一个可用节点创建新Segment)
9.4.8 Proxy
Wait:等待,根据策略制定请求,减少频繁请求带来的IO压力
9.4.9 多机房部署
一个Proxy对Proxy的访问跨机房访问(保证分区内数据一致性)
多机房容灾
9.4.10 BMQ高级特性
开发流程相关
BOE (Bytedance Offline Environment):是一套完全独立的线下机房环境
方法一:多个人同时测试,需要等待上一个人测试完成
方法二:每多一个测试人员,都需要重新搭建一个相同配置的Topic,造成人力和资源的浪费
PPE (Product Preview Environment):即产品预览环境
对于PPE消费者来说,资源没有生产环境多,所以无法承受生产环境的流量
泳道消息
解决主干泳道流量隔离问题以及泳道资源重复创建问题
Databus
直接使用原生SDK的问题
- 客户端配置较为复杂
- 不支持动态配置,更改配置需要停掉服务
- 对于latency不是很敏感的业务,batch效果不佳
使用Databus
- 简化消息队列客户端复杂度
- 解耦业务与Topic
- 缓解集群压力,提高吞吐
Mirror
如何通过多机房部署方式,解决跨Region读写问题(跨国等业务)
使用Mirror通过最终一致的方式,解决跨Region读写问题
Index
希望通过写入的Logld、UserId或者其他的业务字段进行消息的查询
直接在BMQ中将数据结构化,配置索引DDL,异步构建索引后,通过Index Query服务读出数据
Parquet
Apache Parquet是Hadoop生态圈中一种新型列式存储格式,它可以兼容Hadoop生态圈中大多数计算框架(Hadoop、Spark等),被多种查询引擎支持(Hive、Impala、Drill等)
直接在BMQ中将数据结构化,通过Parquet Engine,可以使用不同的方式构建Parquet格式文件
9.5 消息队列 - RocketMQ
9.5.1 使用场景
针对电商业务线,业务涉及广泛,如注册、订单、库存、物流等;同时也会涉及许多业务峰值时刻,如秒杀活动、周年庆、定期特惠等
9.5.2 RocketMQ和Kafka对比
区别:
Tag字段 - 为了在Topic下还可以进行区分(如性别等),消费时提供更丰富的场景
Producer Group - 生产者组,为了支持事务消息
9.5.3 RocketMQ架构
Nameserver:向生产者消费者提供路由