Flink
概述
Apache Flink 是一个框架和分布式处理引擎,用于在无边界和有边界数据流上进行有状态的计算。Flink 能在所有常见集群环境中运行,并能以内存速度和任意规模进行计算
无界流
-
有定义流的开始,但没有定义流的结束
- 持续产生数据
- 数据需要持续处理+立刻处理
- 以特定的顺序摄取事件
- 流处理
-
就是流数据
有界流
-
有定义流的开始, 也有定义流的结束
- 可以摄取所有数据后再进行计算
- 所有数据可以被排序, 不需要有序摄取
- 批处理
-
就是静态数据
Apache Flink 擅长处理无界和有界数据集
部署应用到任意地方
运行任意规模应用
- 处理每天处理数万亿的事件
- 应用维护几TB大小的状态
- 应用在数千个内核上运行
利用内存性能
- 任务状态始终保留在内存中, 如果状态大小超过内存, 那么会保存在高效访问的磁盘数据结构中
- Flink 通过定期和异步地对本地状态进行持久化存储来保证故障场景下精确一次的状态一致性。
API 和库
流处理应用的基本组件
数据管道 & ETL(抽取、转换、加载)
-
无状态的转换
-
map()
-
适用于一对一的转换
- 对每个进入算子的流元素,map() 将仅输出一个转换后的元素。
-
flatmap()
- 使用接口中提供的 Collector ,flatmap() 可以输出你想要的任意数量的元素,也可以一个都不发。
- 一变多(打散)
-
Filter()
-
Keyed Streams
rides .flatMap(new NYCEnrichment()) .keyBy(enrichedRide -> enrichedRide.startCell)
keyBy(ride -> GeoUtils.mapToGridCell(ride.startLon, ride.startLat))
-
Keyed Stream 的聚合 -
(隐式的)状态
-
考虑状态的大小
- 如果键值的数量是无限的,那 Flink 的状态需要的空间也同样是无限的。
- 在流处理场景中,考虑有限窗口的聚合往往比整个流聚合更有意义
-
reduce() 和其他聚合算子
-
有状态的转换
-
为什么要状态管理?
- 本地性: Flink 状态是存储在使用它的机器本地的,并且可以以内存访问速度来获取
- 持久性: Flink 状态是容错的,例如,它可以自动按一定的时间间隔产生 checkpoint,并且在任务失败后进行恢复
- 纵向可扩展性: Flink 状态可以存储在集成的 RocksDB 实例中,这种方式下可以通过增加本地磁盘来扩展空间
- 横向可扩展性: Flink 状态可以随着集群的扩缩容重新分布
- 可查询性: Flink 状态可以通过使用 状态查询 API 从外部进行查询。
-
Rich Functions
-
清理状态
-
Non-keyed State -
Connected Streams
-
更灵活地调整转换的某些功能
-
一个单独的算子有两个输入流 -
实例
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStream<String> control = env
.fromElements("DROP", "IGNORE")
.keyBy(x -> x);
DataStream<String> streamOfWords = env
.fromElements("Apache", "DROP", "Flink", "IGNORE")
.keyBy(x -> x);
control
.connect(streamOfWords)
.flatMap(new ControlFunction())
.print();
env.execute();
}
-
注意两个流只有键一致的时候才能连接 -
两个流中所有键相同的事件发到同一个实例上
分层API
库
运维
7 * 24小时稳定运行
-
故障时重启 -
故障时保证能够持久化服务内部各个组件状态状态
-
可持续性与一致性维护机制
-
检查点的一致性
- 应用服务会重启后,再重新加载上一次成功备份的状态检查点信息
- 保证精确一次(exactly-once)的状态一致性
-
高效的检查点
-
端到端的精确一次
-
集成多种集群管理服务
- Hadoop YARN, Mesos, 以及 Kubernetes
-
内置高可用服务
Flink能够更方便地升级、迁移、暂停、恢复应用服务
监控和控制应用服务
应用场景
事件驱动型应用
-
概念
-
应用从本地(内存/磁盘)访问获取数据
-
容错性
-
优势
-
无须查询远程数据库 -
更高的吞吐和更低的延迟 -
只需考虑自身数据
-
Flink 如何支持事件驱动型应用?
-
一系列丰富的状态操作原语
-
ProcessFunction
-
复杂事件处理(CEP)类库
-
savepoint
- 用来初始化任意状态兼容的应用
- 在完成一次 savepoint 后,即可放心对应用升级或扩容,还可以启动多个版本的应用来完成 A/B 测试
数据分析应用
-
概念
-
优势
-
省掉了周期性的数据导入和查询过程
-
获取指标的延迟更低 -
简化应用抽象
- 流式分析应用整体运行在 Flink 之类的高端流处理系统之上,涵盖了从数据接入到连续结果计算的所有步骤,因此可以依赖底层引擎提供的故障恢复机制
-
Flink 如何支持数据分析类应用?
数据管道应用
-
概念
-
优势
- 可以明显降低将数据移动到目的端的延迟
- 能够持续消费和发送数据
-
Flink 如何支持数据管道应用?
实践
目标
- 实现可扩展并行度的ETL,数据分析,事件驱动的流式应用程序
- 如何实现流数据处理管道(pipelines)
- Flink 如何管理状态以及为何需要管理状态
- 如何使用事件时间(event time)来一致并准确地进行计算分析
- 如何在源源不断的数据流上构建事件驱动的应用程序
- Flink 如何提供具有精确一次(exactly-once)计算语义的可容错、有状态流处理
流处理
-
应用程序(就是一堆处理方法, 简称算子)
-
由用户自定义算子(operator, DAG途中每块都是一个算子)转换而来的流式dataflows组成 -
这些流式 dataflows 形成了有向图,以一个或多个源(source)开始,并以一个或多个汇(sink下沉)结束 -
并行Dataflows
-
算子之间传输数据
-
一对一模式
- 例如上图中的 Source 和 map() 算子之间
- map() 算子的 subtask[1] 输入的数据以及其顺序与 Source 算子的 subtask[1] 输出的数据和顺序完全相同,即同一分区的数据只会进入到下游算子的同一分区
-
重新分发模式
-
例如上图中的 map() 和 keyBy/window 之间,以及 keyBy/window 和 Sink 之间 -
当你在程序中选择使用不同的 transformation,每个算子子任务也会根据不同的 transformation 将数据发送到不同的目标子任务
- keyBy()(通过散列键重新分区)、broadcast()(广播)或 rebalance()(随机重新分发)
-
重新分发数据的过程中,元素只有在每对输出和输入子任务之间才能保留其之间的顺序信息
- 例如,keyBy/window 的 subtask[2] 接收到的 map() 的 subtask[1] 中的元素都是有序的
-
不同键(key)的聚合结果到达 Sink 的顺序是不确定的 -
自定义时间流处理
- 使用记录在数据流中的事件时间的时间戳,而不是处理数据的机器时钟的时间戳
-
有状态流处理
-
通过状态快照实现的容错
|