消息队列 | 青训营笔记

73 阅读5分钟

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

前言

1.系统崩溃

image.png
解决方案

image.png

2.服务器能力有限,如何面对庞大请求量

image.png
解决方案——削峰

image.png 3.链路耗时长尾

image.png
解决方案——异步

image.png 4.日志处理,本地日志丢失? 解决方案

image.png

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

发展历程

image.png

常见的消息队列

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

Kafka

如何使用Kafka

image.png

基本概念

  • Cluster:物理集群,每个集群中可以建立多个不同的Topic
  • Producer:生产者,负责将业务消息发送到Topic中
  • Consumer:消费者,负责消费Topic中的消息
  • ConsumerGroup:消费者组,不同组 Consumer消费进度互不干涉
  • Topic:逻辑队列,可以理解为一个队列,生产者和消费者都是面向一个Topic
  • Partition:分区,一个Topic可以分为多个Partition,每个Partition是一个有序的队列(分区有序,不能保证全局有序)
  • Offset:消息在partition 内的相对位置信息,可以理解为唯一ID,在partition内部严格递增。 image.png
  • Replica:副本Replication,为保证集群中某个节点发生故障,节点上的Partition数据不丢失,Kafka可以正常的工作,Kafka提供了副本机制,一个Topic的每个分区有若干个副本,一个Leader和多个Follower image.png
  • Broker:一台Kafka服务器就是一个Broker,一个集群由多个Broker组成,一个Broker可以容纳多个Topic。一个非常大的Topic可以分为多个Partition并分布到多个Broker上。

image.png

Kafka架构

image.png

Produce

生产者要向Kafka中发送消息 如果等一个消息发送成功后发送消息会怎样? 传输效率低 image.png 那么如果单个消息量很大(比如1mb,那么批量发送1k个消息就很大),网络带宽不够用如何解决?

image.png 通过压缩,减少消息大小,目前支持Snappy、Gzip、LZ4、ZSTD压缩算法

Broker消息文件结构

消息发送到Broker后,Broker又是如何存储数据?

image.png
副本最终以相应的log与index等文件保存具体的消息文件。生产者不断的向log文件追加消息文件,为了防止log文件过大导致定位效率低下。Kafka 又引入了日志分段(LogSegment)的概念,将 Log 切分为多个 LogSegment,相当于一个巨型文件被平均分配为多个相对较小的文件,这样也便于消息的维护和清理。事实上,Log 和 LogSegment 也不是纯粹物理意义上的概念,Log 在物理上只以文件夹的形式存储,而每个 LogSegment 对应于磁盘上的一个日志文件(.log日志文件)和两个索引文件(.index偏离量索引文件,.timeindex时间戳索引文件),以及可能的其他文件 image.png

Broker又是如何找到消息的?
Consumer通过发送FetchRequest请求消息数据,Broker 会将指定Offset处的消息,按照时间窗口和消息 大小窗口发送给Consumer,寻找数据这个细节是如何做到的呢? 1.二分找到小于目标offset的最大文件

image.png 2.在该文件中二分找到小于目标offset的最大位置

image.png

Consumer

消息的接收端

image.png 如何解决Partition在 Consumer Group中的分配问题? consumer rebalance image.png

Kafka重启操作

image.png

BMQ

BMQ是字节跳动用C++重写的一套存算分离架构的消息队列服务

RocketMQ

image.png

NameService

Name Server是一个几乎无状态节点,可集群部署,节点之间无任何信息同步。
NameServer 是整个 RocketMQ 的“大脑” NameServer)用来保存 Broker 相关元信息并给 Producer 和 Consumer 查找Broker 信息。它是 RocketMQ 的服务注册中心,所以 RocketMQ 需要先启动 NameServer 再启动Rocket中的 Broker。
每个 Broker 在启动的时候会到 NameServer 注册,Producer 在发送消息前会根据 Topic 到NameServer 获取到 Broker 的路由信息,进而和Broker取得连接。Consumer 也会定时获取 Topic 的路由信息。

和Zookeeper的区别

Name Server和ZooKeeper的作用大致是相同的,从宏观上来看,Name Server做的东西很少,就是保存一些运行数据,Name Server之间不互连,这就需要broker端连接所有的Name Server,运行数据的改动要发送到每一个Name Server来保证运行数据的一致性(这个一致性确实有点弱),这样就变成了Name Server很轻量级,但是broker端就要做更多的东西了。
而ZooKeeper,broker只需要连接其中的一台机器,运行数据分发、一致性都交给了ZooKeeper来完成。

Broker

Broker 有 Master 和 Slave 两种类型,Master既可以写又可以读,Slave不可以写只可以读。
Broker分为Master与Slave,一个Master可以对应多个Slave,但是一个Slave只能对应一个Master,Master与Slave的对应关系通过指定相同的Broker Name,不同的BrokerId来定义,BrokerId为0表Master,非0表示Slave。Master也可以部署多个。

高可用

每个Broker与Name Server集群中的所有节点建立长连接,定时(每隔30s)注册Topic信息到所有Name Server。Name Server定时(每隔10s)扫描所有存活broker的连接,如果Name Server超过2分钟没有收到心跳,则Name Server断开与Broker的连接。

与Kafka对比

image.png