Flink
Flink
-
Flink 主要特点
- 事件驱动
- 基于流的世界观:在 Flink 的世界观中,一切都是由流组成的,离线数据是有界的流;实时数据是一个没有界限的流
- 分层API:越顶层越抽象,表达含义越简明,使用越方便;越底层越具体,表达能力越丰富,使用越灵活
- 支持事件时间(event-time)和处理时间(processing-time)语义
- 精确一次(exactly-once)的状态一致性保证
- 低延迟,每秒处理数百万个时间,毫秒级延迟
- 与众多常用存储系统的连接
- 高可用,动态扩展,实现 7*24 小时全天候运行
-
Flink 和 Spark Streaming 比较
-
流(stream)和微批(micro-batching)
-
数据模型
- spark 采用 RDD 模型
- flink 基本数据模型是数据流,以及事件序列
-
运行时架构
- spark 时批计算,将 DAG 划分不同的 stage,一个完成后才能下一个
- flink 是标准的流执行模式,一个事件在一个节点处理完后可以直接发往下一节点进行处理
-
-
Flink Standalone部署
在lib下增加hadoop依赖 flink-shaded-hadoop-2-uber-2.8.3-10.0.jar,并复制三份
vi ./conf/flink-conf.yaml # taskmanager.numberOfTaskSlots: 4 vi ./conf/slaves # hadoop03 hadoop04 ./bin/start-cluster.sh ./bin/stop-cluster.sh ./bin/flink run -c com.csmar.flink.flinktutorial.wc.StreamWordCount -p 3 /xxx/xxx/xxx/bigdata-1.0-SNAPSHOT.jar --host 192.168.10.128 --port 7777 ./bin/flink_list # 查看job的 jobId ./bin/flink cancel xxxxxxx
-
Flink Yarn部署
- Session Cluster
# -n : container,TaskManager的数量 # -s :每个 TaskManager的 slot 数量,默认一个 slot 一个 core,默认每个 taskmanager 的 slot 的个数是 1,有时候会多一些 taskmanager 做冗余 # -jm:JobManager 的内存 MB # -tm:taskmanager 的内存 MB # -nm:yarn 的appName # -d:后台执行 ./yarn-session.sh -n 2 -s 2 -jm 1024 -tm 1024 -nm test -d ./flink run -c com.csmar.flink.flinktutorial.wc.StreamWordCount bigdata-1.0-SNAPSHOT.jar --host 192.168.10.128 --port 7777 yarn application kill application_xxxxxxx
-
Per Job Cluster
# 启动 hadoop 集群 # 不启动 yarn-session,直接执行 job ./flink run -m yarn-cluster -c com.csmar.flink.flinktutorial.wc.StreamWordCount bigdata-1.0-SNAPSHOT.jar --host 192.168.10.128 --port 7777 yarn application kill application_xxxxxxx
-
Kubernates 部署
-
Flink 运行时架构
-
Flink 运行时组件
JobManager:控制应用程序执行的主进程,每个应用程序都会被一个不同的 JobManager 所控制执行
TaskManager:任务管理器。通常在Flink中会有多个TaskManager运行,每一个TaskManager都包含了一定数量的插槽(slots)。插槽的数量限制了 TaskManager 能够并行执行的速度。
ResourceManager:资源管理器,主要负责管理插槽
Dispacher:分发器,为应用提供 REST 接口
-
任务提交流程
-
Yarn上作业提交流程
-
作业调度原理及思考问题
-
slot 和任务调度
- 并行度:一个特定算子的子任务的个数被称为并行度。一般情况下,一个stream的并行度,可以认为就是其所有算子中最大的并行度
- TaskManager 和 Slots
- Flink 中每一个 Task Manager 都是一个 JVM 进程,它可能会在独立的线程上执行一个或多个子任务
- 为了控制一个 TaskManager 能接受多少个task,TaskManager 通过 task slot 来进行控制
-
程序与数据流
所有的 Flink 程序都是由三部分组成:Source 负责读取数据源、Transformation 利用各种算子进行处理加工、Sink 负责输出
-
任务链
- Flink 采用了一种称为任务链的优化技术,可以在特定条件下减少本地通信的开销。为了满足任务链的要求,必须将两个或多个算子设为相同的并行度,并通过本地转发的方式进行连接
- 相同并行度的one-to-one操作,Flink这样相连的算子链接在一起形成一个 task,原来的算子称为里面的 subtask
- 并行度相同、并且是 one-to-one 操作,两个条件缺一不可
-
-
Flink 流处理 API
kafka 进 kafka 出,可以做数据清洗
-
窗口(window)
窗口就是将无限流切割为有限流的一种方式,它会将流数据分发到有限大小的桶(bucket)中进行分析。
window类型(Time Window)
时间窗口
计数窗口
滚动窗口 Tumbling Window:固定窗口长度切分 + 时间对齐,窗口长度固定,没有重叠
滑动窗口 Sliding Window:滑动窗口由固定的窗口长度和滑动间隔组成 +窗口长度固定,可以有重叠
会话窗口 Session Window:由一系列事件组合一个指定长度的timeout间隙组成,也就是一段时间没有接收到新数据就会生成新的窗口 + 时间无对齐
窗口分配器(window assigner)
window方法接收的输入参数是一个 WindowAssigner,WindowAssigner 负责将每条输入的数据分发到正确的window中。
滚动窗口 tumbling window
滚动窗口 sliding window
会话窗口 session window
全局窗口 global window
窗口函数(window function)
增量聚合函数:每条数据到来就进行计算,保持一个简单的状态
全窗口函数:先把窗口所有数据收集起来,等到计算的时候会遍历所有数据
其他可选API
trigger() ——触发器
evictor()——移除器:定义移除某些数据的逻辑
allowedLateness()——9点输出结果,后面继续等数据,来一个处理一个,时间到了就关闭窗口
sideOutputLateDate()——放到侧输出流
时间语义
Event Time:事件创建的时间
Ingestion Time:数据进入Flink的时间
Processing Time:执行操作算子的本地系统时间,与机器有关
水位线(Watermark)
遇到一个时间戳达到了窗口关闭时间,不应该立刻触发窗口计算,而是等待一段时间,等迟到的数据来了再关闭窗口
1. Watermark 是一种衡量 EventTime 进展的机制,可以设定延迟触发
2. Watermark 是用于处理乱序事件的,而正确的处理乱序事件,通常用 Watermark 机制结合 window 来实现
3. 数据流中的 Watermark 用于表示 timestamp 小于 Watermark 的数据,都已经到达了,因此,window 的执行也是由 Watermark 触发的
4. watermark 用来让程序自己平衡延迟和结果正确性
watermark的特点
- watermark 是一条特殊的数据记录
- watermark 必须单调递增,以确保任务的事件时间时钟在向前推进,而不是在后退
- watermark 与数据的时间戳相关
watermark的设定
1. 在Flink中,watermark由应用程序开发人员生成,这通常要对相应的领域有一定的了解
2. 如果watermark设置的延迟太久,收到结果的速度可能就会很慢,解决办法是在水位线到达之前输出一个近似结果
3. 如果watermark到达得太早,则可能收到错误结果,不过Flink处理迟到数据的机制可以解决这个问题
watermark的生成
1. 间断性生成:每来一条就会生成
2. 周期性生成
窗口起始点和偏移量
状态管理
-
算子状态
- 键控状态
状态后端
一致性检查点
Flink故障恢复机制的核心,就是应用状态的一致性检查点
有状态流应用的一致检查点,其实就是所有任务的状态,在某个时间点的一份拷贝(快照);这个时间点,应该是所有任务都恰好处理完一个相同的输入数据的时候
在执行流应用程序期间,Flink会定期保存状态的一致检查点
如果发生故障,Flink 将会使用最近的检查点来一致恢复应用程序的状态,并重新启动处理流程
检查点的实现算法
—— 一种简单的想法:暂停应用,保存状态到检查点,再重新恢复应用
—— Flink的改进实现:基于Chandy-Lamport算法的分布式快照,将检查点的保存和数据处理分离开,不暂停整个应用
分界线对齐:barrier向下游传递,sum任务会等待所有输入分区的barrier到达
对于barrier已经到达的分区,继续到达的数据会被缓存
而barrier尚未到达的分区,数据会被正常处理
当收到所有输入分区的barrier时,任务就将其状态保存到状态后端的检查点中,然后将barrier继续向下游转发
Sink任务向JobManager确认状态保存到checkpoint完毕
当所有任务都确认已成功将状态保存到检查点时,检查点就真正完成了
保存点
Flink提供了自定义的镜像保存功能,就是保存点。
保存点就是具有一些额外元数据的检查点。
Flink不会自动创建保存点,用户必须明确地触发创建操作。
保存点可以故障恢复,可以用于:有计划的手动备份,更新应用程序,版本迁移,暂停和重启应用,等等
状态一致性
有状态的流处理,内部每个算子任务都可以有自己的状态
对于流处理器内部来说,所谓的状态一致性,其实就是我们所说的计算结果要保证准确
一条数据不应该丢失,也不应该重复计算
在遇到故障时可以恢复状态,恢复以后的重新计算,结果应该也是完全正确的
状态一致性分类
AT-MOST-ONCE(最多一次):当任务故障时,什么都不干,既不恢复丢失的状态,也不重播丢失的数据
AT-LEAST-ONCE(至少一次):不丢失事件,所有的事件都得到了处理,而一些事件还可能被处理多次
EXACT-ONCE(精确一次):恰好处理一次是最严格的保证,也是最难实现的。恰好处理一次语义不仅仅意味着没有事件丢失,还意味着针对每一个数据,内部状态仅仅更新一次
端到端exactly-once
1. 内部保证:checkpoint
2. source端:可重设数据的读取位置。状态回滚后,source端重设到回滚后的位置
3. sink端:从故障恢复时,数据不会重复写入外部系统
1. 幂等写入
2. 事务写入:预写日志Write-Ahead-Log Wal + 两阶段提交Two-Phase-Commit 2PC
Flink+Kafka端到端状态一致性的保证
1. 内部:利用checkpoint机制,把状态存盘,发生故障时可以恢复,保证内部的状态一致性
2. source:kafka consumer作为source,可以将偏移量保存下来,如果后续任务出现了故障,恢复的时候可以由连接器重置偏移量,重新消费数据,保证一致性
3. sink:kafka producer作为sink,采用两阶段提交sink,需要实现一个TwoPhraseCommitSinkFunction
Table API 和 Flink SQL
更新模式
追加模式(Append)
撤回模式(Retract)
更新插入模式(Upsert)
流式表查询的处理过程
1. 流被转换为动态表
2. 对动态表计算连续查询,生成新的动态表
3. 生成的动态表被转换回流