1. 概述
Apache Kafka 是一个流行的开源分布式消息流平台。在 Kafka 中,topic 是一组特定数据流的抽象。例如,在一个车队定位系统中,车辆的位置信息可以是一个 topic,而车速可能是另一个 topic。车辆作为生产者向这些 topic 发送数据,控制中心则作为消费者从这些 topic 中读取消息。
然而,消费者读取消息的顺序并不总是与消息被生产时的顺序一致。本文将讨论如何让 Kafka 的消息读取行为像一个 FIFO(先进先出)队列。我们使用 Kafka 3.7.0 版本进行演示。
2. Topic 分区机制
在 Kafka 中,每个 topic 会被划分为多个分区(Partition)。Kafka 会将消息分散存储在这些分区中。我们可以在创建 topic 时指定分区数量。
默认情况下,如果生产者没有指定 key,Kafka 会使用默认的分区策略(如 RoundRobin)将消息分配到不同分区。如果指定了 key,相同 key 的消息会被分配到同一个分区中。
⚠️ Kafka 仅保证单个分区内的消息顺序,不保证跨分区的消息顺序。因此,如果消息顺序对你的业务至关重要,建议使用单个分区的 topic。
3. 多分区下的消息顺序行为
本节我们将通过命令行操作,演示 Kafka 在多分区场景下的消息顺序行为。
3.1. 启动 Kafka 服务
我们使用 Kafka Raft 模式启动服务。首先生成集群唯一标识:
$ kafka-storage.sh random-uuid
trRz7RXuS7mHDQkxCOZnYQ
格式化存储目录:
$ kafka-storage.sh format -t trRz7RXuS7mHDQkxCOZnYQ -c /home/baeldung/work/kafka/config/kraft/server.properties
启动 Kafka 服务:
$ kafka-server-start.sh /home/baeldung/work/kafka/config/kraft/server.properties
服务启动成功后,进入下一步。
3.2. 创建多分区 Topic
创建一个名为 first-topic
的 topic,包含 3 个分区:
$ kafka-topics.sh --bootstrap-server localhost:9092 --topic first-topic --create --partitions 3
查看分区信息:
$ kafka-topics.sh --bootstrap-server localhost:9092 --topic first-topic --describe
输出显示该 topic 有 3 个分区,每个分区的副本数为 1。
3.3. 写入消息
启动生产者,使用 RoundRobin 分区策略向 topic 发送 6 条消息:
$ kafka-console-producer.sh --bootstrap-server localhost:9092 --topic first-topic --producer-property partitioner.class=org.apache.kafka.clients.producer.RoundRobinPartitioner
>Message1
>Message2
>Message3
>Message4
>Message5
>Message6
由于使用 RoundRobin 策略,消息会依次写入不同分区。
3.4. 读取消息
启动消费者,从头开始读取:
$ kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic first-topic --from-beginning
输出可能如下:
Message2
Message5
Message1
Message4
Message3
Message6
✅ 结果说明:
- 同一分区内的消息顺序是正确的(如 Message1 在 Message4 之前)。
- 不同分区之间的消息顺序不保证(如 Message5 在 Message1 之前)。
这说明:在多分区情况下,Kafka 无法保证全局顺序。
4. 单分区下的消息顺序行为
接下来我们演示单分区下 Kafka 的行为。
4.1. 创建单分区 Topic
创建一个名为 second-topic
的 topic,指定 1 个分区:
$ kafka-topics.sh --bootstrap-server localhost:9092 --topic second-topic --create --partitions 1
查看分区信息确认:
$ kafka-topics.sh --bootstrap-server localhost:9092 --topic second-topic --describe
输出显示仅有一个分区。
4.2. 写入消息
启动生产者发送 6 条消息:
$ kafka-console-producer.sh --bootstrap-server localhost:9092 --topic second-topic
>Message11
>Message12
>Message13
>Message14
>Message15
>Message16
所有消息将写入同一个分区。
4.3. 读取消息
启动消费者从头读取:
$ kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic second-topic --from-beginning
输出如下:
Message11
Message12
Message13
Message14
Message15
Message16
✅ 结果说明:
- 所有消息按写入顺序读出。
- Kafka 在单分区下表现出了 FIFO 队列的特性。
5. 结论
本文通过实际操作验证了 Kafka 的消息顺序行为:
✅ 关键结论:
- Kafka 仅保证单个分区内的消息顺序。
- 跨分区的消息顺序无法保证。
- 如果业务场景对消息顺序敏感,建议:
- 使用 单分区 topic。
- 或者使用 key 来确保相关消息进入同一分区。
⚠️ 注意:单分区会影响 Kafka 的吞吐量和扩展性,使用时需权衡性能与顺序保证之间的关系。