1. Flink 基础与环境搭建
各位同学,咱们正式开始这门《Flink 实时规则特征计算》课程。第一节课,我不会直接扔给你一堆晦涩的概念。咱们先聊聊 Flink 是什么,它从哪来,以及怎么把开发环境跑起来。这部分是地基,地基不稳,后面盖楼会塌。
1.1 Flink 发展史:从学术项目到实时计算标配
Flink 的故事挺有意思。它最早是柏林工业大学的一个研究项目,叫 Stratosphere。那时候还没多少人知道它。我记得 2014 年 Flink 成为 Apache 顶级项目时,圈子里还在争论「流处理到底有没有未来」。
转折点出现在 2016 年左右。当时阿里开始大规模用 Flink 替换 Storm,做双十一大屏的实时计算。为什么选 Flink?说白了,Storm 的「At-Least-Once」语义在金融场景下根本不敢用,丢数据或者重复计算都是大事故。Flink 的「Exactly-Once」和「事件时间」语义,正好戳中了痛点。
后来阿里把内部的 Blink 分支回馈给社区,Flink 1.9 之后性能直接起飞。到现在,Flink 已经是实时计算的事实标准。你去看招聘网站,大数据岗位十个有八个要求 Flink 经验。
核心时间线:
- 2009年:柏林工业大学启动 Stratosphere 项目
- 2014年:成为 Apache 顶级项目,改名 Flink
- 2016年:阿里引入 Flink 替代 Storm
- 2019年:Flink 1.9 合并 Blink 特性,批流一体成熟
- 2023年:Flink 2.0 预览版发布,存算分离架构
1.2 核心概念:DataStream 与 DataSet
Flink 最核心的两个抽象,就是 DataStream 和 DataSet。你想想看,一个处理无限流数据,一个处理有限批数据。
DataStream 是实时计算的主角。数据源源不断进来,你没法等所有数据到齐再处理。比如监控用户点击行为,每秒钟几万条日志,必须来一条处理一条。DataStream 就是干这个的。
DataSet 是批处理的老大哥。数据已经完整存在,比如 HDFS 上的历史日志文件,一次性读进来做全量分析。不过从 Flink 1.12 开始,官方主推「批流一体」,DataSet API 逐渐被 DataStream 统一。我个人建议,新项目直接上手 DataStream,批处理也用它。
我的经验: 很多初学者纠结「什么时候用 DataStream,什么时候用 DataSet」。其实很简单——数据源是 Kafka、Pulsar、Socket 这种持续产生的,用 DataStream;数据源是 HDFS、本地文件这种固定大小的,用 DataStream 的批模式就行。DataSet 你了解一下概念就够了。
1.3 Flink vs Spark Streaming:到底选哪个?
这个问题我几乎每次技术交流都会被问到。咱们直接上对比表,一目了然。
| 对比维度 | Flink | Spark Streaming |
|---|---|---|
| 处理模型 | 真正的逐条流处理 | 微批次(Micro-Batch) |
| 延迟 | 毫秒级 | 秒级(取决于批次间隔) |
| 事件时间语义 | 原生支持,精确到毫秒 | 支持但实现复杂 |
| 状态管理 | 内置状态后端,支持增量快照 | 依赖外部存储(如 Redis) |
| Exactly-Once | 端到端保证 | 需要配置才能实现 |
| SQL 支持 | Flink SQL 成熟度高 | Spark SQL 生态更丰富 |
说白了,如果你的业务对延迟敏感(比如风控、实时大屏、规则引擎),Flink 是唯一选择。如果你们团队 Spark 技术栈已经很成熟,批处理为主,偶尔做做准实时,Spark Streaming 也能凑合。
我曾经帮一家金融公司做过选型评估。他们原来用 Spark Streaming 做交易反欺诈,批次间隔设到 500 毫秒,结果还是漏了几笔异常交易。换成 Flink 后,延迟降到 50 毫秒以内,规则命中率提升了 30%。嗯,这就是架构选型带来的差距。
1.4 本地开发环境搭建:IDEA + Maven + Flink 集群
光说不练假把式。咱们现在就把环境搭起来。我习惯用 IDEA + Maven + Flink Standalone 集群 这套组合,轻量、可控、适合学习。
1.4.1 前置准备
- JDK 8 或 11(推荐 JDK 8,兼容性最好)
- Maven 3.6+
- IDEA(社区版足够)
- Flink 1.17.2(当前稳定版)
1.4.2 创建 Maven 项目
在 IDEA 里新建 Maven 项目,groupId 填 com.flink,artifactId 填 flink-course。然后修改 pom.xml,加入 Flink 依赖:
<properties>
<flink.version>1.17.2</flink.version>
<scala.binary.version>2.12</scala.binary.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-java</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-streaming-java</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-clients</artifactId>
<version>${flink.version}</version>
</dependency>
</dependencies>
注意: 依赖版本一定要统一。我见过有人 flink-java 用 1.14,flink-streaming-java 用 1.17,结果运行时各种 NoSuchMethodError。所有 Flink 相关依赖保持同一个版本号。
1.4.3 第一个 Flink 程序:WordCount
写一个最简单的流式 WordCount,验证环境是否通:
public class StreamingWordCount {
public static void main(String[] args) throws Exception {
// 1. 创建执行环境
StreamExecutionEnvironment env =
StreamExecutionEnvironment.getExecutionEnvironment();
// 2. 从 socket 读取数据(先启动 nc -lk 9999)
DataStream<String> text = env.socketTextStream("localhost", 9999);
// 3. 转换逻辑
DataStream<Tuple2<String, Integer>> counts = text
.flatMap((String line, Collector<Tuple2<String, Integer>> out) -> {
for (String word : line.split(" ")) {
out.collect(new Tuple2<>(word, 1));
}
})
.keyBy(value -> value.f0)
.sum(1);
// 4. 打印结果
counts.print();
// 5. 启动任务
env.execute("Streaming WordCount");
}
}
运行前记得在终端执行 nc -lk 9999。然后随便输入几个单词,你就能看到实时统计结果了。
1.4.4 启动本地 Flink 集群
下载 Flink 压缩包,解压后进入 bin/ 目录:
./start-cluster.sh
打开浏览器访问 http://localhost:8081,看到 Flink Web UI 就说明集群起来了。你可以把刚才的 WordCount 打成 jar 包,通过 Web UI 提交运行。
避坑指南: 我曾经在 Windows 上启动集群时,发现 Web UI 一直连不上。查了半天,原来是 Windows 的防火墙把 8081 端口拦了。如果你也遇到类似问题,先检查防火墙,或者临时关掉试试。
1.5 本章知识体系总览
下面这张图帮你把本章的核心脉络串起来。你可以把它当作一张「地图」,后面每学一个新知识点,都能在这张图上找到位置。
好了,环境搭好,概念理清,咱们就可以正式开始写代码了。记住,Flink 的学习曲线不算陡,但需要你动手敲、动手跑。光看文档是学不会的。