这是我参与「第五届青训营 」伴学笔记创作活动的第 9 天
内容来自掘金字节内部课程:消息队列前世今生,消息队列-Kafka,消息队列- BMQ,消息队列- RocketMQ
一、本堂课重点内容:
- 消息队列发展历程
- 消息队列-Kafka
- 消息队列-BMQ
- 消息队列-RocketMQ
二、详细知识点介绍:
案例一:系统崩溃
案例二:服务能力有限
案例三:链路耗时长尾
案例四:日志存储如何处理
什么是消息队列?
消息队列(MQ),指保存消息的一个容器,本质是个队列。但这个队列呢,需要支持高吞吐,高并发,并且高可用。
1. 前世今生
消息队列发展历程
业界消息队列对比:
- Kafka:分布式的、分区的、多副本的日志提交服务,在高吞吐场景下发挥较为出色
- RocketMQ:低延迟、强一致、高性能、高可靠、万亿级容量和灵活的可扩展性,在一些实时场景中运用较广
- Pulsar:是下一代云原生分布式消息流平台,集消息、存储、轻量化函数式计算为一体、采用存算分离的架构设计
- BMQ:和Pulsar架构类似,存算分离,初期定位是承接高吞吐的离线业务场景,逐步替换掉对应的Kafka集群
2. 消息队列-Kafka
2.1 使用场景
2.2 如何使用KafKa
- 创建集群
- 新增Topic(设置分区数量)
- 编写生产者逻辑(上游、hello world)
- 编写消费者逻辑
2.3 基本概念
- Topic:逻辑队列,不同Topic可以建立不同的Topic
- Cluster:物理集群,每个集群中可以建立多个不同的Topic
- Producer:生产者,负责将业务消息发送到Topic中
- Consumer:消费者,负责消费Topic中的消息
- ConsumerGroup:消费者组,不同组 Consumer消费进度互不干涉
- partition: topic分区,多个分区消息可并发处理,来提高单个topic的吞吐能力
Offset :消息在 partition内的相对位置信息,可以理解为唯一ID,在 partition内部严格递增。 (PS:多个partition有多个副本,达到容灾的作用)
Replica: 每个分片有多个 Replica,Leader Replica将会从ISR中选出。
- Leader:写入与读取
- Follower:从leader拉取数据,努力保持一致
- ISR(In-Sync Replicas):Follower与Leader差距过大会被踢出。若leader宕机,可从follower选一个替代
2.4 数据复制
2.5 KafKa架构
2.6 一条消息的自述
Producer -- (生产) --> Broker -- (消费) --> Consumer
从一条消息的视角,看看为什么 Kafka 能支撑这么高的吞吐?
思考:如果发送一条消息,等到其成功后再发一条会有什么问题?
2.7 Producer - 批量发送
思考题:如果消息量很大,网络带宽不够用,如何解决?
2.7 Producer - 数据压缩
2.8 Broker - 数据的存储
Broker 如何将数据存储到本地磁盘的?
数据路径:/Topic/Partition/Segment/(log | index | timeindex | ...)
2.8 Broker - 磁盘结构
移动磁头找到对应磁道,磁盘转动,找到对应扇区,最后写入。寻道成本比较高,因此顺序写可以减少寻道所带来的时间成本。
2.8 Broker - 顺序写
采用顺序写的方式进行写入,以提高写入效率
2.8 Broker - 如何找到消息
Consumer通过发送FetchRequest请求消息数据,Broker 会将指定Offset处的消息,按照时间窗口和消息 大小窗口发送给Consumer,寻找数据这个细节是如何做到的呢?
2.8 Broker - 偏移量索引文件
2.8 Broker - 时间戳索引文件
二分找到小于目标时间戳最大的索引位置,再通过寻找 offset的方式找到最终数据。
2.8 Broker - 传统数据拷贝
2.8 Broker - 零拷贝
2.9 Consumer - 消息的接收端
如何解决Partition在 Consumer Group中的分配问题?
- Low Level:通过手动进行分配,哪一个 Consumer消费哪一个 Partition完全由业务来决定。—— 缺点:1. Consumer挂掉就无了,不能自动容灾;2. 若Consumer能力不够要加一个,只能把原来的先停掉,业务数据中断。
- High Level:Coordinator自动分配
2.10 Consumer Rebalance
刚刚总共讲了哪一些可以帮助Kafka提高吞吐或者稳定性的功能?
- Producer:批量发送、数据压缩
- Broker:顺序写,消息索引,零拷贝
- Consumer: Rebalance
缺点:
2.11 KafKa - 数据复制问题
2.12 KafKa - 重启操作
2.13 KafKa - 替换、扩容、缩容
思考一下,替换,扩容,缩容的流程应该是怎样的?——均有数据复制的问题(时间成本)
2.12 KafKa - 负载不均衡
为了解决io问题引入了新的io问题
问题总结:
- 运维成本高
- 对于负载不均衡的场景,解决方案复杂
- 没有自己的缓存,完全依赖Page Cache
- Controller和 Coordinator和Broker 在同一进程中(既当Producer又当Consumer),大量IO会造成其性能下降
3. 消息队列-BMQ
3.1 BMQ简介
兼容Kafka协议(生产者消费者不用变),存算分离(底层分布式系统),云原生消息队列
BMQ介绍:
3.2 运维操作对比
3.3 HDFS写文件流程
3.4 BMQ文件结构
分配打散到多个Node
3.5 Broker - Partition 状态机
保证对于任意分片在同一时刻只能在一个 Broker上存活
3.5 Broker - 写文件流程
3.5 Broker - 写文件Fileover
如果DataNode节点挂了或者是其他原因导致我们写文件失败,应该如何处理?——找一个新的可用的节点写入
3.6 Proxy
Wait:eg.一个topic没有数据写入,Consumer会轮询发送request,一个topic有过多的consumer扛不住。Wait机制即proxy在没有数据时会在此处等待(一般会设置数据窗口、时间窗口)
3.7 多机房部署
防止机房故障
- Proxy在每个机房(每个分区)都会去处理全部的partition
- Broker加在一起才是全部(保证分区内数据的一致性)
3.8 BMQ - 高级特性
3.9 泳道消息
开发流程:开发 -> BOE -> PPE -> Prod
- BOE: Bytedance Offline Environment,是一套完全独立的线下机房环境
- PPE: Product Preview Environment,即产品预览环境
多个人同时测试,需要等待上一个人测试完成
每多一个测试人员,都需要重新搭建一个相同配置的Topic,造成人力和资源的浪费。
对于PPE的消费者来说,资源没有生产环境多,所以无法承受生产环境的流量。
解决主干泳道流量隔离问题以及泳道资源重复创建问题。(消息代标识,只在泳道内)
3.10 Databus
直接使用原生SDK会有什么问题?
- 客户端配置较为复杂
- 不支持动态配置,更改配置需要停掉服务
- 对于 latency 不是很敏感的业务,batch效果不佳
加入Agent代理,所有消息会先发到agent做大范围batch
- 简化消息队列客户端复杂度
- 解耦业务与Topic
- 缓解集群压力,提高吞吐
3.11 Mirror
思考一下,我们是否可以通过多机房部署的方式,解决跨Region(跨国、跨洲)读写的问题?
Proxy跨region访问broker时延很大
使用Mirror通过最终—致的方式(中间采用异步),解决跨Region读写问题。
3.12 Index
如果希望通过写入的 Logld、Userld 或者其他的业务字段进行消息的查询,应该怎么做(想把topic、MQ当数据库来用)?
3.13 Index
直接在 BMQ中将数据结构化,配置索引 DDL,异步构建索引后(不用通过什么时间戳的),通过Index Query 服务读出数据。
3.14 parquet
Apache Parquet是Hadoop生态圈中一种新型列式存储格式,它可以兼容Hadoop生态圈中大多数计算框架(Hadoop、Spark等),被多种查询引擎支持(Hive、lmpala、Drill等)。
消息即类似于行存
直接在BMQ中将数据结构化,通过 Parquet Engine,可以使用不同的方式构建 Parquet格式文件。(可采用列式存储用于某些场景如大数据)
小结:
- BMQ的架构模型解决Kafka存在的问题)
- BMQ读写流程(Failover机制,写入状态机)。
- BMQ高级特性(泳道、Databus、Mirror、Index、Parquet)
4. 消息队列-RocketMQ
使用场景:
例如,针对电商业务线,其业务涉及广泛,如注册、订单、库存、物流等;同时,也会涉及许多业务峰值时刻,如秒杀活动、周年庆、定期特惠等
4.1 RocketMQ 基本概念
4.2 RocketMQ架构
4.3 存储模型
ConsumerQueue(存入密集索引)
4.4 高级特性 - 事务场景
回忆ACID;一致性解决事务问题
4.4 高级特性 - 事务消息
4.4 高级特性 - 延迟发送
4.4 高级特性 - 处理失败
消息重试和死信队列
小结
- RocketMQ的基本概念(Queue,Tag)
- RocketMQ的底层原理(架构模型、存储模型)
- RocketMQ的高级特性(事务消息、重试和死信队列,延迟队列)
课程总结
- 前世今生:消息队列发展历程
- Kafka:基本概念、架构设计、底层原理、架构缺点
- BMQ:架构设计、底层原理、Kafka 比较、高级特性
- RocketMQ:架构设计、底层原理、高级特性