本专栏文章持续更新 ,新增内容使用蓝色表示。本文将从初学者的视角串联 Kafka 的核心概念与设计思想。
引入
很多初学者对 Kafka 的了解,可能只停留在"它是一个高性能的消息队列"。但消息队列到底是什么?它解决了什么问题?让我们从一个真实的场景开始思考。
场景分析:生产者与消费者
假设有两个服务:
-
生产者服务:平时流量平稳(100 QPS)
-
消费者服务:处理能力较强(1000 QPS)
平时一切运行良好,直到促销活动到来------生产者流量飙升至2000 QPS。消费者服务不堪重负,可能出现:
-
请求超时:消费者处理不过来,堆积的请求超时。
-
服务崩溃:消费者资源(CPU、内存)耗尽,直接宕机。
-
数据丢失:未来得及处理的消息在内存中丢失。

鉴于这种情况,第一反应是在消费者服务的内存里维护一个队列(比如一个列表),让生产者的消息先进入队列缓冲,消费者再慢慢处理。这确实缓解了瞬时压力。
队列内部每个节点存储消息,且每个节点都有一个序号,通过 offset 记录消费的消息位置。

但是消息太多,来不及处理的消息会堆积在内存中,可能会导致 OOM。如果消费者服务重启,在内存中的消息会丢失的。
不难想到可以将队列外置,这样就互不干扰了。

但仅是这样的消息队列,抗风险能力几乎为0,高性能,高可用,高拓展性都没有,压力一大,可能就嘎巴一下 down 掉了。
不过,没关系,我们可以逐个优化。
首先针对 高性能部分,我们可以增加生产者和消费者的数量。但是问题也暴露出来了,队列只有一个,各个服务实例之间会因为竞争同一个消息队列(共享资源)而阻塞,这样一来,性能"如提"。

对此,我们可以引入 Topic(主题) 的概念,将消息按业务类型(如订单、日志)分类(key),发送到不同的 Topic。消费者按需订阅,互不影响。

但单个 Topic 内部仍可能压力过大。于是,我们将一个 Topic 拆分成多个 Partition(分区)。
生产者根据消息的Key,将同一Key的消息发往同一个分区,这保证了分区内消息的有序性 。每个分区可以被一个独立的消费者处理,实现了并发消费,大幅提升吞吐量。

接下来是 高扩展性 。高扩展性是指系统能够通过增加资源来优雅地处理不断增长的工作负载。
经过上面的处理,Topic + Partition 的设计,解决了单一队列的性能瓶颈。
但随着分区数量增加,如果所有分区都集中在一台机器上,单机的CPU、内存和磁盘I/O很快会成为新的瓶颈。
对此,我们可以进行水平拓展 ,引入多台机器(称为 Broker),将不同的分区分散存储在不同的Broker上。这样,系统的处理能力可以随着 Broker 的增加而近乎线性地增长。

最后是 高可用,如果有一台 broker 挂了,那相关的 partition 中的消息岂不是都没了?
Kafka的答案是 副本(Replica)机制:
-
每个分区的数据会被复制到多个Broker上,形成多个副本。
-
其中一个是 Leader,负责所有读写请求。
-
其他是 Follower,被动地从Leader同步数据。
-
当Leader所在Broker故障时,Kafka会自动从Follower中选举出一个新的Leader,客户端几乎无感知,服务持续可用。

