3.1 DataStream API 编程模型
想象一下:你正在经营一家24小时营业的快餐店,顾客络绎不绝地进来点餐。你不可能等所有顾客都点完餐再一起处理,而是需要实时处理每一个订单。Flink的DataStream API就像是这样一个高效的快餐店管理系统,专门用来处理源源不断的数据流。
Flink DataStream API 编程模型核心概念
核心编程模型组成
DataStream编程模型就像一条数据处理流水线,由三个核心部分组成:
Source(数据源) → Transformation(转换操作) → Sink(输出目标)
1. Source(数据源)- “水龙头”
- 作用:源源不断地产生数据流
- 比喻:就像水龙头不断流出水一样
- 常见类型:
- Kafka消息队列
- 文件系统
- Socket连接
- 内存集合
2. Transformation(转换操作)- “加工车间”
- 作用:对流经的数据进行各种处理和转换
- 比喻:像工厂流水线上的各个加工站点
- 常见操作:
- Map:一对一转换(给苹果削皮)
- Filter:过滤筛选(挑选合格产品)
- KeyBy:分组归类(按颜色分拣)
- Reduce:聚合计算(统计总数)
3. Sink(输出目标)- “出货口”
- 作用:将处理结果输出到目标系统
- 比喻:像工厂的出货口,把成品运走
- 常见目标:
- 数据库
- 文件系统
- 控制台打印
- 消息队列
编程模型的核心特点
流式处理思维
传统批处理就像批量洗衣服:
- 积累一堆脏衣服
- 一次性全部洗完
- 等待所有衣服干透
而流式处理更像24小时洗衣店:
- 有一件处理一件
- 边洗边晾
- 实时响应需求
声明式编程
你只需要告诉Flink"做什么",不需要关心"怎么做":
// 声明式:告诉Flink要做什么
dataStream.filter(order -> order.getAmount() > 100) // 筛选大额订单.map(order -> order.getCustomerId()) // 提取客户ID.keyBy(customerId -> customerId) // 按客户分组.sum(1); // 统计每个客户的订单数// 而不是命令式地告诉它每一步具体怎么执行
惰性执行(Lazy Evaluation)
DataStream API采用惰性执行策略,就像点菜系统:
- 你可以不断地在菜单上勾选菜品(定义转换操作)
- 但只有当你说"下单"时(调用execute()),厨房才开始制作
// 这些操作只是在"定义菜单",还没有真正执行
DataStream<String> processed = source.filter(data -> data.length() > 5).map(String::toLowerCase);// 只有这里才真正"下单"开始执行
env.execute("我的流处理程序");
简单示例代码
让我们通过一个简单的例子来理解整个编程模型:
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.datastream.DataStream;public class SimpleDataStreamExample {public static void main(String[] args) throws Exception {// 1. 创建执行环境(准备工厂)StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();// 2. 创建数据源(打开水龙头)DataStream<String> source = env.fromElements("hello world", "hello flink", "hello streaming");// 3. 数据转换(流水线加工)DataStream<String> processed = source.filter(line -> line.contains("hello")) // 过滤包含"hello"的行.map(line -> line.toUpperCase()) // 转为大写.flatMap((String line, Collector<String> out) -> { // 按空格分割for (String word : line.split(" ")) {out.collect(word);}});// 4. 输出结果(货物出厂)processed.print();// 5. 启动执行(开工生产)env.execute("Simple DataStream Example");}
}
编程模型的优势
统一的API设计
无论数据来自Kafka、文件还是数据库,处理方式都是一致的:
// 处理逻辑完全相同,只是数据源不同
DataStream<Event> events1 = env.addSource(new KafkaSource<>(...));
DataStream<Event> events2 = env.readTextFile("file://...");// 后续处理逻辑完全一样
events1.filter(...).map(...).print();
events2.filter(...).map(...).print();
灵活的组合能力
就像搭积木一样,你可以自由组合各种转换操作:
dataStream.filter(过滤条件).map(转换逻辑).keyBy(分组键).window(窗口).reduce(聚合逻辑).sink(输出);
自动优化执行
Flink会自动优化你的程序执行计划,就像GPS导航会自动选择最优路线一样。
与批处理的对比
特性 | 批处理(DataSet) | 流处理(DataStream) |
---|---|---|
数据特点 | 有界、静态 | 无界、动态 |
处理时机 | 数据全部到达后 | 数据到达即处理 |
延迟 | 高延迟 | 低延迟 |
应用场景 | 历史数据分析 | 实时监控、告警 |
批处理像电影院:
- 等所有观众坐好才开始放映
- 一次性播放完整部电影
而流处理更像电视直播:
- 信号来了就播放
- 实时传输,实时观看
编程模型的执行流程
// 1. 环境准备阶段
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();// 2. 构建数据流图阶段(只是定义,还未执行)
DataStream<String> result = env.addSource(new MySource()) // 定义数据源.map(new MyMapFunction()) // 定义转换.addSink(new MySink()); // 定义输出// 3. 提交执行阶段(真正开始处理数据)
env.execute("My Streaming Job");
这个过程就像:
- 准备舞台:搭建好演出场地
- 编排节目:安排好演员和流程
- 开始演出:观众入场,正式开演
小结
DataStream API编程模型的核心思想很简单:定义数据如何流动和转换。你只需要:
- 指定数据从哪来(Source)
- 描述如何处理(Transformation)
- 决定输出到哪(Sink)
- 启动执行(Execute)
这种编程模型让复杂的流数据处理变得像搭积木一样简单,同时保持了强大的功能和性能。
理解Flink DataStream API的编程模型的核心要点是:
DataStream编程模型 = Source + Transformation + Sink
就像一条数据处理的流水线,数据从源头流出,经过各种加工处理,最终输出到目标位置。这种声明式的编程方式让我们只需要关心"做什么",而不用操心"怎么做",大大简化了流数据处理的复杂度。