消息队列学习笔记 | 青训营笔记

74 阅读6分钟

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

一、消息队列

1.1 为何要用消息队列

案例

案例一、系统崩溃

image.png 首先,请求会先到搜索商品这个服务上,并记录下你的搜索行为,然后点击商品的时候,又记录了我们的点击商品,这些数据最终都会通过计算分析,目的是为了下一次给你更准确的信息,这个时候问题来了,如果这个时候,负责记录存储的数据库被一个小哥删库跑路了。我们的所有操作都动不了了,这个时候我们应该怎么办?

案例二、服务能力有限

image.png

可以看到,一堆人都发起了订单请求,可是公司给的预算不够,服务器的配置太弱,订单服务只能同事处理10个订单请求。这个时候我们又该怎么办?

案例三、链路耗时长

image.png

一通分析,发现,库存服务和订单服务都挺快的,但是最后通知商家这一步咋这么慢,是不是还可以进行优化呀?

案例四、日志处理

在大家都抢到了自己心仪商品准备睡去的时候,在字节跳动的会议室里传出了悲伤的声音,因为刚刚有服务器坏掉了,我们的本地日志都丢掉了,没有了日志,我们还怎么去修复那些刚刚出现的那些问题,周围一片寂静,突然小张站出来缓缓的说了一句话,众人才露出了微笑准备下班离开,大家能猜到小张到底说的什么吗?

解决

案例一、解耦

image.png

案例二、削峰

image.png

案例三、异步

image.png 案例四、日志处理

image.png

1.2 消息队列

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

常用的消息队列如下:

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

二、Kafka

2.1 使用场景

image.png

2.2 如何使用

  1. 创建集群。首先需要创建一个Kafka集群。
  2. 新增Topic。需要在这个集群中创建一个Topic,并且设置好分片数量
  3. 编写生产者逻辑。引入对应语言的SDK,配置好集群和Topic等参数,初始化一个生产者,调用Send方法,将你的Hello World发送出去
  4. 编写消费者逻辑。引入对应语言的SDK,配置好集群和Topic等参数,初始化一个消费者,调用Poll方法,你将收到你刚刚发送的Hello World

2.3 基本概念

  • Topic:Kakfa中的逻辑队列,可以理解成每一个不同的业务场景就是一个不同的topic,对于这个业务来说,所有的数据都存储在这个topic中

  • Cluster:Kafka的物理集群,每个集群中可以新建多个不同的topic

  • Producer:顾名思义,也就是消息的生产端,负责将业务消息发送到Topic当中

  • Consumer:消息的消费端,负责消费已经发送到topic中的消息

  • Partition:通常topic会有多个分片,不同分片直接消息是可以并发来处理的,这样提高单个Topic的吞吐

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

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

    • Replica:分片的副本,分布在不同的机器上,可用来容灾,Leader对外服务,Follower异步去拉取leader的数据进行一个同步,如果leader挂掉了,可以将Follower提升成leader再堆外进行服务
    • ISR:意思是同步中的副本,对于Follower来说,始终和leader是有一定差距的,但当这个差距比较小的时候,我们就可以将这个follower副本加入到ISR中,不在ISR中的副本是不允许提升成Leader的

2.4 数据复制

image.png

下面这幅图代表着Kafka中副本的分布图。途中Broker代表每一个Kafka的节点,所有的Broker节点最终组成了一个集群。整个图表示,图中整个集群,包含了4个Broker机器节点,集群有两个Topic,分别是Topic1和Topic2,Topic1有两个分片,Topic2有1个分片,每个分片都是三副本的状态。这里中间有一个Broker同时也扮演了Controller的角色,Controller是整个集群的大脑,负责对副本和Broker进行分配

2.5 架构

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

2.6 一条消息的完整流程(可以帮助Kafka提高吞吐或者稳定性的功能)

producer

批量发送(可以减少IO次数,从而加强发送能力) + 数据压缩(解决消息量太大则网络带宽高要求的问题)

Broker

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

  • (接收)采用顺序写的方式进行写入,以提高写入效率

  • (发送)首先二分找到小于目标 offset的最大文件,随后二分找到小于目标 offset的最大索引位置,最后二分找到小于目标时间戳最大的索引位置,在通过寻找offset的方式找到最终数据。消息索引

  • (发送)零拷贝直接从系统的读缓冲区直接发送给网卡的缓冲区。

Consumer

消息的接收端

Partition在Consumer Group中的分配问题(Rebalance机制):

  • 方法一,通过手动进行分配,哪一个 Consumer 消费哪一个Partition完全由业务来决定。优点是比较快;缺点就是启停的情况,会导致业务中断。
  • 方法二,就是增加一个Coordinator,来协调分配。

2.7 缺点

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