第4章 Kafka核心原理与集群部署
Kafka 在实时数仓里扮演什么角色?说白了,它就是整个数据流的「中枢神经」。所有业务数据、日志、埋点,都得先经过 Kafka 做缓冲和解耦,下游的 Flink、Spark 才能放心消费。我做了这么多年实时数仓,还没见过哪个生产环境敢不用 Kafka 的。
这一章,咱们就把 Kafka 的核心原理掰开揉碎,再手把手搭一套集群出来。
4.1 Kafka 架构:一张图看懂全局
先看整体架构。Kafka 集群由多个 Broker 组成,每个 Broker 就是一台服务器。Producer 发消息,Consumer 拉消息,ZooKeeper 负责协调元数据。
这张图我建议你多看两眼。Producer 不直接找 Consumer,而是把数据扔给 Broker。Broker 负责存,Consumer 自己来取。这种「推拉分离」的设计,让生产者和消费者完全解耦。
4.2 Topic 与 Partition:数据分片的核心
Topic 是逻辑上的消息分类。比如订单数据放 order_topic,用户行为放 user_behavior_topic。但真正存数据的是 Partition。
每个 Partition 是一个有序的、不可变的日志文件。消息追加到尾部,Consumer 通过偏移量(Offset)来定位读取位置。
4.2.1 Partition 的分布策略
假设一个 Topic 有 3 个 Partition,集群有 3 个 Broker。Kafka 会尽量把 Partition 分散到不同 Broker 上。这样做的好处很明显:
- 负载均衡:不会让一台机器扛所有读写
- 高可用:每个 Partition 可以设置副本,副本分布在其他 Broker 上
- 并行度:一个 Partition 只能被一个 Consumer 消费,Partition 越多,消费并行度越高
关键点: Partition 的数量决定了消费的并行上限。我见过有人把 Partition 设成 1,然后抱怨消费速度上不去——这不废话吗?
4.2.2 副本机制
每个 Partition 可以有多个副本。副本分为 Leader 和 Follower。Producer 只写 Leader,Follower 从 Leader 同步数据。如果 Leader 挂了,Follower 会选出一个新的 Leader。
| 参数 | 说明 | 推荐值 |
|---|---|---|
| replication.factor | 副本数量 | 生产环境至少 2,建议 3 |
| min.insync.replicas | 最小同步副本数 | 配合 acks=all 使用,建议设为 2 |
| acks | Producer 确认级别 | 0(不等待)/ 1(Leader 确认)/ all(所有副本确认) |
4.3 生产者与消费者:消息的来与去
4.3.1 生产者核心参数
写 Producer 代码不难,难的是配好参数。我整理了一份常用配置清单:
// Producer 核心配置
Properties props = new Properties();
props.put("bootstrap.servers", "192.168.1.10:9092,192.168.1.11:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
// 可靠性相关
props.put("acks", "all"); // 等待所有副本确认
props.put("retries", 3); // 重试次数
props.put("enable.idempotence", true); // 开启幂等性,防止重复
// 吞吐量相关
props.put("batch.size", 16384); // 批次大小,16KB
props.put("linger.ms", 5); // 延迟发送时间,5ms
props.put("compression.type", "snappy"); // 压缩,减少网络开销
为什么 acks=all 还要开幂等性?你想想看,如果网络抖动导致 Producer 重试,Broker 可能收到两条相同的消息。幂等性通过 Producer ID 和序列号去重,保证 Exactly Once 语义。
4.3.2 消费者核心参数
Consumer 的配置更讲究,尤其是消费位移的管理:
// Consumer 核心配置
Properties props = new Properties();
props.put("bootstrap.servers", "192.168.1.10:9092,192.168.1.11:9092");
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("group.id", "order_consumer_group");
// 消费位移
props.put("enable.auto.commit", false); // 手动提交位移
props.put("auto.offset.reset", "earliest"); // 无位移时从最早开始消费
// 性能相关
props.put("max.poll.records", 500); // 每次拉取最大条数
props.put("fetch.max.bytes", 52428800); // 每次拉取最大字节,50MB
4.4 Kafka 集群搭建:三台机器就够了
理论说完了,咱们动手搭集群。我习惯用三台机器,每台部署一个 Broker。这样既满足高可用,又不会太浪费资源。
4.4.1 环境准备
- 三台 CentOS 7 服务器,IP 分别为 192.168.1.10、192.168.1.11、192.168.1.12
- JDK 1.8+(Kafka 依赖 Java 环境)
- ZooKeeper 3.6+(Kafka 2.8 之前必须依赖 ZK)
- Kafka 2.13-3.2.0(我选这个版本,稳定且社区活跃)
4.4.2 安装步骤
- 下载解压:三台机器都执行
wget https://archive.apache.org/dist/kafka/3.2.0/kafka_2.13-3.2.0.tgz
tar -xzf kafka_2.13-3.2.0.tgz -C /opt/
ln -s /opt/kafka_2.13-3.2.0 /opt/kafka
- 配置 server.properties(以 Broker 1 为例)
# /opt/kafka/config/server.properties
broker.id=1
listeners=PLAINTEXT://192.168.1.10:9092
log.dirs=/data/kafka/logs
num.partitions=3
default.replication.factor=2
zookeeper.connect=192.168.1.10:2181,192.168.1.11:2181,192.168.1.12:2181
其他两台机器类似,broker.id 分别设为 2 和 3,listeners 改成对应 IP。
- 启动 ZooKeeper(三台都启动)
# 使用 Kafka 自带的 ZK(生产环境建议独立部署)
/opt/kafka/bin/zookeeper-server-start.sh -daemon /opt/kafka/config/zookeeper.properties
- 启动 Kafka
/opt/kafka/bin/kafka-server-start.sh -daemon /opt/kafka/config/server.properties
- 验证集群
# 创建测试 Topic
/opt/kafka/bin/kafka-topics.sh --create \
--bootstrap-server 192.168.1.10:9092 \
--replication-factor 2 \
--partitions 3 \
--topic test_topic
# 查看 Topic 详情
/opt/kafka/bin/kafka-topics.sh --describe \
--bootstrap-server 192.168.1.10:9092 \
--topic test_topic
如果看到 Partition 分布在不同的 Broker 上,副本也正常同步,说明集群搭好了。
验证结果示例:
Topic: test_topic PartitionCount: 3 ReplicationFactor: 2
Topic: test_topic Partition: 0 Leader: 1 Replicas: 1,2 Isr: 1,2
Topic: test_topic Partition: 1 Leader: 2 Replicas: 2,3 Isr: 2,3
Topic: test_topic Partition: 2 Leader: 3 Replicas: 3,1 Isr: 3,1
Leader 分布在三个 Broker 上,每个 Partition 有两个副本,ISR(同步副本)全部在线。完美。
4.4.3 生产环境调优建议
| 配置项 | 默认值 | 生产推荐 | 说明 |
|---|---|---|---|
| num.network.threads | 3 | CPU 核数 | 网络处理线程,I/O 密集型可多配 |
| num.io.threads | 8 | CPU 核数 * 2 | 磁盘 I/O 线程 |
| log.segment.bytes | 1GB | 1GB | 日志段大小,太小会导致频繁滚动 |
| log.retention.hours | 168 | 72 | 日志保留时间,根据业务调整 |
| message.max.bytes | 1MB | 10MB | 单条消息最大大小,日志数据通常较大 |
嗯,这一章的内容就到这。Kafka 的原理和部署其实不复杂,但细节很多。你只要把架构图记在脑子里,把参数配置理解透,生产环境基本不会出大问题。