消息队列原理与实战 | 青训营笔记

63 阅读8分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 9 天

内容来自掘金字节内部课程:消息队列前世今生消息队列-Kafka消息队列- BMQ消息队列- RocketMQ

一、本堂课重点内容:

  1. 消息队列发展历程
  2. 消息队列-Kafka
  3. 消息队列-BMQ
  4. 消息队列-RocketMQ

二、详细知识点介绍:

案例一:系统崩溃

image.png

image.png

案例二:服务能力有限

image.png

image.png

案例三:链路耗时长尾

image.png

image.png

案例四:日志存储如何处理

image.png

什么是消息队列?

消息队列(MQ),指保存消息的一个容器,本质是个队列。但这个队列呢,需要支持高吞吐,高并发,并且高可用。

image.png

1. 前世今生

消息队列发展历程

image.png

业界消息队列对比:

  • Kafka:分布式的、分区的、多副本的日志提交服务,在高吞吐场景下发挥较为出色
  • RocketMQ:低延迟、强一致、高性能、高可靠、万亿级容量和灵活的可扩展性,在一些实时场景中运用较广
  • Pulsar:是下一代云原生分布式消息流平台,集消息、存储、轻量化函数式计算为一体、采用存算分离的架构设计
  • BMQ:和Pulsar架构类似,存算分离,初期定位是承接高吞吐的离线业务场景,逐步替换掉对应的Kafka集群

2. 消息队列-Kafka

2.1 使用场景

image.png

2.2 如何使用KafKa

  1. 创建集群
  2. 新增Topic(设置分区数量)
  3. 编写生产者逻辑(上游、hello world)
  4. 编写消费者逻辑

2.3 基本概念

image.png

  • Topic:逻辑队列,不同Topic可以建立不同的Topic
  • Cluster:物理集群,每个集群中可以建立多个不同的Topic
  • Producer:生产者,负责将业务消息发送到Topic中
  • Consumer:消费者,负责消费Topic中的消息
  • ConsumerGroup:消费者组,不同组 Consumer消费进度互不干涉
  • partition: topic分区,多个分区消息可并发处理,来提高单个topic的吞吐能力

Offset :消息在 partition内的相对位置信息,可以理解为唯一ID,在 partition内部严格递增。 (PS:多个partition有多个副本,达到容灾的作用)

image.png

Replica: 每个分片有多个 Replica,Leader Replica将会从ISR中选出。

image.png

  • Leader:写入与读取
  • Follower:从leader拉取数据,努力保持一致
  • ISR(In-Sync Replicas):Follower与Leader差距过大会被踢出。若leader宕机,可从follower选一个替代

2.4 数据复制

image.png

2.5 KafKa架构

image.png

2.6 一条消息的自述

Producer -- (生产) --> Broker -- (消费) --> Consumer

从一条消息的视角,看看为什么 Kafka 能支撑这么高的吞吐?

image.png

思考:如果发送一条消息,等到其成功后再发一条会有什么问题?

2.7 Producer - 批量发送

image.png

思考题:如果消息量很大,网络带宽不够用,如何解决?

2.7 Producer - 数据压缩

image.png

2.8 Broker - 数据的存储

Broker 如何将数据存储到本地磁盘的?

image.png

数据路径:/Topic/Partition/Segment/(log | index | timeindex | ...)

2.8 Broker - 磁盘结构

移动磁头找到对应磁道,磁盘转动,找到对应扇区,最后写入。寻道成本比较高,因此顺序写可以减少寻道所带来的时间成本。

image.png

2.8 Broker - 顺序写

image.png

采用顺序写的方式进行写入,以提高写入效率

2.8 Broker - 如何找到消息

Consumer通过发送FetchRequest请求消息数据,Broker 会将指定Offset处的消息,按照时间窗口和消息 大小窗口发送给Consumer,寻找数据这个细节是如何做到的呢?

2.8 Broker - 偏移量索引文件

image.png

image.png

2.8 Broker - 时间戳索引文件

二分找到小于目标时间戳最大的索引位置,再通过寻找 offset的方式找到最终数据。

2.8 Broker - 传统数据拷贝

image.png

2.8 Broker - 零拷贝

image.png

2.9 Consumer - 消息的接收端

image.png

如何解决Partition在 Consumer Group中的分配问题?

  • Low Level:通过手动进行分配,哪一个 Consumer消费哪一个 Partition完全由业务来决定。—— 缺点:1. Consumer挂掉就无了,不能自动容灾;2. 若Consumer能力不够要加一个,只能把原来的先停掉,业务数据中断。
  • High Level:Coordinator自动分配

image.png

2.10 Consumer Rebalance

image.png

刚刚总共讲了哪一些可以帮助Kafka提高吞吐或者稳定性的功能?

  • Producer:批量发送、数据压缩
  • Broker:顺序写,消息索引,零拷贝
  • Consumer: Rebalance

缺点:

2.11 KafKa - 数据复制问题

2.12 KafKa - 重启操作

image.png

2.13 KafKa - 替换、扩容、缩容

思考一下,替换,扩容,缩容的流程应该是怎样的?——均有数据复制的问题(时间成本)