如果所有 broker 都挂了呢?那就不能只将数据放在内存中,还要持久化到磁盘里。但磁盘不是无限的,所以 Kafka 引入了 保留策略(Retention Policy):
-
基于时间:例如只保留最近7天的数据。
-
基于大小 :例如每个分区只保留1GB的数据。
超过限制的旧数据会被自动清理,腾出空间。
以上就是有关消息队列和 kakfa 的简单引入了。
简介
kafka 是一个分布式的基于发布/订阅模式的消息队列(Message Queue),主要应用于大数据实时处理领域。
常见概念
Message 消息
Kafka 中消息的基本单元,以键值对(Key-Value)形式存在。
-
Key:可选。用于决定消息被发送到哪个分区(相同Key去往相同分区)。
-
Value:消息的实际内容(Payload)。
-
Offset(偏移量):消息在分区中的唯一序号,消费者据此记录消费位置。
【补充】若消息未指定 Key,Kafka 会采用轮询(Round-Robin)策略将消息均匀分配到各分区,以均衡负载。
Topic 主题与 Partition 分区
-
Topic:逻辑上的消息类别,是生产者发布与消费者订阅的主体。
-
Partition:物理上的存储单元,一个 Topic 可划分为多个分区,每个分区是一个有序、不可变的记录序列。
【补充】分区是 Kafka 实现并行处理 和水平扩展的基础。通过增加分区,可以同时提升写入与消费的吞吐量。
Producer 生产者 与 Consumer 消费者
-
Producer:向指定Topic发布消息的客户端。
-
Consumer:从Topic订阅并处理消息的客户端。
Consumer Group 消费者组
Kafka 消费者是以消费者组的方式工作,由一个或者多个消费者组成,共同消费一个 topic。每个 partition 在同一时间只能由 group 中的一个消费者读取,但是多个 group 可以同时消费这个 partition。
优点:消费者可以通过水平扩展的方式同时读取大量的消息。如果一个消费者失败了,那么同组的其他成员会自动负载均衡去读取之前失败消费者读取的分区。
【补充】关于"为什么一个分区只能由消费者组的一个消费者消费?"
答:如果一个分区可以由同个消费者组的多个消费者消费,相当于可以多线程读取同一个消息,这样不利于保证消息的有序,以及有可能重复读取消息。
Broker 代理 与 Cluster 集群
-
Broker:一个独立的 Kafka 服务节点,负责消息存储与传输。
-
Cluster:由多个 Broker 组成的集群,共同对外提供服务,实现高可用与负载均衡。
Replica 副本与 ISR
每个分区的数据会在多个 Broker 上复制存储,形成副本(replica),用于容灾备份。创建 Topic 时可设置 replication-factor 参数指定副本数。其中一个副本被选为 Leader,负责处理该分区的所有读写请求。其他副本作为 Follower,持续从 Leader 同步数据,保持与 Leader 一致。
**ISR(In-Sync Replicas)**指当前与 Leader 保持同步的副本集合(含 Leader 自身)。只有 ISR 中的副本才有资格在 Leader 失效时参与选举。
消费模型
常见的消费模型一般有两种:推送(push)模型 和 拉取(pull)模型。
Kafka消费者采用 Pull(拉取) 模式,即消费者主动向Broker请求数据。相比于Push(推送)模式,它的优势在于:
-
消费者自主控制速率:可以根据自身处理能力决定拉取频率和数量,防止被压垮。
-
灵活的消费顺序:可以回溯消费旧消息(通过修改Offset)。
消息确认机制
生产者可通过 acks 参数控制消息写入的可靠性级别:
-
acks=0:最不可靠的模式。生产者在发送消息后不会等待来自服务器的确认。意味着消息可能会在发送之后丢失,而生产者将无法知晓。
-
acks=1:默认模式。生产者会在消息发送后只等待来自分区领导者(leader)写入成功即返回确认。在 Leader 故障且数据未同步时可能丢失数据。
-
acks=-1:最可靠的模式。生产者会在消息发送后等待 ISR 中所有副本都写入成功才确认。可靠性最高,但延迟较大。
消息积压
消息积压是指消费速度持续低于生产速度,导致消息在 Kafka 中堆积。常见应对策略包括:
1)通过增加消费者实例提高消息的消费速度,从而缓解积压问题。
2)通过增加 Kafka topic 的分区数量提高消息的并行处理能力。在创建新分区后,需要重新平衡消费者组,让更多的消费者可以同时消费消息。
【补充】topic 创建之后分区数只能增加不能减少。
3)优化消费逻辑,检查消费者业务代码,尝试批量处理、异步化、减少外部依赖调用等,提升单消费者吞吐量。
消费者-分区关系
| 情况 | 主题分区数 | 消费者数量 | 分配关系 | 状态 |
|---|---|---|---|---|
| 情况1 | 3个分区 | 3个消费者 | 消费者 C1 → 分区 P0 消费者 C2 → 分区 P1 消费者 C3 → 分区 P2 | ✅ 理想状态,每个消费者负责一个分区,完全负载均衡 |
| 情况2 | 4个分区 | 2个消费者 | 消费者 C1 → 分区 P0, P2 消费者 C2 → 分区 P1, P3 | ✅ 正常工作,消费者处理多个分区,需管理不同分区的偏移量 |
| 情况3 | 2个分区 | 4个消费者 | 消费者 C1 → 分区 P0 消费者 C2 → 分区 P1 消费者 C3 → (闲置) 消费者 C4 → (闲置) | ❌ 资源浪费,超出分区的消费者无法分配到工作 |
ZooKeeper 与 KRaft
经过上述的了解,可以发现 kafka 的组件是很多的,每个组件都有自己的数据和状态,所以需要一个组件进行维护。
在 Kafka 早期架构中,ZooKeeper 负责管理集群元数据、控制器选举、消费者组位移等协调工作。而从 Kafka 2.8.0 版本开始,社区引入了 KRaft 协议(基于 Raft 共识算法),并在 3.0+ 版本中逐步替代 ZooKeeper,以实现更简洁的架构、更高的性能与更稳定的运维体验。
有关zookeeper的更多内容可以阅读:
【Hadoop】ZooKeeper:分布式系统的协调核心与一致性保障-CSDN博客
https://blog.csdn.net/D2005_10_25/article/details/151839033
应用场景
-
削峰填谷:应对突发流量(如秒杀),将请求缓冲在Kafka中,让下游服务平稳处理。
-
系统解耦:连接上下游系统,分离数据生产方与消费方,一方变更不影响另一方,如订单系统与库存、物流、通知系统解耦,提升系统灵活性与可维护性。
-
异步处理:非核心流程异步化,提升主流程响应速度,如用户注册后发送欢迎邮件。
-
实时流处理:作为流处理平台(如Kafka Streams, Flink)的数据源,实时处理点击流、日志等数据。
-
日志聚合:统一采集分布式系统日志,便于监控与分析。
如有问题或建议,欢迎在评论区中留言~