第2章 环境准备与依赖配置:Flink与Kafka版本兼容性、Maven/Gradle依赖配置、集群环境搭建要点
说实话,做实时数据管道这么多年,我见过太多因为版本不匹配导致的诡异问题了。明明代码写得没问题,一跑就报序列化异常,或者连不上 Kafka。嗯,这一章咱们就把这些坑提前填上。
2.1 Flink与Kafka版本兼容性——别让版本坑了你
Flink 和 Kafka 的版本兼容性,说白了就是「连接器」和「客户端协议」的匹配问题。Flink 官方为每个大版本的 Kafka 都提供了对应的连接器(connector),但版本号对应关系很容易搞混。
我个人习惯是直接查这张表,比看文档快:
| Flink 版本 | Kafka 版本 | 推荐连接器(Maven artifactId) | 备注 |
|---|---|---|---|
| 1.12.x | 2.4.x - 2.6.x | flink-connector-kafka_2.12 | 老项目还在用,但建议升级 |
| 1.13.x | 2.5.x - 2.8.x | flink-connector-kafka_2.12 | 兼容性较好,我踩坑最少 |
| 1.14.x | 2.6.x - 3.0.x | flink-connector-kafka_2.12 / 2.11 | 开始支持 Kafka 3.x |
| 1.15.x | 2.7.x - 3.2.x | flink-connector-kafka | 连接器独立发布,不再捆绑 |
| 1.16.x - 1.17.x | 2.8.x - 3.4.x | flink-connector-kafka | 当前主流组合 |
| 1.18.x+ | 3.0.x - 3.6.x | flink-connector-kafka | 推荐使用 Kafka 3.2+ |
⚠️ 我曾经踩过的坑: 有一次生产环境 Flink 1.13 配了 Kafka 3.1,结果消费者一直报
UnsupportedVersionException。查了半天才发现,Flink 1.13 自带的 Kafka 客户端版本太低,不认识 Kafka 3.x 的新协议。后来手动升级了 kafka-clients 版本才解决。所以,连接器版本和 Kafka broker 版本必须匹配,别只看 Flink 大版本。
2.2 Maven/Gradle 依赖配置——写对一行,省心一周
依赖配置是环境准备里最琐碎但最关键的一步。我见过太多同事把依赖写错,导致编译通过但运行时 ClassNotFound。下面直接给标准配置。
2.4.1 Maven 配置(推荐)
我个人更倾向 Maven,因为公司内部私服基本都是 Maven 仓库。以 Flink 1.17 + Kafka 3.4 为例:
<properties>
<flink.version>1.17.1</flink.version>
<kafka.version>3.4.0</kafka.version>
<scala.binary.version>2.12</scala.binary.version>
</properties>
<dependencies>
<!-- Flink 核心依赖 -->
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-java</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-streaming-java</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
<!-- Kafka 连接器(独立发布,注意版本对应) -->
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-connector-kafka</artifactId>
<version>3.0.0-1.17</version>
</dependency>
<!-- Kafka 客户端(建议显式指定,避免传递依赖版本冲突) -->
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-connector-kafka</artifactId>
<version>${kafka.version}</version>
</dependency>
</dependencies>
💡 我的习惯: 把
flink-java 和 flink-streaming-java 设为 provided 作用域,这样打包时不会把 Flink 自身 jar 打进去,避免和集群环境冲突。但 flink-connector-kafka 必须设为 compile(默认),因为集群里没有这个 jar。
2.4.2 Gradle 配置
如果你用 Gradle,配置思路一样,只是语法不同:
ext {
flinkVersion = '1.17.1'
kafkaVersion = '3.4.0'
scalaBinaryVersion = '2.12'
}
dependencies {
// Flink 核心(provided)
implementation "org.apache.flink:flink-java:${flinkVersion}"
implementation "org.apache.flink:flink-streaming-java:${flinkVersion}"
// Kafka 连接器
implementation "org.apache.flink:flink-connector-kafka:3.0.0-1.17"
// Kafka 客户端
implementation "org.apache.kafka:kafka-clients:${kafkaVersion}"
}
🔑 关键点: 无论用 Maven 还是 Gradle,一定要显式声明
kafka-clients 版本。Flink 连接器传递依赖的 kafka-clients 版本可能比较旧,不显式声明的话,你可能会遇到「编译用 3.4,运行时却是 2.8」的尴尬情况。
2.3 集群环境搭建要点——从单机到生产
环境搭建这事儿,不同阶段要求不一样。开发时单机跑通就行,生产环境就得考虑资源隔离和高可用。我按场景分开说。
2.3.1 本地开发环境(快速验证)
我个人习惯在本地用 Docker Compose 起一套最小集群,这样不污染宿主机环境:
version: '3.8'
services:
zookeeper:
image: confluentinc/cp-zookeeper:7.4.0
environment:
ZOOKEEPER_CLIENT_PORT: 2181
kafka:
image: confluentinc/cp-kafka:7.4.0
depends_on:
- zookeeper
ports:
- "9092:9092"
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
jobmanager:
image: flink:1.17.1-scala_2.12
ports:
- "8081:8081"
command: jobmanager
environment:
- JOB_MANAGER_RPC_ADDRESS=jobmanager
taskmanager:
image: flink:1.17.1-scala_2.12
depends_on:
- jobmanager
command: taskmanager
environment:
- JOB_MANAGER_RPC_ADDRESS=jobmanager
跑起来之后,访问 localhost:8081 就能看到 Flink Web UI,Kafka 用 localhost:9092 连接。嗯,开发调试足够了。
2.3.2 生产环境要点
生产环境我建议至少注意这几点:
- 资源隔离:Flink 和 Kafka 不要混部在同一台机器上。两者都是资源密集型,抢 CPU 和内存会导致频繁 GC 和延迟抖动。
- 网络规划:Flink TaskManager 和 Kafka Broker 之间的网络延迟最好 < 1ms。跨机房部署时,记得调大
fetch.max.wait.ms和request.timeout.ms。 - 并行度匹配:Flink Source 的并行度最好和 Kafka 分区数成倍数关系。比如 12 个分区,Source 并行度设 6 或 12,避免数据倾斜。
- JMX 监控:一定要开启 Flink 和 Kafka 的 JMX 端口,方便接入 Prometheus + Grafana。我吃过一次亏,线上出问题才发现监控没配,全靠猜。
⚠️ 我曾经踩过的坑: 有次生产环境 Flink 作业频繁重启,查日志发现是 Kafka 连接超时。但 Kafka 集群明明正常。后来发现是 Flink 的
taskmanager.network.memory.min 设得太小,导致网络缓冲区不够,请求排队超时。调大这个参数后问题解决。所以,网络内存配置不能省。
2.4 知识体系总览
下面这张图把本章的核心逻辑串起来了,你可以对照着检查自己的环境:
2.5 快速验证——跑通第一个集成作业
环境搭好之后,我习惯用一段最简单的代码验证连通性。别一上来就搞复杂逻辑,先确认「Flink 能读到 Kafka 数据」再说。
import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer;
import java.util.Properties;
public class KafkaFlinkQuickTest {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
Properties props = new Properties();
props.setProperty("bootstrap.servers", "localhost:9092");
props.setProperty("group.id", "flink-quick-test");
FlinkKafkaConsumer<String> consumer = new FlinkKafkaConsumer<>(
"test-topic",
new SimpleStringSchema(),
props
);
consumer.setStartFromLatest();
DataStream<String> stream = env.addSource(consumer);
stream.print();
env.execute("Kafka Flink Quick Test");
}
}
跑之前记得在 Kafka 里创建 test-topic,然后往里面发几条消息。如果控制台能打印出来,说明环境通了。嗯,这一步走通,后面的事就好办了。
💡 我的习惯: 验证通过后,我会把这段代码保留在项目里作为「健康检查」脚本。每次环境变更后跑一遍,能快速定位是代码问题还是环境问题。