了解Kafka

什么是Kafka

Kafka 是一款高吞吐量的分布式消息队列

Apache Kafka是分布式发布-订阅消息系统,Kafka最初由LinkedIn公司开发,Linkedin于2010年贡献给了Apache基金会并成为顶级开源项目。

初衷是解决 “大规模实时数据传输与存储” 问题,因此它的设计更偏向 “高吞吐、可持久化、分布式” 的日志系统,而消息队列只是其核心功能之一。

kafka每秒可以处理几十万条消息,它的延迟最低只有几毫秒。而且kafka集群支持热扩展,同时支持数千个客户端同时读,拥有很好的高并发。

简单说:RabbitMQ 更像 “快递中转站”(强调消息路由、即时投递),而 Kafka 更像 “大型仓库”(强调批量存储、高效读写)。

所以开发中,Kafka多使用在

  1. 日志收集:多服务的日志实时写入 Kafka,下游消费端(如 ELK)统一处理分析;
  2. 实时数据管道:数据库变更数据(CDC)通过 Kafka 同步到数据仓库、缓存或其他系统;
  3. 实时计算:作为 Flink/Spark Streaming 的数据源,支撑实时数据分析(如实时报表、监控告警);
  4. 高吞吐消息通信:秒杀、大促等场景下,用 Kafka 缓冲峰值流量,避免下游服务被压垮。

作为MQ有什么特点

Kafka作为 MQ 的核心特点是超高吞吐量,适合大数据场景

  • 设计支撑
    • 消息采用 磁盘顺序写入(而非内存随机读写),配合操作系统的页缓存(Page Cache),写入性能远超内存操作(避免频繁 GC 问题)。
    • 消息分 分区(Partition) 存储,分布式并行读写(类似数据库分表),吞吐量随集群规模线性扩展。
  • 数据对比
    • Kafka 单节点吞吐量轻松达到 10 万 +/ 秒(甚至更高),而 RabbitMQ 通常在 万级 / 秒(受限于内存和交换机路由开销)。
  • 适用场景:日志收集(如 ELK 栈)、大数据同步(如 Flink/Spark 实时计算)、海量用户行为追踪等。

在消息持久化上,有这样的特点

  • 消息默认写入磁盘(可配置持久化策略),且支持 多副本(Replication) 存储(分区数据复制到多个节点),即使某节点宕机,数据也不丢失。

  • 持久化文件按 segment 分段 存储,方便过期删除(按时间 / 大小自动清理,适合日志等 “过期无效” 的数据)。

  • 与 RabbitMQ 对比:

    • RabbitMQ 也支持持久化,但默认依赖内存,大量消息堆积时容易触发内存告警,需频繁刷盘,性能下降明显;
    • Kafka 从设计上就以磁盘为核心,天然适合海量消息长期存储。

而在消费模型上,kafka使用“拉取式”+“偏移量(Offset)”,这是 Kafka 与 RabbitMQ 最核心的差异之一,直接影响消费灵活性和吞吐量:

  • 拉取式消费(Pull):
    • 消费者主动从 Kafka 拉取消息(可自主控制速率),避免 RabbitMQ“推模式(Push)” 可能导致的消费者过载问题(尤其是消费者处理能力不足时)。
  • 偏移量(Offset):
    • 每个消费者组(Consumer Group)对每个分区的消费进度用 Offset 记录(本质是一个整数,代表已消费到第几条消息)。
    • 消费者可通过修改 Offset 实现 重复消费、跳过消费、回溯消费(例如:数据处理失败后,重新从指定位置消费)。
  • 与 RabbitMQ 对比:
    • RabbitMQ 采用 “推模式”,消息被消费后默认从队列删除(需手动 ACK 确认),不记录消费进度,无法直接回溯;
    • Kafka 的 Offset 机制让消费更灵活,尤其适合需要重放历史数据的场景(如数据重算、故障恢复)。

消费者组(Consumer Group),kafka分布式消费的核心

  • 定义:多个消费者组成一个 “消费者组”,共同消费一个主题(Topic)的消息,同一条消息只会被组内一个消费者消费(类似 RabbitMQ 的 “工作队列模式”,但更强大)。
  • 分区与消费的绑定:
    • 主题的每个分区只能被消费者组内的 一个消费者 消费(反之,一个消费者可消费多个分区)。
    • 例:主题有 3 个分区,消费者组有 2 个消费者,则可能 “消费者 1 消费分区 0/1,消费者 2 消费分区 2”,实现负载均衡。
  • 优势:
    • 轻松实现分布式消费(增加消费者数量即可提高消费能力,前提是分区数 ≥ 消费者数);
    • 不同消费者组可独立消费同一主题的消息(互不干扰),适合 “一条消息被多系统处理” 的场景(类似 RabbitMQ 的 “扇形交换机”,但更高效)。

