消息队列与Kafka详解

一、消息队列的基本概念

1.1 什么是消息队列

消息队列(Message Queue,简称MQ),本质上就是一个队列 ,遵循FIFO(First In First Out)先入先出原则。只不过队列中存放的内容是Message(消息),因此得名"消息队列"。

复制代码
消息队列模型:

  生产者                              消费者
    │                                  ▲
    ▼                                  │
  [MSG1] ──► [    消息队列    ] ──► [Consumer]
  [MSG2] ──► [    (FIFO)     ] ──► [Consumer]
  [MSG3] ──► [              ] ──► [Consumer]

   写入顺序:MSG1 → MSG2 → MSG3
   消费顺序:MSG1 → MSG2 → MSG3

1.2 消息队列的主要用途

用途 说明 典型场景
异步处理 将同步调用拆分为异步消息传递,提升系统响应速度 用户下单后,订单服务发送消息,库存服务、短信服务异步处理
削峰填谷 缓解瞬时流量压力,平滑处理能力 秒杀场景下,订单请求先入队列,后端服务匀速消费
解耦服务 不同服务之间通过消息通信,互不依赖 网关接收请求,投递消息,后端服务独立处理
流量控制 通过队列最大长度限制,保护后端服务 设置消息队列最大数量,超出则拒绝或等待
日志服务 收集并处理海量日志 Kafka常用于日志采集、监控上报
发布订阅 同一消息可被多个消费者消费 课堂通知发给所有订阅的同学

1.3 点对点模型 vs 发布订阅模型

点对点模型(Point-to-Point):

复制代码
                        队列
  [Producer] ──────► [Queue] ──────► [Consumer]
                           (消息被消费后消失)

  特点:
  - 每条消息只能被一个消费者消费
  - 消费后队列中消息消失
  - 类似打电话,一对一

发布订阅模型(Publish-Subscribe):

复制代码
                        Topic
  [Producer] ──────► [Topic] ──────► [Consumer A]
                           │
                           ├─────► [Consumer B]
                           │
                           ├─────► [Consumer C]

  特点:
  - 每条消息可被多个消费者重复消费
  - 消费者相互独立,互不影响
  - 类似广播,发布者和订阅者彼此不认识

二、Kafka概述

2.1 Kafka是什么

Kafka是由Apache软件基金会开发的分布式消息队列系统,本质是一个MQ(Message Queue)。它被广泛应用于日志收集、消息流处理、事件源等场景。

2.2 为什么使用Kafka

优势 说明
解耦 允许独立扩展或修改生产者和消费者,两边互不影响
可恢复性 消息持久化到磁盘,进程挂掉后重启仍可继续处理
缓冲 解决生产速度和消费速度不一致的问题,起到蓄水池作用
峰值处理 关键组件顶住突发流量压力,不会因过载崩溃
异步通信 消息放入队列后无需立即处理,提升系统响应效率
高吞吐量 支持每秒百万级消息传输

三、Kafka核心概念与架构

3.1 核心术语一览

术语 解释
Broker Kafka服务器节点,多个Broker可以组成集群
Topic 消息主题,类似于消息的分类目录
Partition 分区,Topic物理上的划分,一个Topic可分为多个Partition
Replica 副本,分区的备份,保证高可用
Producer 消息生产者,负责发送消息到Kafka
Consumer 消息消费者,从Kafka拉取消息
Consumer Group 消费组,多个消费者组成,共同消费一个Topic
Offset 消息偏移量,每个Partition中消息的唯一序号

3.2 Kafka集群架构图

复制代码
                         Kafka集群
                         =========

  [Broker 1]             [Broker 2]             [Broker 3]
  ┌─────────┐            ┌─────────┐            ┌─────────┐
  │Topic-A  │            │Topic-A  │            │Topic-A  │
  │Part-0(L)│◄──副本────►│Part-1(L)│◄──副本────►│Part-2(L)│
  │Part-1(F)│            │Part-2(F)│            │Part-0(F)│
  └─────────┘            └─────────┘            └─────────┘
       ▲                       │                      │
       │                       ▼                      ▼
  [Producer] ─────────────► 写入Leader副本 ────────────────
                                 │
                    Leader副本分布在不同Broker上
                    Follower副本实时同步

