这是我参与「第五届青训营」笔记创作活动的第13天。
一、本堂课重点知识
今天主要的学习内容是消息队列原理与实战相关知识。
二、详细知识点介绍
什么是消息队列?
消息队列(MQ),指保存消息的一个容器,本质是个队列。但这个队列呢,需要支持高吞吐,高并发,并且高可用。
1. 前世今生
1.1 业界消息队列对比
- Kafka:分布式的、分区的。多副本的日志提交服务,在高吞吐场景下发挥较为出色
- RocketMQ:低延迟、强一致、高性能、高可靠、万亿级容量和灵活的可扩展性,在一些实时场景中运用较广
- Pulsar:是下一代云原生分布式消息流平台,集消息、存储、轻量化函数式计算为一体、采用存算分离的架构设计
- BMQ:和Pulsar架构类似,存算分离,初期定位是承接高吞吐的离线业务场景,逐步替换掉对应的Kafka集群
2. Kafka
2.1 使用场景
- 搜索服务
- 直播服务
- 订单服务
- 支付服务
2.2 如何使用Kafka
- 创建集群
- 新增Topic
- 编写生产者逻辑
- 编写消费者逻辑
2.3 基本概念
- Topic:逻辑队列,不同Topic可以建立不同的Topic
- Cluster:物理集群,每个集群中可以建立多个不同的Topic
- Producer:生产者,负责将业务消息发送到Topic中
- Consumer:消费者,负责消费Topic中的消息
- ConsumerGroup:消费者组,不同组Consumer消费进度互不干涉
- Offset:消息在partition内的相对位置信息,可以理解为唯一D,在partition内部严格递增
- Replica:每个分片有多个Replica,Leader Replica将会从ISR中选出
2.4 数据复制
2.5 Kafka架构
ZooKeeper:负责存储集群元信息,包括分区分配信息等
2.6 Producer
- 批量发送
- 数据压缩
2.7 Broker
- 数据的存储
- 消息文件结构
- 磁盘结构
- 顺序写
如何找到消息?
Consumer通过发送FetchRequest请求消息数据,Broker会将指定Offset处的消息,按照时间窗口和消息大小窗口发送给Consumer,寻找数据这个细节是如何做到的呢?
-
偏移量索引文件
- 目标:寻找offset=28
- 二分找到小于目标offset的最大文件
- 二分找到小于目标offset的最大索引位置
-
时间戳索引文件
- 二分找到小于目标时间戳最大的索引位置,通过寻找offset的方式找到最终数据
-
传统数据拷贝
- 零拷贝
2.8 Consumer
消息的接收端
- Low Level
- 通过手动进行分配,哪一个Consumeri消费哪一个Partition完全由业务来决定
- High Level
- 数据复制问题
- 重启操作
- 替换、扩容、缩容
- 负载不均衡
问题总结
- 运维成本高
- 对于负载不均衡的场景,解决方案复杂
- 没有自己的缓存,完全依赖Page Cache
- Controller和Coordinator和Broker在同一进程中,大量IO会造成其性能下降
3. BMQ
3.1 简介
兼容Kafka协议,存算分离,云原生消息队列
3.2 运维操作对比
| 具体操作 | Kafka | BMQ |
|---|---|---|
| 重启 | 需要数据复制,分钟级重启 | 重启后可直接对外服务,秒级完成 |
| 替换 | 需要数据复制,分钟级重启,甚至天级别 | 替换后可直接对外服务,秒级完成 |
| 扩容 | 需要数据复制,分钟级重启,甚至天级别 | 扩容后可直接对外服务,秒级完成 |
| 缩容 | 需要数据复制,分钟级重启,甚至天级别 | 缩容后可直接对外服务,秒级完成 |
3.3 HDFS写文件流程
随机选择一定数量的DataNode进行写入
3.4 BMQ文件结构
3.5 Broker
- Partition状态机
保证对于任意分片在同一时刻只能在一个Broker上存活
- 写文件流程
3.6 Proxy
3.7 多机房部署
3.8 高级特性
3,9 泳道消息
开发 BOE PPE Prod
-
BOE:Bytedance Offline Environment,是一套完全独立的线下机房环境
-
PPE:Product Preview Environment,即产品预览环境、
-
串行:多人同时测试,需要等待上一个人测试完成
-
并行:每多一个测试人员,都需要重新搭建一个相同配置的Topc,造成人力和资源的浪费。
对于PPE的消费者来说,资源没有生产环境多,所以无法承受生产环境的流量。
解决主干泳道流量隔离问题以及泳道资源重复创建问题。
3.10 Databus
直接使用原生SDK会有什么问题?
- 客户端配置较为复杂
- 不支持动态配置,更改配置需要停掉服务
- 对于latency不是很敏感的业务,batch效果不佳
- 简化消息队列客户端复杂度
- 解耦业务与Topic
- 缓解集群压力,提高吞吐
3.11 Mirror
使用Mirror通过最终一致的方式,解决跨Region读写问题。
3.12 Index
如果希望通过写入的LogId、UserId或者其他的业务字段进行消息的查询,应该怎么做?
直接在BMQ中将数据结构化,配置索引DDL,异步构建索引后,通过Index Query服务读出数据
3.14 Parquet
直接在BMQ中将数据结构化,通过Parquet Engine,可以使用不同的方式构建Parquet格式文件。
4. RocketMQ
4.1 使用场景
例如,针对电商业务线,其业务涉及广泛,如注册、订单、库存、物流等;同时,也会涉及许多业务峰值时刻,如秒杀活动、周年庆、定期特惠等
4.2 基本概念
4.3 RocketMQ架构
4.4 高级特性
- 事务场景
- 最终一致性
- 事务消息
- 延迟发送
- 延迟消息
- 消费重试和死信队列
三、实践练习例子
如何解决如下四个问题
- 案例一:系统崩溃
- 解耦
- 案例二:服务能力有限
- 削峰
- 案例三:链路耗时长尾
- 异步
- 案例四:日志存储
- 日志处理
从一条消息的视角,看看为什么Kafka能支撑这么高的吞吐?
如果发送一条消息,等到其成功后再发一条会有什么问题?
如果消息量很大,网络带宽不够用,如何解决?
可以帮助Kafka提高吞吐或者稳定性的功能?
- Producer:批量发送、数据压缩
- Broker:顺序写,消息索引,零拷贝
- Connsumer:Rebalance
四、课后个人总结
学习到了更多消息队列原理与实战的相关知识。
- 手动搭建一个Kafka集群。
- 完成Hello World的发送与接收。
- 关闭其中一个Broker,观察发送与接收的情况,并写出,在关闭一个Broker后,Kafka集群会做哪些事情?
五、引用参考
无