Kafka使用主题(Topic)与分区(Partition)作为数据组织的核心

  • 主题(Topic):消息的逻辑分类(类似 RabbitMQ 的 “队列”,但更灵活),生产者向 Topic 发送消息,消费者从 Topic 消费。
  • 分区(Partition):
    • 每个 Topic 可分为多个分区(物理存储单元),消息按一定规则(默认轮询或指定 Key)分配到不同分区,实现并行读写。
    • 分区内的消息是 有序的(按写入顺序),但跨分区无序(若需全局有序,需将 Topic 设为单分区)。
  • 与 RabbitMQ 对比:
    • RabbitMQ 的队列是 “单队列单存储”,消息有序但吞吐量受限;
    • Kafka 用分区实现 “并行化”,牺牲全局有序换取高吞吐,更适合大数据场景。

Kafka 的弱路由也是其重要特点之一,实现了简化设计,专注于吞吐

Kafka 的消息路由非常简单:生产者直接指定 Topic(最多通过 Key 路由到分区),没有 RabbitMQ 中 “交换机(Exchange)+ 绑定键(Binding Key)+ 路由键(Routing Key)” 的复杂路由规则(如扇出、主题匹配、 headers 匹配等)。

  • 优势:减少路由计算开销,提高吞吐量;
  • 劣势:灵活度低,复杂路由需在业务层实现。

Kafka对比RabbitMQ

首先要知道,Kafka 不是 “RabbitMQ 的升级版”,而是 “为不同场景设计的产品”,天天都有人说 RabbitMQ 不如 Kafka 一根,我真晕了

核心差异

一表说明核心差异

维度 Kafka RabbitMQ
吞吐量 极高(十万级 / 秒),适合大数据 中等(万级 / 秒),适合中小规模
消息模型 基于 Topic + 分区,拉取式 + Offset 基于队列 + 交换机,推模式 + ACK
路由能力 简单(仅 Topic/Key 路由) 强大(多种交换机类型,灵活路由)
持久化 磁盘优先,天然支持海量存储 内存优先,大量堆积易性能下降
消费灵活性 支持回溯、重复消费(Offset 控制) 消费后默认删除,回溯困难
适用场景 日志收集、大数据同步、实时计算 业务解耦、即时通信、复杂路由场景

本质上的差异我们可以这样理解

产品 核心定位 类比场景 设计优先级
RabbitMQ 通用型消息队列(AMQP 协议实现) 快递中转站(精准投递) 灵活性 > 吞吐量 > 持久化
Kafka 分布式日志系统(兼顾 MQ 功能) 大型仓库(批量存储 + 分发) 吞吐量 > 持久化 > 灵活性
  • RabbitMQ 追求 “消息投递的精准与灵活”(比如支持多种路由规则、即时 ACK 确认),适合业务层的 “解耦通信”;

  • Kafka 追求 “海量数据的高效存储与传输”(比如磁盘顺序读写、分区并行),适合 “大数据场景”(日志、实时计算)。

设计和工作流程

我们在前面学习了 RabbitMQ,反正都是消息队列,借助RabbitMQ的设计理念,我们这样对比着先看一下Kafka的基本概念

RabbitMQ 概念 Kafka 对应概念 核心差异说明
队列(Queue) 主题(Topic)+ 分区(Partition) RabbitMQ 的 Queue 是 “物理存储单元”,一个 Queue 对应一个存储队列;Kafka 的 Topic 是 “逻辑分类”,物理存储靠 Partition(一个 Topic 可拆成多个 Partition)。
交换机(Exchange) 无(或简化为 Topic/Key) RabbitMQ 靠 Exchange 实现复杂路由(扇出、主题匹配等);Kafka 无 Exchange,路由仅靠 “Topic 名称” 或 “消息 Key”(Key 相同的消息进入同一 Partition)。
消费者(Consumer) 消费者组(Consumer Group)成员 RabbitMQ 单个消费者独立消费一个 Queue;Kafka 消费者必须属于某个 Group,Group 内消费者共同消费 Topic(同一条消息仅被 Group 内一个消费者消费)。
消息 ACK 偏移量(Offset) RabbitMQ 靠 ACK 确认 “消息已消费”,确认后消息从 Queue 删除;Kafka 靠 Offset 记录 “消费进度”,消息不删除,消费者可通过修改 Offset 回溯 / 重复消费。
持久化(Durability) 分区副本(Replication) RabbitMQ 持久化需手动开启(Queue + 消息都设为持久化),大量堆积易性能下降;Kafka 消息默认写入磁盘,且支持多副本(Partition 数据复制到多个节点),天然抗故障。

