4. 环境搭建与工具链:Docker Compose搭建开发环境、Kafka集群部署、Flink Standalone模式部署、MinIO对象存储
说实话,做增量计算最怕什么?不是算法难,是环境搭不起来。
我见过太多团队,代码写好了,结果在测试环境跑不起来。Kafka连不上,Flink内存不够,MinIO权限报错……一查就是半天。所以这一章,咱们把环境一次性搭稳。
本章核心目标:用 Docker Compose 一键拉起全套开发环境,包含 Kafka 集群、Flink Standalone 集群、MinIO 对象存储。你跟着我走一遍,以后新项目直接复用这个模板。
4.1 整体架构概览
先看整体结构。我们这套环境包含四个核心组件:
- Kafka:消息队列,负责接收实时数据流
- Flink:计算引擎,做增量处理
- MinIO:对象存储,存状态快照和中间结果
- Docker Compose:编排工具,把上面三个串起来
它们之间的关系,我画了张图:
你看,数据从左边进来,经过 Kafka 缓冲,Flink 消费计算,结果状态存到 MinIO。这套架构我用了两年多,稳定得很。
4.2 Docker Compose 编排文件
我个人习惯把所有服务写在一个 docker-compose.yml 里。这样一条命令就能拉起全部环境。
下面是我常用的模板:
version: '3.8'
services:
# ---------- Kafka 集群 ----------
zookeeper:
image: confluentinc/cp-zookeeper:7.4.0
environment:
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
ports:
- "2181:2181"
kafka1:
image: confluentinc/cp-kafka:7.4.0
depends_on:
- zookeeper
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 3
ports:
- "9092:9092"
kafka2:
image: confluentinc/cp-kafka:7.4.0
depends_on:
- zookeeper
environment:
KAFKA_BROKER_ID: 2
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9093
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 3
ports:
- "9093:9093"
kafka3:
image: confluentinc/cp-kafka:7.4.0
depends_on:
- zookeeper
environment:
KAFKA_BROKER_ID: 3
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9094
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 3
ports:
- "9094:9094"
# ---------- Flink Standalone 集群 ----------
flink-jobmanager:
image: flink:1.18.0-scala_2.12
ports:
- "8081:8081"
command: jobmanager
environment:
- JOB_MANAGER_MEMORY=2048m
- |
FLINK_PROPERTIES=
jobmanager.rpc.address: flink-jobmanager
flink-taskmanager:
image: flink:1.18.0-scala_2.12
depends_on:
- flink-jobmanager
command: taskmanager
environment:
- TASK_MANAGER_MEMORY=4096m
- |
FLINK_PROPERTIES=
jobmanager.rpc.address: flink-jobmanager
taskmanager.numberOfTaskSlots: 4
# ---------- MinIO 对象存储 ----------
minio:
image: minio/minio:latest
ports:
- "9000:9000"
- "9001:9001"
environment:
MINIO_ROOT_USER: admin
MINIO_ROOT_PASSWORD: admin123
command: server /data --console-address ":9001"
volumes:
- minio-data:/data
volumes:
minio-data:
💡 我的经验:Kafka 的 ADVERTISED_LISTENERS 一定要配对。如果你在本地跑,用 localhost;如果在服务器上,改成对应的内网 IP。我曾经因为这里写错,折腾了俩小时。
4.3 Kafka 集群部署详解
Kafka 集群为什么用 3 个 Broker?说白了,为了高可用。你想想看,如果只有一个 Broker,它挂了整个系统就瘫了。3 个 Broker 配合复制因子 3,任何一个节点宕机都不丢数据。
启动之后,建议先验证一下:
# 进入 Kafka 容器
docker exec -it kafka1 bash
# 创建一个测试 topic
kafka-topics --bootstrap-server localhost:9092 \
--create --topic test-topic \
--partitions 3 --replication-factor 3
# 查看 topic 详情
kafka-topics --bootstrap-server localhost:9092 \
--describe --topic test-topic
输出应该类似这样:
Topic: test-topic PartitionCount: 3 ReplicationFactor: 3
Topic: test-topic Partition: 0 Leader: 1 Replicas: 1,2,3 Isr: 1,2,3
Topic: test-topic Partition: 1 Leader: 2 Replicas: 2,3,1 Isr: 2,3,1
Topic: test-topic Partition: 2 Leader: 3 Replicas: 3,1,2 Isr: 3,1,2
看到 Isr 里三个 Broker 都在,说明集群正常。
⚠️ 避坑指南:我曾经在生产环境遇到过一个问题——Kafka 的 offsets.topic.replication.factor 没设成 3,结果某个 Broker 挂了之后,消费者组无法提交 offset,导致重复消费。所以这个参数一定要和 Broker 数量一致。
4.4 Flink Standalone 模式部署
Flink 的部署模式有好几种,为什么我选 Standalone?
原因很简单:开发环境不需要 YARN 或 Kubernetes。Standalone 模式轻量、启动快、调试方便。你本地开发用这个最合适。
启动之后,访问 http://localhost:8081 就能看到 Flink Web UI。我建议你重点关注这几个指标:
| 指标 | 正常值 | 说明 |
|---|---|---|
| Task Slots | 8(2个 TaskManager × 4 Slot) | 并行度上限 |
| JobManager 内存 | 2 GB | 管理调度用,够用就行 |
| TaskManager 内存 | 4 GB | 每个 TaskManager,根据数据量调整 |
| 可用 TaskManager | 2 | 至少 2 个才能体现分布式 |
提交一个测试任务试试:
# 下载 Flink 客户端(如果本地没有)
wget https://archive.apache.org/dist/flink/flink-1.18.0/flink-1.18.0-bin-scala_2.12.tgz
tar -xzf flink-1.18.0-bin-scala_2.12.tgz
# 提交一个示例任务
./flink-1.18.0/bin/flink run \
-m localhost:8081 \
./flink-1.18.0/examples/streaming/SocketWindowWordCount.jar \
--hostname localhost --port 9999
💡 个人习惯:我会在 flink-conf.yaml 里把 taskmanager.numberOfTaskSlots 设成 4,而不是默认的 1。为什么?因为增量计算任务通常需要多个算子并行,Slot 太少会导致任务排队,白白浪费资源。
4.5 MinIO 对象存储配置
MinIO 在这套环境里扮演什么角色?说白了,就是 Flink 的「状态后端」。Flink 做增量计算时,需要定期把状态快照保存下来。如果存本地磁盘,容器一重启就没了。存 MinIO,数据持久化,还能跨集群共享。
启动之后,访问 http://localhost:9001,用 admin / admin123 登录。然后创建一个 Bucket:
# 用 mc 客户端操作
docker exec -it minio bash
# 安装 mc
wget https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x mc
./mc alias set myminio http://localhost:9000 admin admin123
# 创建 bucket
./mc mb myminio/flink-checkpoints
./mc mb myminio/flink-savepoints
然后在 Flink 的 flink-conf.yaml 里配置状态后端:
state.backend: filesystem
state.checkpoints.dir: s3://flink-checkpoints
state.savepoints.dir: s3://flink-savepoints
s3.access-key: admin
s3.secret-key: admin123
s3.endpoint: http://minio:9000
⚠️ 注意:Flink 连接 MinIO 需要依赖 flink-s3-fs-hadoop 插件。记得把 jar 包放到 flink/lib 目录下。我刚开始用的时候忘了这一步,结果状态后端一直报错,查了半天才发现。
4.6 一键启动与验证
所有配置都准备好了,启动就一行命令:
docker-compose up -d
等个 30 秒左右,验证所有服务:
| 服务 | 验证方式 | 预期结果 |
|---|---|---|
| Kafka | docker exec kafka1 kafka-broker-api-versions --bootstrap-server localhost:9092 |
返回 API 版本列表 |
| Flink | 浏览器访问 http://localhost:8081 |
看到 Flink Web UI |
| MinIO | 浏览器访问 http://localhost:9001 |
看到 MinIO 控制台 |
🎯 最终检查:在 Flink Web UI 里提交一个简单的 Kafka 消费任务,看能不能从 Kafka 读到数据,然后状态快照能不能写到 MinIO。如果能跑通,恭喜你,环境搭建完成!
这套环境我用了快三年,从 Flink 1.13 一直升级到 1.18,基本没出过问题。你把它保存好,以后每个新项目都能复用。