流转换 单数据流基本转换、基于Key的分组转换、多数据流转换和数据重分布转换
keyBy会将一个DataStream转化为一个KeyedStream,聚合操作会将KeyedStream转化为DataStream
keyedStream 有key的state、定时器
分区策略是hashcode
shuffle random
rebalance Round-Robin
rescale 将数据分发到就近
broadcast 广播
partitionCustom 数据重分布
Flink 中 checkpointing 执行流程
Coordinator 向所有 Source 节点发出 Barrier。
Task 从输入中收到所有 Barrier 后,将自己的状态写入持久化存储中,并向自己的下游继续传递 Barrier。
当 Task 完成状态持久化之后将存储后的状态地址通知到 Coordinator。
当 Coordinator 汇总所有 Task 的状态,并将这些数据的存放路径写入持久化存储中,完成 CheckPointing。
算子合并
上下游的并行度一致
下游节点的入度为 1
上下游节点都在同一个 Slot Group 中
下游节点的 Chain 策略为 ALWAYS
上游节点的 Chain 策略为 ALWAYS 或 HEAD
两个节点间数据分区方式是 Forward
用户没有禁用 Chain
Flink的内存管理分为三部分
Network Buffers:这个是在TaskManager启动的时候分配的,这是一组用于缓存网络数据的内存,每个块是32K,默认分配2048个,可以通过“taskmanager.network.numberOfBuffers”修改
Memory Manage pool:大量的Memory Segment块,用于运行时的算法(Sort/Join/Shuffle等),这部分启动的时候就会分配。下面这段代码,根据配置文件中的各种参数来计算内存的分配方法。(heap or off-heap,这个放到下节谈),内存的分配支持预分配和lazy load,默认懒加载的方式。
User Code,这部分是除了Memory Manager之外的内存用于User code和TaskManager本身的数据结构。
算子链 为了更高效地分布式执行,Flink会尽可能地将operator的subtask链接(chain)在一起形成task。每个task在一个线程中执行。将operators链接成task是非常有效的优化:它能减少线程之间的切换,减少消息的序列化/反序列化,减少数据在缓冲区的交换,减少了延迟的同时提高整体的吞吐量
Flink是如何做到高效的数据交换的
在一个Flink Job中,数据需要在不同的task中进行交换,整个数据交换是有 TaskManager 负责的,TaskManager 的网络组件首先从缓冲buffer中收集records,然后再发送。Records 并不是一个一个被发送的,二是积累一个批次再发送,batch 技术可以更加高效的利用网络资源。
Operator Chain是将多个Operator链接在一起放置在一个Task中,只针对Operator;Slot Sharing是在一个Slot中执行多个Task,针对的是Operator Chain之后的Task。
kafka leader 选主时,默认 flink 程序会进行重启,可以增加 RETRIES 配置,让 producer 进行重试。
开启 RETREIS 时,可能导致消息乱序,如果要求消息严格有序,配置 MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION 为 1
StreamingFileSink如何保证flink exactly once
正常流程
StreamingFileSink 首先会将结果写入中间文件,以 . 开头、in-progress 结尾。
默认策略是基于时间(60 秒)和基于大小(128 MB;
1 StreamingFileSink中会不断注册Timer来检测bucket在当前滚动策略下是否需要滚动
2 StreamingFileSink在自身做ckp的时候检测是否滚动文件
3 bucket在write期间会判断文件大小,判断是否需要滚动这些中间文件会在符合一定条件后会调用clostPartFile()更名为正式文件,
取决于用户配置的 RollingPolicy。
异常恢复
当程序出现异常重启时,中间文件会被直接关闭;
在恢复时,由于检查点中保存了中间文件名和成功写入的长度,程序会重新打开这些文件,切割到指定长度(Truncate),
然后继续写入。这样一来,文件中就不会包含检查点之后的记录了,从而实现 Exactly-once。