RabbitMQ 中 “一个 Queue 对应一个消费者组”,而 Kafka 中 “一个 Topic 可对应多个 Consumer Group”(每个 Group 独立消费)

Offset 和 Consumer Group,这两个是 Kafka 消费模型的核心 —— Offset 决定 “消费到哪”,Consumer Group 决定 “谁来消费”,理解这两个概念,就能解决 80% 的消费相关问题。

我们以 用户下单 → 生产者发送 “订单消息” → 消费者接收消息并发送短信通知 为例子,说明 Kafka 和 RabbitMQ 之间消息流转的差异

RabbitMQ

graph LR
A[生产者(订单服务)] -->|1. 发送消息+RoutingKey=“order.notify”| B[Exchange(类型:Direct)]
B -->|2. 按 RoutingKey 匹配绑定| C[Queue(“sms-queue”)]
C -->|3. 推送给消费者| D[消费者(短信服务)]
D -->|4. 发送 ACK| C[Queue(“sms-queue”)]
C -->|5. 收到 ACK 后删除消息| E[消息删除]
  • 路由依赖 Exchange + RoutingKey,灵活但有额外开销;
  • 消息是 “推模式”(Queue 主动推给消费者),消费者处理慢时易过载;
  • 消息消费后立即删除,无法回溯(除非手动备份)。

Kafka

graph LR
A[生产者(订单服务)] -->|1. 发送消息到 Topic=“order-topic”+Key=“user123”| B[Topic(“order-topic”)]
B -->|2. 按 Key 分配到 Partition 0| C[Partition 0(磁盘存储)]
C -->|3. 消费者组(“sms-group”)的消费者 1 主动拉取| D[消费者 1(短信服务)]
D -->|4. 消费后更新 Offset=100(记录已消费到第 100 条)| E[Offset 存储(Kafka 或本地)]
C -->|5. 消息保留(按时间/大小清理,默认保留 7 天)| F[消息持久化]
  • 无 Exchange,路由仅靠 Topic 名称,简单高效;
  • 消息是 “拉模式”(消费者主动从 Partition 拉取),可自主控制消费速率(避免过载);
  • 消息不删除,消费者可通过修改 Offset 重新消费(比如短信发送失败,重新拉取 Offset=99 的消息)。

吞吐能力

Kafka 的优势是高吞吐,为什么 Kafka 适合高吞吐,而 RabbitMQ 就没这么高

对比维度 RabbitMQ Kafka
存储方式 内存优先(消息先放内存,定期刷盘) 磁盘优先(消息直接写入磁盘,用操作系统页缓存加速)
读写模式 随机读写(消息从内存 / 磁盘随机读取) 顺序写入(消息按顺序追加到 Partition 末尾,磁盘顺序读写性能 ≈ 内存)
并行能力 单 Queue 单线程读写,并行依赖多 Queue 多 Partition 并行读写(一个 Topic 拆成 N 个 Partition,N 个线程同时处理)
实际吞吐量 单节点 ≈ 1-5 万条 / 秒 单节点 ≈ 10-50 万条 / 秒(甚至更高)

消费能力

而 RabbitMQ 出现消费失败后需手动将消息重新放入 Queue,而 Kafka 能直接将 Offset 回退到失败前的位置,重新拉取

也就是说,Kafka 支持 “回溯消费”,RabbitMQ 不支持,这是两者在 “消费能力” 上的核心差异

场景需求 RabbitMQ 处理方式 Kafka 处理方式
消费失败后重新处理 需手动将消息重新放入 Queue(或依赖死信队列) 直接将 Offset 回退到失败前的位置,重新拉取
需重新计算历史数据 无法实现(消息已删除) 修改 Offset 到历史位置(比如 1 小时前),重新消费所有消息
多系统独立消费同一消息 需创建多个 Queue,生产者发送多次消息 多个 Consumer Group 独立消费同一 Topic,生产者只需发送一次

持久化与可靠性

对比维度 RabbitMQ Kafka
持久化触发 需手动开启(Queue 设为 durable,消息设为 persistent) 默认持久化(消息写入磁盘,可配置保留时间)
存储上限 受内存限制(大量消息堆积会触发内存告警,刷盘频繁导致性能下降) 受磁盘空间限制(支持 TB 级存储,按时间 / 大小自动清理过期数据)
抗故障能力 单节点故障后,需依赖镜像队列(Mirror Queue)恢复 支持多副本(Replication Factor,默认 3),一个节点故障,其他副本自动接管

