用 Gradle 配置 Flink 从开发到打包的一条龙实践

一、环境要求与项目初始化

  • Gradle:7.x
  • Java:11(支持 8,但已不推荐)

提示:若你使用 Gradle Wrapper,命令均可替换为 ./gradlew ...,避免本机 Gradle 版本不一致。

二、IDE 导入与本地运行

  • IntelliJ IDEA:原生 Gradle 插件即可。

    • 运行配置里勾选 Include dependencies with "Provided" scope (旧版没有该选项时,可写一个测试用例调用 main() 代跑)。
    • JVM 堆内存:Help -> Edit Custom VM Options,增加如 -Xmx800m
  • Eclipse :使用 Eclipse Buildship 插件(导入向导最后一步确保 Gradle 版本 ≥ 3.0,Shadow 插件需要)。

三、项目结构与主类配置

  • 默认示例主类通常叫 StreamingJob(可能因模板而异)。

  • 若主类不同,建议在 build.gradle 中设置:

    groovy 复制代码
    application {
      mainClass = 'org.example.MyJob'   // Gradle 7 推荐写法
    }

    或在 shadowJar 的 Manifest 中指定主类(见第六节)。

这样打包后的 JAR 直接被 Flink 识别,无需每次提交都 -c org.example.MyJob

四、依赖管理:providedcompile 的边界

