flink杂记
flink的特点:能同时满足高性能、高吞吐、低延时,相比较于storm和spark streaming,storm的吞吐量不如flink,而spark streaming的延时比较高,因为spark streaming进行流式计算的原理就是微批操作,就是要积累一定的时间,虽然可以尽量降低这个时间粒度,但是延时指标还是会比flink要高
- 同时支持高吞吐、低延时、高性能
- 支持事件时间概念(event time)
- 支持有状态计算(状态就是中间计算结果,每次计算新的数据进入到流式系统中都是基于中间状态结果进行计算,不需要利用原始数据重新计算,这样提升了计算效率)
- 支持高度灵活的窗口计算
- 基于轻量级分布式快照实现的容错(利用checkpoint实现高度容错的状态管理)
- 基于jvm实现独立的内存管理
- save points(保存点)
flink的基本架构
客户端:客户端通过建立akka连接提交任务给JobManager,并且通过JobManager获取任务状态和执行情况。
JobManager:相当于Master,负责任务管理和资源管理,JobManager接受到客户端提交的任务以后,会根据TaskManager的Task Slot情况进行任务的分配,并且通过Actor system和TaskManager进行通信,获取任务的执行状态返回给客户端;同时在任务执行的过程中会触发Checkpoints操作,TaskManager收到checkpoint指令后完成checkpoint操作,所有的checkpoint协调过程都是在JobManager中完成的。
TaskManager:相当于Slave,负责任务的执行和任务在每个节点上的资源申请和管理。
有界数据集:有明确时间范围的起始和结束,用于批计算
无界数据集:会一直产生的数据,没有明确时间范围的起始和结束,用于流处理
spark streaming对有界数据集进行批处理,对无界数据集进行微批处理从而实现流计算;实际上有界数据集合无界数据集是可以相互转化的,利用这个思想,flink利用统一的流处理模式处理不同类型的数据集
flink的开放API
- SQL API
- Table API:在DataSet和DataStream的基础上多了一层Schema信息,将 数据集注册成表
- DataSet/DataStream API
- Stateful Stream Processing API:最底层的API,可以操作状态、时间等底层数据
flink程序的主要步骤
- 设定执行环境
- 创建和加载数据集
- 对数据集指定转换操作逻辑
- 指定计算结果输出位置
- 触发程序执行
flink的编程模型采用DataFlow模型,主要需要实现三种DataStream API:Data Source/Transformation/Data Sink
flink内部常见数据重分区策略
- Random Partitioning:通过随机的方式将数据分配在下游算子的每个分区中,分区相对均衡,但是会破坏原有数据的分区结构
- Roundrobin Partitioning:通过循环的方式对数据集中的数据进行重分区,数据会全局性的通过网络介质传输到其他节点完成数据的重新平衡,尽可能的保证每个分区的数据平衡,当数据集发生数据倾斜的时候使用这种策略是比较有效的优化方法
- Rescaling Partitioning:仅仅针对上下游继承的算子进行重平衡,具体的分区要根据上下游算子的并行度决定
常见的几种通过创建Class实现Function接口
- MapFunction[T, O]需要指定输入输出的流数据类型
- FilterFunction[T]
- ReduceFunction[T]
- 还可以通过实现RichFunction接口,用于比较高级的数据处理场景,接口中有open, close, getRuntimeContext, setRuntimeContext等方法来获取状态,缓存等系统内部数据.
WaterMark
watermark学习
window计算
- flink会根据上游数据集是否为KeyedStream类型,进行不同的window计算,如果是,则根据key在不同的task实例中并行分别计算,如果不是,则用windowAll()方法,将所有数据路由到一个task钟计算,得到全局统计结果(很容易反压导致延迟)
Tumbling Windows:根据固定时间进行切分,窗口连续不重叠,适用于按照固定大小和周期统计某一指标
Sliding Windows:在Tumbling Windows的基础上增加了滑动时间,当滑动时间和窗口大小相等,则两种窗口等价,适用于根据设定频率计算指定窗口大小的统计指标,例如每隔30s统计最近10min的活跃用户
Session Windows:将某段时间内活跃度较高的数据聚合成一个窗口,不需要固定窗口大小和滑动时间,只需要定义session gap,表示多长时间没有活跃数据则触发window,若数据一直不间断进入窗口,有可能导致窗口始终不触发的情况,适用于非连续性数据处理或周期性产生数据的场景
Global Windows:没有起始时间和结束时间,需要自定义触发器来触发,还需要指定数据清理机制,否则数据将一直留在内存中,最终导致内存溢出
- 常用Window Function:
- ReduceFunction/AggregateFunction:基于中间状态计算的增量聚合函数,性能较高
- ProcessWindowsFunction:基于窗口全部数据计算的聚合函数,可以利用窗口状态数据和元数据进行更复杂的计算
多流合并需要保证输入的stream要构建在相同的Window上,并使用相同的key作为关联条件,且每个stream中都要有key与key能关联才会有输出结果
状态管理
Keyed State事先按照key对数据进行了分区,而Operator State只和并行的算子实例绑定
状态管理的两种形式:Managed State由Flink Runtime控制和管理状态数据,并将状态数据存储到内存以及通过外部接口持久化到Checkpoints中,任务异常可以通过状态数据恢复任务;而Raw State是由算子自己管理数据结构,触发Checkpoint过程中,只是将数据序列化到Checkpoints中,恢复任务时再反序列化回来,相比较之下,Managed State能更好的支持状态数据的重平衡以及更加完善的内存管理
- 状态管理器
- MemoryStateBackend:基于内存的状态管理器,将状态数据全部存储在JVM堆内存中,具有快速高效的特点,但是有内存容量的限制;聚合类算子的状态会存储在JobManager的内存中,因此聚合类算子比较多的应用会对JobManager造成较大压力,在创建MemoryStateBackend时最好指定状态初始化内存大小,这种方式比较适用于测试环境,用于本地的测试和验证
- FsStateBackend:基于文件系统的状态管理器,将状态数据存储在文件系统中,可以采用同步/异步的方式同步数据,最大的好处就是相对比较稳定,能最大程度保证数据的安全性,不会因为外部故障导致任务无法恢复,适用于状态数据非常大的场景
- RocksDBStateBackend:flink中内置的第三方状态管理器,采用异步的方式进行状态数据的同步,状态数据首先写入RocksDB,然后异步写入文件系统,对于热点数据存储在RocksDB,长时间才更新的数据则写入磁盘进行存储,而体量比较小的数据则直接存储在JobManager的内存中,因此性能比FsStateBackend高,也适用于状态数据非常大的场景.
批处理DataSet API
利用广播变量和分布式缓存进行数据的共享,让每台计算节点都能在本地获取数据文件,进而提升分布式计算环境下数据处理的效率:实现RichFunction接口,通过实现open()方法调用getRuntimeContext()方法获取广播变量或分布式缓存.
flink部署模式
- local模式:适用于本地开发和测试环境,占用的资源较少,部署简单,只需要部署JDK和flink即可达到功能开发和测试的目的。只需要一台主机即可。
- standalone cluster:可以在测试环境功能验证完毕到版本发布的时候使用,进行性能验证。搭建需要ssh、jdk和flink。至少需要3台主机,一个master两个worker节点。使用自带的资源管理器
- YARN:flink使用YARN进行调度。有两种模式,一是yarn session model,这种模式flink会向yarn申请足够多的资源,并在yarn上启动长时间运行的flink session集群,用户将任务提交到flink session集群上运行,从而不再与yarn进行交互,让flink应用在相同的集群环境上运行,屏蔽底层不同的运行环境;另一种是single job model,每个flink任务单独向yarn提交一个application,并且有独立的JobManager和TaskManager,任务结束对应组件的资源也会被释放
- kubernetes:更加方便进行管理和运维
HA模式:
现在主流的方式有standalone cluster HA 和YARN cluster HA方式,适用于在生产上部署。
standalone cluster HA利用zookeeper完成JobManager leader的选举,多个JobManager只有一个处于工作模式,其他处于standby模式
YARN cluster HA通过重启的方式保证JobManager高可用