说明:

  • L = Leader(主副本),F = Follower(从副本)
  • Kafka只往Leader副本写入数据,也只从Leader读取数据
  • 只有Leader失效时才会重新选举

3.3 Topic与Partition的关系

复制代码
Topic: 订单消息
├── Partition 0 ──► [MSG_A] [MSG_B] [MSG_E]    Offset: 0, 1, 2
├── Partition 1 ──► [MSG_C] [MSG_D] [MSG_F]    Offset: 0, 1, 2
└── Partition 2 ──► [MSG_G] [MSG_H]             Offset: 0, 1

分区策略示例(轮询):
MSG_A → Partition 0
MSG_B → Partition 1
MSG_C → Partition 2
MSG_D → Partition 0
MSG_E → Partition 1
...

特点:
- 分区数量决定了并行消费的能力
- 分区越多,吞吐率越高(但并非越多越好)
- 不同Partition之间无法保证消息顺序
- 同一Partition内保证FIFO顺序

3.4 分区副本机制

复制代码
副本分布示例(3个Broker,3副本):

Topic: 订单消息, Partitions: 3, ReplicationFactor: 3

Partition 0:  Leader@Broker1  Follower@Broker2  Follower@Broker3
Partition 1:  Leader@Broker2  Follower@Broker3  Follower@Broker1
Partition 2:  Leader@Broker3  Follower@Broker1  Follower@Broker2

写入流程:
1. Producer发送消息到Partition 0
2. 消息写入Broker1的Leader副本
3. Broker2、Broker3的Follower副本异步同步
4. Leader确认写入完成,返回ACK给Producer

选举机制:
- Leader失效 → 从该Partition的ISR(In-Sync Replicas)中选举新Leader
- Kafka提供多种ACK策略平衡可靠性与性能

3.5 消息的Offset机制

复制代码
Partition内部消息存储结构:

Offset:   0       1       2       3       4       5
        ┌───────┬───────┬───────┬───────┬───────┬───────┐
        │ MSG_A │ MSG_B │ MSG_C │ MSG_D │ MSG_E │ MSG_F │
        └───────┴───────┴───────┴───────┴───────┴───────┘
                                              ▲
                                        Consumer下次从这里消费

Consumer Group A 消费进度:
  Partition 0: committed_offset = 3  (已消费到Offset=2)
  Partition 1: committed_offset = 5  (已消费到Offset=4)
  Partition 2: committed_offset = 1  (已消费到Offset=0)

注意:
- 每个Partition有独立的Offset计数
- 不同Partition之间无法保证全局消息顺序
- 只能保证单个Partition内消息有序

四、Kafka分区分配策略

4.1 四种分区分配策略一览

策略 原理 特点
Range 按主题分区数除以消费者数,分配给每个消费者连续的分区 每个主题独立计算,多主题易不均
RoundRobin 将所有分区轮询分配给消费者 跨主题均匀分布
Sticky 首次分配均匀,Rebalance时尽量少移动分区 减少Rebalance开销
CooperativeSticky 增量协作式Rebalance,渐进式转移分区 最小化消息处理中断

4.2 Range(范围策略)

原理:

将每个主题的分区按编号排序,然后按消费者字典序排序。计算每个消费者应分配的分区数 = 分区总数 / 消费者数量(向下取整),剩余未分配的分区分给排在前面的消费者。

执行流程:

复制代码
场景:
- Topic: orders,共有6个分区 [P0, P1, P2, P3, P4, P5]
- Consumer Group: [Consumer-A, Consumer-B](2个消费者)
- 订阅主题:orders