核心原则:

  • Flink 核心/运行时 (例如 flink-clientsflink-table-runtimeflink-table-planner-loader由集群提供 → 在工程中标记为 provided/compileOnly不要打进 JAR。
  • 你必须随作业分发 的依赖(连接器、格式库、业务 SDK)→ 设为 compile/runtime ,并通过 Shadow 打包进 fat/uber JAR。

示例(build.gradle

groovy 复制代码
plugins {
  id 'java'
  id 'application'
  id 'com.github.johnrengelman.shadow' version '8.1.1'
}

ext {
  flinkVersion = '2.1.0'
}

repositories { mavenCentral() }

dependencies {
  // 1) API(按需)
  implementation "org.apache.flink:flink-streaming-java:${flinkVersion}"
  implementation "org.apache.flink:flink-table-api-java:${flinkVersion}"
  implementation "org.apache.flink:flink-table-api-java-bridge:${flinkVersion}"

  // 2) 连接器/格式(打进 fat JAR)
  implementation "org.apache.flink:flink-connector-kafka:${flinkVersion}"
  implementation "org.apache.flink:flink-json:${flinkVersion}"

  // 3) 集群提供的运行时(不要打包)
  compileOnly "org.apache.flink:flink-clients:${flinkVersion}"
  compileOnly "org.apache.flink:flink-table-runtime:${flinkVersion}"
  compileOnly "org.apache.flink:flink-table-planner-loader:${flinkVersion}"

  // 4) 测试
  testImplementation "org.apache.flink:flink-test-utils-junit:${flinkVersion}"
  testImplementation "org.junit.jupiter:junit-jupiter:5.10.2"
}

application {
  mainClass = 'org.example.MyJob'
}

tasks.withType(Test).configureEach {
  useJUnitPlatform()
}

五、添加依赖的常见场景

Kafka Connector 为例(shadow 专用的配置法在很多模板中叫 flinkShadowJar;若无该自定义配置,implementation 即可):

groovy 复制代码
dependencies {
  // 如果模板定义了 'flinkShadowJar' 以便区分要打进 fat JAR 的依赖
  flinkShadowJar "org.apache.flink:flink-connector-kafka:${flinkVersion}"

  // 若没有该自定义配置,使用 implementation 也能被 Shadow 打入
  // implementation "org.apache.flink:flink-connector-kafka:${flinkVersion}"
}

关键不是名字,而是这些依赖最终会进入 Shadow 产物;而 Flink 核心运行时 保持 compileOnly/provided

六、打包策略:普通分发 vs fat/uber JAR

命令一览:

  • 本地快速打包 fat JAR(常用):

    bash 复制代码
    gradle clean shadowJar

    产物:build/libs/<project>-<version>-all.jar

  • 安装可分发目录(不含第三方 fat 合并)

    bash 复制代码
    gradle clean installDist

    适合"只依赖 Flink 发行版内置组件"的简单作业(例如 filesystem + JSON)。

  • 安装 fat 分发目录(单 JAR 带齐第三方依赖)

    bash 复制代码
    gradle clean installShadowDist

    产物在:build/install/<project>/lib/(包含单一 fat JAR)。

Shadow 细节(可选优化)

groovy 复制代码
tasks.shadowJar {
  archiveClassifier.set('all')
  mergeServiceFiles()
  exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA' // 避免签名冲突
  manifest {
    attributes 'Main-Class': 'org.example.MyJob' // 双保险:Manifest 写主类
  }
}

建议:生产环境用 fat/uber JAR 更省心:一次打包,处处可跑;但务必别把 Flink 运行时也打进去。

七、提交运行与命令示例

bash 复制代码
bin/flink run -c org.example.MyJob build/libs/my-job-1.0.0-all.jar
# 若 Manifest 已写 Main-Class,可省略 -c:
# bin/flink run build/libs/my-job-1.0.0-all.jar

亦可在 Kubernetes Application/Session 模式下提交,上线前先在测试集群验证。

八、常见问题与排查清单

(1)JAR 过大或类冲突

  • 症状:依赖冲突、NoSuchMethodErrorLinkageError
  • 原因:把 flink-clients/table-runtime/planner-loader 这类运行时打进了 fat JAR。
  • 解决:改为 compileOnly/provided,重新打包;核对依赖树(gradle dependencies)。

(2)IDE 能跑,集群报错

  • 原因:集群的 Flink 版本与本地依赖不匹配,或缺少对应运行时。
  • 解决:统一版本;确保运行时由集群提供,应用仅携带连接器与三方库。

(3)主类找不到

  • 原因:打包未写 Main-Class,或改了主类却没同步到配置。
  • 解决:application { mainClass = ... } 或在 shadowJar.manifest 写入。

(4)内存不足

  • 现象:IDE 或本地运行时 OOM。
  • 处理:增加 JVM 堆(-Xmx800m 起步),或在运行配置调大。

(5)Kafka/格式类找不到

  • 原因:连接器/格式库没有被 Shadow 打进产物。
  • 解决:确认依赖在 implementation 或模板的 flinkShadowJar;重新打包 shadowJar

九、实践建议与下一步

(1)以 Kafka → 清洗 → Sink 的最小链路为骨架,先在本地跑通。

(2)用 shadowJar 生成 fat JAR,在测试集群验证端到端。

(3)在 CI/CD 中固化:Gradle Wrapper + 版本锁定 + 产物归档 + 自动提交

(4)连接器与 Flink 版本强一致 ;显式设置有状态算子的 UID(与部署相关,但同样建议固定)。

依赖作用域 划清、把 Shadow 打包 配好、把 主类 写明白,你的 Flink + Gradle 项目就能稳定地在"开发---构建---部署"全链路运行。祝你第一条 Flink 作业流水线顺利上线!

相关推荐
秃头菜狗2 小时前
十三、格式化 HDFS 文件系统、启动伪分布式集群
大数据·hadoop·hdfs
想ai抽2 小时前
吃透大数据算法-霍夫曼编码(Huffman Coding)
大数据·数据结构·算法
笨蛋少年派2 小时前
Hadoop简介
大数据·hadoop
Hello.Reader3 小时前
Flink 高级配置发行版剖析、Scala 版本、Table 依赖与 Hadoop 集成实战
hadoop·flink·scala
孟意昶3 小时前
Spark专题-第三部分:性能监控与实战优化(3)-数据倾斜优化
大数据·分布式·sql·spark
Lansonli3 小时前
大数据Spark(六十六):Transformation转换算子sample、sortBy和sortByKey
大数据·分布式·spark
武子康3 小时前
大数据-117 - Flink JDBC Sink 详细解析:MySQL 实时写入、批处理优化与最佳实践 写出Kafka
大数据·后端·flink
数据小子21412 小时前
【自记】MaxCompute中的冒烟测试
大数据·maxcompute
未来之窗软件服务14 小时前
万象EXCEL开发(九)excel 高级混合查询 ——东方仙盟金丹期
大数据·excel·仙盟创梦ide·东方仙盟·万象excel