消息队列重点知识 | 青训营笔记

56 阅读6分钟

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

这节课对消息队列技术的历史及其演进做了简要介绍,同时介绍了 Kafka, BMQ 和 RocketMQ 的内部架构及其高级特性。

消息队列概述

什么是消息队列?

消息队列范例是发布者/订阅者模式的同级,通常是更大的面向消息的中间件系统的一部分。大多数消息传递系统在其API中同时支持发布者/订阅者和消息队列模型,例如Java消息服务(JMS)。

本质上,消息队列(MQ)是一个支持高吞吐,高并发和高可用的队列(Queue)。

消息队列解决的问题

系统解耦、冗余存储、流量削峰、缓冲、异步通信......

消息队列的发展历史

  • TIB(诞生于 1985 年,服务于金融机构和新闻机构)
  • IBM MQ/WebSphere(诞生于 1993 年,商业消息队列平台市场主要玩家)
  • MSMQ(微软发布于 1997 年)
  • JMS(诞生于 2001 年,本质上是一套 Java API)
  • AMQP/RabbitMQ(规范发布于 2004 年,同年 RabbitMQ 面世)
  • Kafka(2010 年由 Linked 开源)
  • RocketMQ(2011 年阿里中间件团队自研)
  • Pulsar(2012 年诞生于 Yahoo 内部)

常用的4种消息队列对比

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

Kafka

基本概念

  • Topic: 逻辑队列,不同Topic可以建立不同的Topic
  • Cluster: 物理集群,每个集群中可以建立多个不同的Topic
  • Producer: 生产者,负责将业务消息发送到Topic中
  • Consumer: 消费者,负责消费Topic中的消息
  • ConsumerGroup: 消费者组,不同组Consumer消费进度互不干涉

Cluster/Topic

Offset: 对于每一个Partition来说,每一条消息都有一个唯一的Offset,消息在partition内的相对位置信息,并且严格递增。

Replica: 分片的副本,分布在不同的机器上,可用来容灾,Leader对外服务,Follower异步去拉取leader的数据进行一个同步,如果leader挂掉了,可以将Follower提升成leader再堆外进行服务。

ISR: 意思是同步中的副本,对于Follower来说,始终和leader是有一定差距的,但当这个差距比较小的时候,我们就可以将这个follower副本加入到ISR中,不在ISR中的副本是不允许提升成Leader的。

上面这幅图代表着Kafka中副本的分布图。图中Broker代表每一个Kafka的节点,所有的Broker节点最终组成了一个集群。

整个图表示,图中整个集群,包含了4个Broker机器节点,集群有两个Topic,分别是Topic1和Topic2,Topic1有两个分片,Topic2有1个分片,每个分片都是三副本的状态。

这里中间有一个Broker同时也扮演了Controller的角色,Controller是整个集群的大脑,负责对副本和Broker进行分配。

而在集群的基础上,还有一个模块是ZooKeeper,这个模块其实是存储了集群的元数据信息,比如副本的分配信息等等,Controller计算好的方案都会放到这个地方。

Producer

  • 批量发送可以减少IO次数,从而加强发送能力。
  • 通过压缩,减少消息大小,目前支持Snappy、Gzip、LZ4、ZSTD压缩算法。

Broker

消息文件结构:

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

Broker如何找到消息:

  • 偏移量索引文件
  • 时间戳索引文件

零拷贝:

  • Consumer从Broker中读取数据,通过sendfile的方式,将磁盘读到os内核缓冲区后,直接转到socket buffer进行网络发送。
  • Producer生产的数据持久化到broker,采用mmap文件映射,实现顺序的快速写入。

Consumer

Rebalance:Kafka也提供了自动分配的方式,这里也叫做High Level的消费方式,简单的来说,就是在我们的Broker集群中,对于不同的Consumer Group来讲,都会选取一台Broker当做Coordinator,而Coordinator的作用就是帮助Consumer Group进行分片的分配,也叫做分片的rebalance,使用这种方式,如果ConsumerGroup中有发生宕机,或者有新的Consumer加入,整个partition和Consumer都会重新进行分配来达到一个稳定的消费状态。

Kafka的缺点

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

BMQ

BMQ兼容Kafka协议,存算分离,云原生消息队列,初期定位是承接高吞吐的离线业务场景,逐步替换掉对应的Kafka集群。

Producer -> Consumer -> Proxy -> Broker -> HDFS -> Controller -> Coordinator -> Meta

Broker写文件操作

  • 数据校验:CRC , 参数是否合法。
  • 校验完成后,会把数据放入Buffer中。
  • 通过一个异步的Write Thread线程将数据最终写入到底层的存储系统当中。
  • 这里有一个地方需要注意一下,就是对于业务的写入来说,可以配置返回方式,可以在写完缓存之后直接返回,另外我也可以数据真正写入存储系统后再返回,对于这两个来说前者损失了数据的可靠性,带来了吞吐性能的优势,因为只写入内存是比较快的,但如果在下一次flush前发生宕机了,这个时候数据就有可能丢失了,后者的话,因为数据已经写入了存储系统,这个时候也不需要担心数据丢失,相应的来说吞吐就会小一些。
  • 我们再来看看Thread的具体逻辑,首先会将Buffer中的数据取出来,调用底层写入逻辑,在一定的时间周期上去flush,flush完成后开始建立Index,也就是offset和timestamp对于消息具体位置的映射关系。
  • Index建立好以后,会save一次checkpoint,也就表示,checkpoint后的数据是可以被消费的辣,我们想一下,如果没有checkpoint的情况下会发生什么问题,如果flush完成之后宕机,index还没有建立,这个数据是不应该被消费的。
  • 最后当文件到达一定大小之后,需要建立一个新的segment文件来写入。

BMQ各模块是如何工作的,Broker、Proxy、HDFS、MetaStorage

BMQ多机房容灾

BMQ 高级特性 (泳道、Databus、Mirror、Index、 Parquet)

RocketMQ

与Kafka的对比