计算过程:
1. 分区按编号排序:[P0, P1, P2, P3, P4, P5]
2. 消费者按字典序排序:[Consumer-A, Consumer-B]
3. 每消费者分配数 = 6 / 2 = 3(向下取整)

分配结果:
- Consumer-A: P0, P1, P2(连续)
- Consumer-B: P3, P4, P5(连续)

多主题场景下的缺陷:

复制代码
场景:
- Topic-A: 3个分区 [P0, P1, P2]
- Topic-B: 3个分区 [P0, P1, P2]
- Consumer Group: [Consumer-A, Consumer-B]

Topic-A分配:
- Consumer-A: P0, P1
- Consumer-B: P2

Topic-B分配:
- Consumer-A: P0, P1  ← 每个主题独立计算,容易出现不均
- Consumer-B: P2

结果:Consumer-A拿到了4个分区,Consumer-B只拿了2个

特点总结:

维度 描述
分配方式 每个主题独立计算,不跨主题均衡
优点 实现简单,理解直观
缺点 多主题下容易造成分区不均
适用场景 单一主题或主题数量少的场景

4.3 RoundRobin(轮询策略)

原理:

将所有主题的所有分区和所有消费者分别排序,然后轮询分配,每次给消费者分配一个分区,直到分配完毕。

执行流程:

复制代码
场景:
- Topic-A: [A-P0, A-P1, A-P2]
- Topic-B: [B-P0, B-P1, B-P2]
- Consumer Group: [Consumer-A, Consumer-B]

构建分区列表(按主题分区内编号排序):
[A-P0, A-P1, A-P2, B-P0, B-P1, B-P2]

轮询分配:
第1次: A-P0 → Consumer-A
第2次: A-P1 → Consumer-B
第3次: A-P2 → Consumer-A
第4次: B-P0 → Consumer-B
第5次: B-P1 → Consumer-A
第6次: B-P2 → Consumer-B

分配结果:
- Consumer-A: A-P0, A-P2, B-P1
- Consumer-B: A-P1, B-P0, B-P2

分区数相等,每个消费者3个,整体均匀

特点总结:

维度 描述
分配方式 跨所有主题分区轮询分配
优点 多主题场景下分配更均匀
缺点 可能打断同一主题分区的连续性
适用场景 消费者数量多、主题数量多的场景

4.4 Sticky(粘性策略)

原理:

在保证分区均匀分配的前提下,尽量保持原有的分配关系不变。首次分配时和RoundRobin类似,但发生Rebalance时,会尽量少移动分区,减少Rebalance开销。

初次分配表现:

复制代码
分区列表:[A-P0, A-P1, A-P2, B-P0, B-P1, B-P2]
消费者:[Consumer-A, Consumer-B]

初次分配(尽量均匀):
- Consumer-A: A-P0, A-P1, B-P0  ← 尝试保持"粘性"
- Consumer-B: A-P2, B-P1, B-P2

Rebalance时的优势:

复制代码
原分配(3个消费者):
- Consumer-A: P0, P1, P2
- Consumer-B: P3, P4, P5
- Consumer-C: (不存在)

新消费者Consumer-D加入,发生Rebalance:

非粘性策略(Range/RoundRobin):
- Consumer-A: P0, P1
- Consumer-B: P2, P3
- Consumer-C: P4, P5
- Consumer-D: (新加入,需要接管)
(所有分区几乎都要重新分配)

粘性策略:
- Consumer-A: P0, P1, P2  ← 保持不变
- Consumer-B: P3, P4      ← 释放P5
- Consumer-C: (保持不变)
- Consumer-D: P5         ← 只接管P5这一个

重分配开销对比:粘性策略移动更少分区

特点总结:

维度 描述
分配方式 尽量保持原有分配关系,最小化分区移动
优点 Rebalance时减少分区重分配范围,降低消息处理中断
缺点 实现复杂,分配结果不一定完全均匀
适用场景 生产环境首选,减少Rebalance影响

4.5 CooperativeSticky(协作粘性策略)

原理:

