Flink开发环境搭建与WordCount实战
前言
上一篇我们从宏观角度认识了 Flink,知道它是干什么的。但光说不练假把式,这篇文章我们要动手搞起来------从零搭建 Flink 开发环境,并写出人生中第一个 Flink 程序:WordCount(单词计数)。
别担心环境问题,我会一步步带你配置,保证你能跑起来。如果中间遇到问题,文末有常见问题汇总。
🏠个人主页:你的主页
目录
一、环境准备清单
在开始之前,先确认你的电脑上有以下环境:
| 环境 | 要求 | 推荐版本 | 说明 |
|---|---|---|---|
| JDK | 必须 | JDK 8 或 JDK 11 | Flink 官方推荐,JDK 17+ 需要额外配置 |
| Maven | 必须 | 3.6+ | 依赖管理工具 |
| IDE | 推荐 | IntelliJ IDEA | 社区版免费够用 |
| Git | 可选 | 最新版 | 版本管理 |
为什么推荐 JDK 8 或 11?
Flink 对 JDK 版本有一定要求:
- JDK 8:最稳定,兼容性最好
- JDK 11:官方支持,长期维护版本
- JDK 17+:需要额外的 JVM 参数,初学者不推荐
如果你电脑上已经有 JDK,可以用命令查看版本:
bash
java -version
输出类似:
java version "1.8.0_301"
Java(TM) SE Runtime Environment (build 1.8.0_301-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.301-b09, mixed mode)
看到 1.8 就是 JDK 8,看到 11.x.x 就是 JDK 11。
二、JDK安装与配置
如果你还没安装 JDK,按以下步骤操作:
Windows 用户
- 下载 JDK:Oracle JDK 下载 或 AdoptOpenJDK
- 双击安装,记住安装路径(如
C:\Program Files\Java\jdk1.8.0_301) - 配置环境变量:
- 新建
JAVA_HOME:C:\Program Files\Java\jdk1.8.0_301 - 在
Path中添加:%JAVA_HOME%\bin
- 新建
Mac 用户
推荐用 Homebrew 安装:
bash
# 安装 JDK 8
brew install openjdk@8
# 配置环境变量(添加到 ~/.zshrc 或 ~/.bash_profile)
export JAVA_HOME=$(/usr/libexec/java_home -v 1.8)
export PATH=$JAVA_HOME/bin:$PATH
# 使配置生效
source ~/.zshrc
Linux 用户
bash
# Ubuntu/Debian
sudo apt update
sudo apt install openjdk-8-jdk
# CentOS/RHEL
sudo yum install java-1.8.0-openjdk-devel
# 配置环境变量
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH
三、Maven安装与配置
安装 Maven
Windows
- 下载:Maven 官网,选择
apache-maven-x.x.x-bin.zip - 解压到某个目录(如
C:\apache-maven-3.9.5) - 配置环境变量:
- 新建
MAVEN_HOME:C:\apache-maven-3.9.5 - 在
Path中添加:%MAVEN_HOME%\bin
- 新建
Mac
bash
brew install maven
Linux
bash
# Ubuntu/Debian
sudo apt install maven
# CentOS
sudo yum install maven
验证安装
bash
mvn -v
输出类似:
Apache Maven 3.9.5
Maven home: /usr/local/Cellar/maven/3.9.5/libexec
Java version: 1.8.0_301, vendor: Oracle Corporation
配置国内镜像(重要!)
Maven 默认从国外下载依赖,速度很慢。强烈建议配置阿里云镜像。
找到 Maven 配置文件 settings.xml:
- Windows:
C:\Users\你的用户名\.m2\settings.xml - Mac/Linux:
~/.m2/settings.xml
如果文件不存在,从 {MAVEN_HOME}/conf/settings.xml 复制一份。
在 <mirrors> 标签内添加:
xml
<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
四、IDEA创建Flink项目
第一步:创建 Maven 项目
- 打开 IDEA →
File→New→Project - 选择
Maven(不要勾选 Create from archetype) - 填写项目信息:
- Name :
flink-tutorial - GroupId :
com.example - ArtifactId :
flink-tutorial
- Name :
- 点击
Create
第二步:配置 pom.xml
这是最关键的一步。把 pom.xml 替换成以下内容:
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>flink-tutorial</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- Flink 版本,推荐使用 1.17.x 或 1.18.x -->
<flink.version>1.17.2</flink.version>
<scala.binary.version>2.12</scala.binary.version>
<slf4j.version>1.7.36</slf4j.version>
</properties>
<dependencies>
<!-- Flink 核心依赖 -->
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-streaming-java</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
<!-- Flink 客户端,本地运行需要 -->
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-clients</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
<!-- 本地运行时需要的运行时依赖 -->
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-runtime-web</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
<!-- 日志依赖 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
<!-- 打包插件,用于生成包含依赖的 jar -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.example.WordCount</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
第三步:刷新 Maven 依赖
在 IDEA 右侧找到 Maven 面板,点击刷新按钮(🔄),等待依赖下载完成。
如果下载很慢,检查是否配置了阿里云镜像。
第四步:配置运行参数
因为 Flink 依赖是 provided 作用域(生产环境由集群提供),本地运行需要额外配置:
- 点击
Run→Edit Configurations - 选择你的运行配置
- 勾选
Include dependencies with "Provided" scope
或者直接在 pom.xml 中把 <scope>provided</scope> 改成 <scope>compile</scope>(仅开发阶段)。
五、第一个WordCount程序
创建代码目录结构
src/main/java/com/example/
└── WordCount.java
WordCount.java 完整代码
java
package com.example;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.util.Collector;
/**
* Flink 入门程序:WordCount(单词计数)
*
* 功能:统计输入文本中每个单词出现的次数
*
* @author 山沐与山
*/
public class WordCount {
public static void main(String[] args) throws Exception {
// ============== 第一步:创建执行环境 ==============
// 这是所有 Flink 程序的入口,类似于 SparkContext
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// ============== 第二步:读取数据源(Source) ==============
// 这里我们用一个简单的集合作为数据源
// 实际生产中,数据源通常是 Kafka、文件、数据库等
DataStream<String> textStream = env.fromElements(
"hello flink",
"hello world",
"flink is awesome",
"hello flink world"
);
// ============== 第三步:数据转换(Transformation) ==============
DataStream<Tuple2<String, Integer>> wordCountStream = textStream
// 3.1 将每行文本切分成单词,并转换为 (单词, 1) 的形式
.flatMap(new Tokenizer())
// 3.2 按单词分组(keyBy)
.keyBy(tuple -> tuple.f0)
// 3.3 对每组数据求和
.sum(1);
// ============== 第四步:输出结果(Sink) ==============
// 这里直接打印到控制台,实际生产中会写入 Kafka、数据库等
wordCountStream.print("WordCount");
// ============== 第五步:触发执行 ==============
// Flink 是懒执行的,只有调用 execute() 才会真正开始运行
env.execute("Flink WordCount Job");
}
/**
* 自定义 FlatMapFunction:将一行文本切分成多个单词
*
* 输入:一行文本,如 "hello flink"
* 输出:多个 (单词, 1) 元组,如 (hello, 1), (flink, 1)
*/
public static class Tokenizer implements FlatMapFunction<String, Tuple2<String, Integer>> {
@Override
public void flatMap(String line, Collector<Tuple2<String, Integer>> out) {
// 按空格切分
String[] words = line.toLowerCase().split("\\s+");
// 遍历每个单词,输出 (单词, 1)
for (String word : words) {
if (word.length() > 0) {
out.collect(new Tuple2<>(word, 1));
}
}
}
}
}
六、运行与验证
在 IDEA 中运行
- 右键点击
WordCount.java - 选择
Run 'WordCount.main()'
预期输出
WordCount:3> (awesome,1)
WordCount:7> (flink,3)
WordCount:6> (world,2)
WordCount:1> (hello,3)
WordCount:4> (is,1)
输出解释:
WordCount:3>表示这条数据由第3个并行任务处理(flink,3)表示单词 "flink" 出现了 3 次
恭喜你! 你的第一个 Flink 程序已经成功运行了!
可能遇到的问题
如果报错 ClassNotFoundException,说明 Flink 依赖没有正确加载。检查:
- Maven 依赖是否下载完成
- 是否配置了
Include dependencies with "Provided" scope - 或者把
pom.xml中的provided改成compile
七、代码逐行解析
让我们把代码拆开来,一块块理解:
7.1 创建执行环境
java
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
这行代码是所有 Flink 流处理程序的起点。StreamExecutionEnvironment 可以理解为 Flink 的"总管家",它负责:
- 配置并行度、状态后端等参数
- 管理数据流的整个生命周期
- 最终提交作业到集群执行
类比一下:如果 Flink 程序是一部电影,env 就是导演。
7.2 读取数据源
java
DataStream<String> textStream = env.fromElements(
"hello flink",
"hello world",
// ...
);
fromElements() 是最简单的数据源,直接从内存中的集合读取数据。
常用的数据源还有:
| 方法 | 说明 | 场景 |
|---|---|---|
fromElements() |
从集合读取 | 测试、演示 |
fromCollection() |
从 List 读取 | 测试 |
readTextFile() |
从文件读取 | 批处理 |
socketTextStream() |
从 Socket 读取 | 实时测试 |
addSource(new FlinkKafkaConsumer()) |
从 Kafka 读取 | 生产环境 |
7.3 数据转换
这是 Flink 程序的核心部分:
java
textStream
.flatMap(new Tokenizer()) // 切分单词
.keyBy(tuple -> tuple.f0) // 按单词分组
.sum(1); // 求和
flatMap:一对多的转换。一行文本 → 多个 (单词, 1) 元组
输入:"hello flink"
输出:(hello, 1), (flink, 1)
keyBy:按 key 分组。相同 key 的数据会被发送到同一个 Task 处理
所有 key="hello" 的数据 → Task A
所有 key="flink" 的数据 → Task B
sum(1):对 Tuple 的第 2 个字段(索引为 1)求和
(hello, 1) + (hello, 1) + (hello, 1) = (hello, 3)
7.4 数据流转换过程图解
原始数据流
│
│ "hello flink"
│ "hello world"
│ "flink is awesome"
│ "hello flink world"
│
▼
┌─────────────────────────────────────────────────────────┐
│ flatMap(Tokenizer) │
│ │
│ "hello flink" → (hello,1), (flink,1) │
│ "hello world" → (hello,1), (world,1) │
│ "flink is awesome" → (flink,1), (is,1), (awesome,1) │
│ "hello flink world" → (hello,1), (flink,1), (world,1) │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ keyBy(word) │
│ │
│ hello组: (hello,1), (hello,1), (hello,1) │
│ flink组: (flink,1), (flink,1), (flink,1) │
│ world组: (world,1), (world,1) │
│ is组: (is,1) │
│ awesome组:(awesome,1) │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ sum(1) │
│ │
│ (hello, 3) │
│ (flink, 3) │
│ (world, 2) │
│ (is, 1) │
│ (awesome, 1) │
└─────────────────────────────────────────────────────────┘
7.5 触发执行
java
env.execute("Flink WordCount Job");
这行代码非常关键!Flink 程序是懒执行 的,前面所有的代码只是在构建执行计划(DAG),只有调用 execute() 才会真正开始执行。
这和 Spark 的 action 操作很像。
八、常见问题与解决
Q1:报错 java.lang.NoClassDefFoundError
原因:Flink 依赖没有正确加载
解决:
- 在 IDEA 运行配置中勾选
Include dependencies with "Provided" scope - 或者把 pom.xml 中的
<scope>provided</scope>改成<scope>compile</scope>
Q2:Maven 下载依赖很慢
原因:默认使用国外仓库
解决:配置阿里云镜像(见第三节)
Q3:报错 Could not find or load main class
原因:包路径不对
解决 :确保 WordCount.java 的 package 声明和实际目录结构一致
Q4:运行后没有输出
原因:可能是日志级别问题
解决 :在 src/main/resources 下创建 log4j.properties:
properties
log4j.rootLogger=INFO, console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p %-60c %x - %m%n
Q5:JDK 版本不兼容
原因:使用了 JDK 17+
解决:
- 切换到 JDK 8 或 11
- 或者添加 JVM 参数:
--add-opens java.base/java.lang=ALL-UNNAMED
九、总结
这篇文章我们完成了:
- 环境准备:JDK 8/11 + Maven + IDEA
- 项目配置:创建 Maven 项目,配置 Flink 依赖
- 第一个程序:WordCount 单词计数
- 代码理解 :
StreamExecutionEnvironment:程序入口Source:数据从哪来Transformation:数据怎么处理(flatMap、keyBy、sum)Sink:数据到哪去execute():触发执行
核心知识点:
| 概念 | 说明 |
|---|---|
| DataStream | Flink 中的数据流抽象 |
| flatMap | 一对多转换 |
| keyBy | 按 key 分组,相同 key 的数据去同一个 Task |
| sum | 聚合操作,对指定字段求和 |
| 懒执行 | 必须调用 execute() 才会真正运行 |
下一篇文章,我们将深入剖析 Flink 的架构,看看 JobManager 和 TaskManager 是怎么协作的,理解 Flink 是如何把任务分配到多台机器上并行执行的。
热门专栏推荐
- Agent小册
- Java基础合集
- Python基础合集
- Go基础合集
- 大数据合集
- 前端小册
- 数据库合集
- Redis 合集
- Spring 全家桶
- 微服务全家桶
- 数据结构与算法合集
- 设计模式小册
- Ai工具小册
等等等还有许多优秀的合集在主页等着大家的光顾,感谢大家的支持
文章到这里就结束了,如果有什么疑问的地方请指出,诸佬们一起来评论区一起讨论😊
希望能和诸佬们一起努力,今后我们一起观看感谢您的阅读🙏
如果帮助到您不妨3连支持一下,创造不易您们的支持是我的动力🌟