【消息队列】消息队列的前世今生-Kafka-BMQ-RocketMQ | 青训营笔记

161 阅读6分钟

这是我参与「第五届青训营」伴学笔记创作活动的第 11 天,今天学习的内容是关于消息队列的前世今生、Kafka、BMQ、RocketMQ,根据课程内容整理学习笔记如下。

9 消息队列原理与实战

9.1 消息队列是什么

9.1.1 四个应用场景

  • 解耦

image.png

  • 削峰

image.png

  • 异步

image.png

  • 日志处理

image.png

9.1.2 消息队列定义

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

image.png

9.2 消息队列的前世今生

9.2.1 消息队列发展历程

image.png

9.2.2 业界消息队列对比

image.png

9.3 消息队列 - Kafka

9.3.1 使用场景

  • 业务日志
  • 用户行为数据
  • Metrics数据(程序运行中程序状态信息,QPS/程序写入耗时等)

image.png

9.3.2 使用方法

创建集群 => 新增Topic => 编写生产者逻辑 => 编写消费者逻辑

9.3.3 基本概念

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

image.png

  • Offset:消息在partition内的相对位置信息,可以理解为唯一ID,在partition内部严格递增

image.png

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

    ISR作用:如果leader副本所在机器发生宕机,可在剩余ISR中选择继续服务

image.png

9.3.4 数据复制

image.png

9.3.5 Kafka架构

image.png

9.3.6 一条消息的处理流程

整体概览

image.png

Kafka提高吞吐量/稳定性的方法:

Producer:批量发送、数据压缩

Broker:顺序写,消息索引,零拷贝

Consumer:Rebalance

Producer端逻辑

批量发送 - 减少IO次数,从而增强发送能力

数据压缩 - 通过压缩,减少消息大小,目前支持Snappy、Gzip、LZ4、ZSTD

image.png

Broker端逻辑

数据的存储

image.png

Broker消息文件结构

image.png

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

image.png

消息索引 - Consumer通过发送FetchRequest请求消息数据,Broker会将指定Offset处的消息,按照时间窗口和消息大小窗口发送给Consumer

image.png

偏移量索引 - 稀疏索引(二分找到小于目标offset的最大索引位置)

image.png

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

image.png

传统数据拷贝(内核态&用户态) - 开销大

image.png

零拷贝(系统调用,读出后直接给网卡发送) - 减少了三次不必要的内存拷贝

image.png

Consumer端逻辑

消息接收端 - 需要解决Partition在Consumer Group中的分配问题(手动分配/自动分配)

image.png

手动分配 - Low Level(直接指定各个Consumer要拉取的Partition)

优点:速度快

缺点:当有Consumer出现问题,有部分消息无法被处理;当新增Consumer时,会存在数据中断问题

image.png

自动分配 - High Level(Rebalance

image.png

Consumer Rabalance

image.png

9.3.7 kafka问题

数据复制问题

重启操作(时间成本问题)

image.png

替换、扩容、缩容(时间成本问题)

image.png

负载均衡问题 - 尝试解决带来IO问题(死循环)

image.png

问题总结
  1. 运维成本高
  2. 对于负载不均衡的场景,解决方案复杂
  3. 没有自己的缓存,完全依赖Page Cache
  4. Controller和Coordinator和Broker在同一进程中,大量IO会造成其性能下降

9.4 消息队列 - BMQ

9.4.1 BMQ简介

采用kafka协议,存算分离,云原生消息队列

9.4.2 BMQ架构

image.png

9.4.3 运维操作对比

image.png

9.4.4 HDFS写文件流程

随机选择一定数量的DataNode进行写入

image.png

9.4.5 BMQ文件结构

每个Partition分为多个Segment,存放在不同DataNode中

image.png

9.4.6 Broker-Partition状态机

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

image.png

9.4.7 Broker模块

Broker写文件流程

image.png

Broker写文件Failover(重新找一个可用节点创建新Segment)

image.png

9.4.8 Proxy

image.png

Wait:等待,根据策略制定请求,减少频繁请求带来的IO压力

9.4.9 多机房部署

一个Proxy对Proxy的访问跨机房访问(保证分区内数据一致性)

多机房容灾

image.png

9.4.10 BMQ高级特性

image.png

开发流程相关

image.png

BOE (Bytedance Offline Environment):是一套完全独立的线下机房环境

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

image.png

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

image.png

PPE (Product Preview Environment):即产品预览环境

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

image.png

泳道消息

解决主干泳道流量隔离问题以及泳道资源重复创建问题

image.png

Databus

直接使用原生SDK的问题

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

image.png

使用Databus

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

image.png

Mirror

如何通过多机房部署方式,解决跨Region读写问题(跨国等业务)

image.png

使用Mirror通过最终一致的方式,解决跨Region读写问题

image.png

Index

希望通过写入的Logld、UserId或者其他的业务字段进行消息的查询

image.png

直接在BMQ中将数据结构化,配置索引DDL,异步构建索引后,通过Index Query服务读出数据

image.png

Parquet

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

image.png

直接在BMQ中将数据结构化,通过Parquet Engine,可以使用不同的方式构建Parquet格式文件

9.5 消息队列 - RocketMQ

9.5.1 使用场景

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

9.5.2 RocketMQ和Kafka对比

image.png

区别:

Tag字段 - 为了在Topic下还可以进行区分(如性别等),消费时提供更丰富的场景

Producer Group - 生产者组,为了支持事务消息

image.png

9.5.3 RocketMQ架构

image.png

Nameserver:向生产者消费者提供路由

9.5.4 存储模型

image.png

9.5.5 高级特性

事务场景

image.png

事务消息

image.png

延迟发送

image.png

image.png

消费重试和死信队列

image.png