是Sticky策略的改进版本,采用增量协作式Rebalance。发生Rebalance时,不会一次性收回所有分区,而是渐进式地转移分区给新加入的消费者,对正在处理的消息影响最小。

执行流程:

复制代码
场景:
- 原消费者:[Consumer-A, Consumer-B]
- 新加入:Consumer-C

初始状态:
- Consumer-A: P0, P1, P2
- Consumer-B: P3, P4, P5

Rebalance第一阶段(增量迁移):
- Consumer-A: P0, P1      ← 释放P2
- Consumer-B: P3, P4, P5
- Consumer-C: P2         ← 渐进接管,不中断正在处理的消息

Rebalance第二阶段(继续调整):
- Consumer-A: P0, P1
- Consumer-B: P3, P4
- Consumer-C: P2, P5      ← 再次接管P5

最终:
- Consumer-A: P0, P1
- Consumer-B: P3, P4
- Consumer-C: P2, P5

对比普通Sticky的Rebalance:

复制代码
普通Sticky(Eager Rebalance):
- 所有消费者同时释放所有分区
- 所有分区重新分配
- 处理中的消息被中断,需重新处理

CooperativeSticky(增量协作):
- 消费者只释放部分分区
- 分区渐进式转移
- 处理中的消息继续完成,新消息开始使用新分配

特点总结:

维度 描述
分配方式 增量协作式Rebalance,渐进式转移分区
优点 最小化Rebalance对消息处理的影响
缺点 实现最复杂,收敛时间可能较长
适用场景 对消息处理连续性要求高的生产环境

4.6 四种策略对比总结

策略 分配范围 Rebalance行为 均匀性 生产推荐度
Range 单主题独立计算 全量重分配 单主题内均匀,多主题可能不均 一般
RoundRobin 全部分区轮询 全量重分配 整体较均匀 常用
Sticky 尽量保持原分配 最小化移动 基本均匀 推荐
CooperativeSticky 增量协作 分区渐进转移 基本均匀 最佳

4.7 实际配置方式

properties 复制代码
# Kafka 2.4+ 版本配置
partition.assignment.strategy=org.apache.kafka.clients.consumer.CooperativeStickyAssignor

# 可以配置多个策略,Kafka会按顺序尝试
partition.assignment.strategy=[org.apache.kafka.clients.consumer.CooperativeStickyAssignor,
                               org.apache.kafka.clients.consumer.RoundRobinAssignor]

五、Kafka消费模式

5.1 消费组的水平扩展

复制代码
场景:队列积压10万消息,单消费者1秒处理1万条

单消费者模式:
[Queue] ──► [Consumer] ──► 1万条/秒,积压10秒

扩展为10消费者:
[Queue] ──► [Consumer A] ──► 1万条/秒
           [Consumer B] ──► 1万条/秒
           [Consumer C] ──► 1万条/秒
           ...
           [Consumer J] ──► 1万条/秒
                            ─────────────────
                            合计:10万条/秒,实时处理

优势:
- 消费组内消费者可水平扩展
- 新增消费者自动触发Rebalance
- 类似线程池模型,灵活伸缩

5.2 同步 vs 异步发送

同步发送:

复制代码
Producer ──► 发送消息 ──► 等待ACK ──► 收到确认 ──► 发送下一条

特点:
- 每条消息等待上一条ACK后才发送
- 可靠性高,性能低
- 类似于请求-应答模式

异步发送:

复制代码
Producer ──► 发送消息 ──► [回调队列] ──► 继续发送下一条
                              │
                         后台线程处理ACK

特点:
- 不等待ACK立即返回
- 通过回调函数处理发送结果
- 性能高,可能丢失少量消息

六、消息队列关键特性

6.1 消息可靠性保障

环节 保障机制
持久化 消息写入磁盘,不依赖内存
副本 多副本冗余存储,Leader失效后自动选举
ACK确认 Producer发送后可选择ACK策略(0/1/all)
消费确认 Consumer处理完毕后提交Offset