2.12 KafKa - 负载不均衡

image.png

为了解决io问题引入了新的io问题

image.png

问题总结:

  • 运维成本高
  • 对于负载不均衡的场景,解决方案复杂
  • 没有自己的缓存,完全依赖Page Cache
  • Controller和 Coordinator和Broker 在同一进程中(既当Producer又当Consumer),大量IO会造成其性能下降

3. 消息队列-BMQ

3.1 BMQ简介

兼容Kafka协议(生产者消费者不用变),存算分离(底层分布式系统),云原生消息队列

BMQ介绍:

image.png

3.2 运维操作对比

image.png

3.3 HDFS写文件流程

image.png

3.4 BMQ文件结构

分配打散到多个Node

image.png

3.5 Broker - Partition 状态机

image.png

保证对于任意分片在同一时刻只能在一个 Broker上存活

3.5 Broker - 写文件流程

image.png

3.5 Broker - 写文件Fileover

image.png

如果DataNode节点挂了或者是其他原因导致我们写文件失败,应该如何处理?——找一个新的可用的节点写入

3.6 Proxy

image.png

Wait:eg.一个topic没有数据写入,Consumer会轮询发送request,一个topic有过多的consumer扛不住。Wait机制即proxy在没有数据时会在此处等待(一般会设置数据窗口、时间窗口)

3.7 多机房部署

防止机房故障

image.png

  • Proxy在每个机房(每个分区)都会去处理全部的partition
  • Broker加在一起才是全部(保证分区内数据的一致性)

3.8 BMQ - 高级特性

image.png

3.9 泳道消息

开发流程:开发 -> BOE -> PPE -> Prod

  • BOE: Bytedance Offline Environment,是一套完全独立的线下机房环境
  • PPE: Product Preview Environment,即产品预览环境

image.png

多个人同时测试,需要等待上一个人测试完成

image.png

每多一个测试人员,都需要重新搭建一个相同配置的Topic,造成人力和资源的浪费。

image.png

对于PPE的消费者来说,资源没有生产环境多,所以无法承受生产环境的流量。

image.png

解决主干泳道流量隔离问题以及泳道资源重复创建问题。(消息代标识,只在泳道内)

3.10 Databus

直接使用原生SDK会有什么问题?

  • 客户端配置较为复杂
  • 不支持动态配置,更改配置需要停掉服务
  • 对于 latency 不是很敏感的业务,batch效果不佳

image.png

加入Agent代理,所有消息会先发到agent做大范围batch

  1. 简化消息队列客户端复杂度
  2. 解耦业务与Topic
  3. 缓解集群压力,提高吞吐

3.11 Mirror

思考一下,我们是否可以通过多机房部署的方式,解决跨Region(跨国、跨洲)读写的问题?

image.png

Proxy跨region访问broker时延很大

image.png

使用Mirror通过最终—致的方式(中间采用异步),解决跨Region读写问题。

3.12 Index

image.png

如果希望通过写入的 Logld、Userld 或者其他的业务字段进行消息的查询,应该怎么做(想把topic、MQ当数据库来用)?

3.13 Index

image.png

直接在 BMQ中将数据结构化,配置索引 DDL,异步构建索引后(不用通过什么时间戳的),通过Index Query 服务读出数据。

3.14 parquet

Apache Parquet是Hadoop生态圈中一种新型列式存储格式,它可以兼容Hadoop生态圈中大多数计算框架(Hadoop、Spark等),被多种查询引擎支持(Hive、lmpala、Drill等)。

image.png

消息即类似于行存

image.png

直接在BMQ中将数据结构化,通过 Parquet Engine,可以使用不同的方式构建 Parquet格式文件。(可采用列式存储用于某些场景如大数据)

小结:

  1. BMQ的架构模型解决Kafka存在的问题)
  2. BMQ读写流程(Failover机制,写入状态机)。
  3. BMQ高级特性(泳道、Databus、Mirror、Index、Parquet)

4. 消息队列-RocketMQ

使用场景:

例如,针对电商业务线,其业务涉及广泛,如注册、订单、库存、物流等;同时,也会涉及许多业务峰值时刻,如秒杀活动、周年庆、定期特惠等

4.1 RocketMQ 基本概念

image.png

image.png

4.2 RocketMQ架构

image.png

4.3 存储模型

image.png

ConsumerQueue(存入密集索引)

4.4 高级特性 - 事务场景

image.png

回忆ACID;一致性解决事务问题

4.4 高级特性 - 事务消息

image.png

4.4 高级特性 - 延迟发送

image.png

image.png

4.4 高级特性 - 处理失败

image.png

消息重试和死信队列

image.png

小结

  1. RocketMQ的基本概念(Queue,Tag)
  2. RocketMQ的底层原理(架构模型、存储模型)
  3. RocketMQ的高级特性(事务消息、重试和死信队列,延迟队列)

课程总结

  • 前世今生:消息队列发展历程
  • Kafka:基本概念、架构设计、底层原理、架构缺点
  • BMQ:架构设计、底层原理、Kafka 比较、高级特性
  • RocketMQ:架构设计、底层原理、高级特性