很明显,Kafka 更适合海量的存储,感觉 RabbitMQ 的持久化类似缓存,Kafka 的持久化是更适合长期存储

路由能力:RabbitMQ 更灵活,Kafka 更简单

对比维度 RabbitMQ Kafka
路由组件 Exchange(支持 4 种类型:Direct、Topic、Fanout、Headers) 无 Exchange,仅靠 Topic 名称 + 消息 Key
支持的路由规则 精准匹配、模糊匹配(通配符 * #)、headers 匹配、广播 仅 “精准匹配 Topic” 或 “Key 哈希分区”(Key 相同进同一 Partition)
路由开销 有(Exchange 需计算路由) 无(直接按 Topic/Key 分配,开销极小)

因为高吞吐高并发,那么 Kafka 在路由上必须要简单一些

该选 Kafka 还是 RabbitMQ

根据上述的对比,我们其实比较清除了,但是我还是简单的说一下

若优先 “高吞吐、持久化、回溯消费”,选 Kafka;若优先 “灵活路由、即时通信、中小规模”,选 RabbitMQ。

举几个例子

场景类型 推荐产品 原因说明
日志收集(ELK 栈) Kafka 需处理海量日志(每秒十万条),且需持久化保留(供 Elasticsearch 分析)。
实时计算(Flink/Spark) Kafka 需作为 “数据源头”,支持高吞吐写入,且计算失败后需回溯消费历史数据。
业务解耦(订单→库存) RabbitMQ 消息量不大(每秒几百条),需灵活路由(比如 “秒杀订单” 走特殊队列)。
即时通信(聊天 / 通知) RabbitMQ 需低延迟(毫秒级投递),且需确保消息不丢失(靠 ACK 确认)。
峰值流量缓冲(秒杀) Kafka 秒杀时每秒几万条请求,需用 Kafka 缓冲峰值,避免下游服务被压垮。
多系统数据同步 Kafka 需将数据库变更数据(CDC)同步到多个系统,Kafka 支持多 Group 独立消费。

Windows下安装配置 Kafka

下载和解压

https://kafka.apache.org/downloads 这是 Kafka 的官网

Kafka需要Java 8或更高版本支持。而且请自行配置 JAVA_HOME 变量

下载 tgz 压缩包

image-20251026165754772

解压到你需要的位置,避免路径中包含空格和中文字符

image-20251026165721296

配置 Kafka

解压后的Kafka目录包含以下重要文件夹:

bin/windows/ - Windows批处理脚本
config/ - 配置文件
libs/ - 依赖库
logs/ - 日志文件(启动后生成)

我们进入config目录,在server.properties文件中添加一些配置

1
2
3
4
5
6
7
8
9
# 数据存储目录
log.dirs=

# 监听地址
listeners=PLAINTEXT://localhost:9092

# Zookeeper连接地址
zookeeper.connect=localhost:2181

虽然日志默认位置也可以

image-20251026170117616

启动Kafka

Zookeeper 模式(兼容旧架构)

Kafka 自带简化版 Zookeeper,配置文件在 config/zookeeper.properties(默认端口 2181)。

打开 cmd,进入 bin\windows 目录,启动 Zookeeper,并且指定其配置文件:

1
zookeeper-server-start.bat ../../config/zookeeper.properties

新打开一个 cmd,进入 bin\windows 目录,启动 Kafka(配置文件 config/server.properties 中默认关联 Zookeeper 地址 localhost:2181),并且指定其配置文件:

1
kafka-server-start.bat ../../config/server.properties

但是这种情况,在我这个版本里,是没有zookeeper-server-start.bat等的文件,也就是说,目前新版本 Kafka 是没有内置 Zookeeper 启动脚本的

Kafka 从 3.0.0 版本开始,为了推动 KRaft 模式(无 Zookeeper)成为主流,默认移除了自带的 Zookeeper 启动脚本(包括 zookeeper-server-start.bat 和相关配置)。

我的 4.1.0 版本属于高版本,因此 bin/windows 目录中不再包含 Zookeeper 的启动脚本,这意味着:

  • 若要使用 Zookeeper 模式,需要单独下载 Zookeeper 并手动启动(不能再依赖 Kafka 自带的简化版 Zookeeper);

  • 推荐直接使用 KRaft 模式(无需 Zookeeper,步骤更简单,也是 Kafka 官方主推的模式)。

KRaft 模式

无需依赖 Zookeeper,直接通过 Kafka 自身的 KRaft 协议管理元数据,步骤如下:

打开 cmd,进入 Kafka 的 bin\windows 目录:

1
cd D:\kafka_2.13-4.1.0\bin\windows

执行命令生成唯一集群 ID(记下来,后续用):

1
kafka-storage.bat random-uuid
image-20251026171544082

在 Kafka 目录下创建数据存储文件夹(例如 D:\kafka_2.13-4.1.0\data)。

执行格式化命令(替换 <你的集群ID> 为上一步 生成的 ID):

1
kafka-storage.bat format -t <你的集群ID> -c ../../config/kraft/server.properties

成功会显示 Formatting completed successfully

但是我好像没成功

image-20251026172051484什么情况,就是说,这个错误是因为在 KRaft 模式下,server.properties 配置文件中缺少 控制器集群相关的关键配置,导致格式化存储时无法确认集群初始化方式。具体来说,controller.quorum.voters 参数未设置,而系统需要你明确指定集群的初始化模式。

KRaft 模式下,Kafka 集群由 控制器(Controller)broker 组成,需要通过配置指定控制器节点信息。当 controller.quorum.voters 未配置时,格式化存储必须通过命令行参数明确初始化方式(单机模式、初始控制器列表等)。

如果你只是在本地启动一个单节点 Kafka(测试用),最简单的方式是在格式化命令中添加 --standalone 参数(表示单机模式),控制器配置。

1
kafka-storage.bat format -t uuid -c server.properties位置 --standalone

修改config/kraft/server.properties

1
2
3
4
5
6
7
8
9
10
11
12
# 表示此节点,既是broker又可以当controller
process.roles=broker,controller
# 节点id,不重名即可
node.id=1
# controller竞争者,也就是controller将从它们之中诞生(这里的kafka1是刚刚设置的本机的域名解析,或者直接写localhost也行)
controller.quorum.voters=1@localhost:9093
listeners=PLAINTEXT://:9092,CONTROLLER://:9093
# 监听地址(也就是客户端连接时访问的地址)
advertised.listeners=PLAINTEXT://localhost:9092
controller.listener.names=CONTROLLER
# kafka数据存放地址
log.dirs=data

初始化数据存储目录,格式化存储

1
.\bin\windows\kafka-storage format -t 你的uuid -c ./config/kraft/server.properties

哦草,我格式化过了

image-20251026173042528

直接启动 Kafka 即可:

守护进程启动加-daemon 参数

1
kafka-server-start.bat ../../config/server.properties
image-20251026173332389

启动成功了

测试

保持启动窗口开启,并新打开 2-3 个 CMD 窗口(分别用于创建主题、发送消息、消费消息),所有窗口都先进入 Kafka 的 bin\windows 目录:

在第一个 CMD 窗口中,执行以下命令创建一个名为 test-topic 的主题(单分区、单副本,适合测试):

1
kafka-topics.bat --create --topic test-topic --bootstrap-server localhost:9092 --partitions 1 --replication-factor 1
  • 参数说明:
    • --bootstrap-server localhost:9092:指定 Kafka 服务地址(默认端口 9092)。
    • --partitions 1:主题的分区数(测试用 1 即可)。
    • --replication-factor 1:副本数(单机环境只能设为 1)。
image-20251026173501299

然后查看主题是否创建成功

在同一窗口或新窗口中,执行以下命令列出所有主题,确认 test-topic 存在:

1
kafka-topics.bat --list --bootstrap-server localhost:9092
image-20251026173543900

启动消费者接收消息,在第二个 CMD 窗口中,启动一个消费者,监听 test-topic 主题的消息:

1
kafka-console-consumer.bat --topic test-topic --bootstrap-server localhost:9092 --from-beginning

在第三个 CMD 窗口中,启动一个生产者,向 test-topic 主题发送消息:

1
kafka-console-producer.bat --topic test-topic --bootstrap-server localhost:9092

启动后,会显示 > 提示符,此时可以输入任意消息(例如 Hello Kafka!这是一条测试消息),每输入一条按回车发送。

image-20251026173714960
image-20251026173724729

说明消息从生产者成功发送到 Kafka 集群,并被消费者正常接收,测试通过

乱码不要紧,默认 utf8 导致的)

若需清理测试数据,可在 CMD 窗口中执行以下命令删除主题:

1
kafka-topics.bat --delete --topic test-topic --bootstrap-server localhost:9092