ACK策略对比:

ACK策略 说明 可靠性 性能
acks=0 Producer不等任何回复就认为成功 低,可能丢消息 最高
acks=1 等待Leader副本写入完成 中,Leader失效可能丢消息
acks=all 等待所有ISR副本写入完成 高,几乎不丢消息

6.2 一致性策略

类型 说明 副本策略 特点
弱一致性 写入主副本即返回成功 只需主副本 性能高,可能丢数据
强一致性 所有副本都写入才返回成功 需要全部副本 可靠性高,性能较低
FastDFS弱一致性 同步给从副本但不等确认 部分同步 平衡性能和可靠性

6.3 消息消费的顺序性

场景 能否保证顺序 说明
单Partition单Consumer 保证顺序 FIFO
单Partition多Consumer 不保证顺序 并行消费打乱顺序
多Partition 不保证全局顺序 只保证Partition内有序

七、面试追问FAQ

问题 回答要点
Kafka为什么这么快? 顺序写磁盘、页缓存、零拷贝技术、批量处理、压缩消息
如何保证消息不丢失? 设置acks=all、副本数>=3、消费者手动提交Offset
如何保证消息不重复消费? 消费端做幂等性处理(如Redis去重、数据库唯一键)
如何保证消息顺序? 使用单Partition,或在消费端做消息排序
Consumer Group和Partition什么关系? 分区数>=消费者数,每个分区只能被一个消费者消费
Rebalance什么时候发生? 消费者加入或离开、订阅的Topic变化、分区数变化
如何解决热点Partition问题? 使用消息键(Key)分散到不同分区、合理设计Partition数
Kafka和RabbitMQ区别? Kafka高吞吐量适合大数据,RabbitMQ功能丰富适合业务消息

八、相关消息队列对比

特性 Kafka RabbitMQ ActiveMQ
吞吐量 百万级/秒 万级/秒 千级/秒
延迟 毫秒级 微妙级 毫秒级
消息持久化 支持 支持 支持
消息事务 支持 支持 支持
负载均衡 分区+副本 主从 主从
集群 原生支持 插件支持 插件支持
适用场景 日志、大数据 业务消息 小型系统
文档 丰富 丰富 一般

九、总结

维度 内容
本质 分布式消息队列,支持发布订阅和点对点两种模型
核心优势 高吞吐量、分布式持久化、水平扩展、多副本高可用
关键概念 Broker、Topic、Partition、Replica、Producer、Consumer、Offset
分区策略 Range、RoundRobin、Sticky、CooperativeSticky
可靠性 副本机制 + ACK确认 + 消费者Offset提交
顺序性 只保证单Partition内有序,多Partition需业务层处理
性能优化 批量发送、压缩消息、合理设置分区数、消费者水平扩展

根据零声教育教学写作https://github .com/0voice

相关推荐
鸿乃江边鸟3 小时前
Spark中怎么做Spark canonicalize归一化
大数据·分布式·spark
SLD_Allen4 小时前
Kafka分区与消费者的关系kafka分区和消费者线程的关系
分布式·kafka
he___H4 小时前
数据密集型应用系统设计--其一
分布式
珠***格6 小时前
Ⅱ型边缘网关|易部署、易扩容、易改造
大数据·人工智能·分布式·能源·边缘计算
无心水6 小时前
17、本地多模态|Qwen-VL离线私有化提取敏感PDF完全指南
人工智能·分布式·架构·openclaw·hermes
Solis程序员7 小时前
分布式 SingleFlight:从单机请求合并到集群级远程调用去重
分布式
填满你的记忆8 小时前
Kafka 面试题 Top40
分布式·kafka
oqX0Cazj28 小时前
Go-Zero数据库事务实战:本地事务+失败自动回滚+生产避坑+简单分布式事务方案
数据库·分布式·golang
团象科技8 小时前
出海技术团队分布式落地调研 海外云团队协作开发实操记录
分布式