Flink基础

内容参考自:

  1. Apache Flink 零基础入门(一):基础概念解析

有状态流式处理

概念

传统批次处理: 持续收集数据,以时间作为批次划分的依据,周期性执行批次运算,这样可能存在的场景问题:

  • 假如一个小时作为一个批次划分的依据,需要统计特定事件转换次数,开始转换发生在第58分钟,结束转换在下一个小时的第7分钟,那么如何完成跨批次的数据统计?
  • 数据从产生到被接收中间耗时不一定,可能某个事件发生早于A,但到达时间晚于A,如何处理这种接收到的时间顺序颠倒问题?

理想方法就是:

  • 引入状态(State)机制,可以累积状态和维护状态,累积状态代表着过去历史中接受过的所有历史事件,对输出结果有影响
  • Time时间机制: 有机制可以做到对数据完整性的操作,比如设定只有某个时间段上的数据全部都接收到后,再计算输出结果

这就是所谓的有状态流式处理

有状态流式处理的挑战

  • 状态容错(State Fault Tolerance):
  • 状态维护(State Management):
  • Event-time处理 (Event-time processing):
  • 状态保存与迁移(Savepoints and Job Migration):

状态容错

简单场景的精确一次(Exactly-once)容错保证:
无限流的数据进入,但后面是单一Process的计算,这种情况下如果要确保 Process 产生精确一次的状态容错,每处理完一笔数据,更改完状态后进行一次快照,快照包含在队列中并与相应的状态进行对比,完成一致的快照,就能确保精确一次

分布式状态容错
  • 在分布式场景中,多个节点计算进行本地状态的修改,但只产生一个Global consistent snapshot(全域一致性的快照)

  • 基于checkpoint检查点机制进行容错恢复

  • 基于simple lamport 演算法机制的延伸实现分布式快照,Flink可以做到再不中断计算的状态下持续完成Global consistent snapshot(全域一致性的快照)。大致方法就是Flink会在数据流中插入 checkpoint barrier标志位,后续的Operator在数据流中收到checkpoint barrier N后就会将自己的状态保存,这样从最开始的数据源到计算完成后都建立了这次的checkpoint保存状态,后面还有checkpoint barrier N+1、N+2也同时在数据流中同步进行,这样就可以做到在不阻挡运算的状况下持续地产生Checkpoint

状态维护

Flink目前支持的方式有:

  • JVM Heap存储状态: 适合状态量不大的情况下,因为直接存储在JVM heap上,当需要读取状态时,是直接用Java object进行的读写,不需要序列化。但当 Checkpoint 需要将每一个运算值的本地状态放入 Distributed Snapshots 的时候,就需要进行序列化了

  • RocksDB存储状态: 一种 out of core 的状态后端。在 Runtime 的本地状态后端让使用者去读取状态的时候会经过磁盘,相当于将状态维护在磁盘里,与之对应的代价可能就是每次读取状态时,都需要经过序列化和反序列化的过程,性能可能相对来说差一点

Event-time处理

  • 处理时间(Processing Time): Process Time 相当于事件到达然后开始进行处理的时间,是不一定的,比如网络原因这个时间都会变化
  • 事件时间(Event Time): Event Time 就是事件实际发生的时间,根据每一条处理记录所携带的时间戳来判定,这个是唯一且不变的
  • 接入时间(Ingestion Time): 是指事件在 source 运算符中进入 Flink 数据流的时间

对比

  • Processing Time 处理起来更加的简单,而 Event Time 要更麻烦一些
  • 使用 Processing Time 的时候,我们得到的处理结果(或者说流处理应用的内部状态)是不确定的。而因为 Flink 内部对 Event Time 做了各种保障,使用 Event Time 的情况下,无论重放数据多少次,都能得到一个相对确定可重现的结果
  • 判断应该使用 Processing Time 还是 Event Time 的时候,可以遵循一个原则:当你的应用遇到某些问题要从上一个 checkpoint 或者 savepoint 进行重放,是不是希望结果完全相同。如果希望结果完全相同,就只能用 Event Time;如果接受结果不同,则可以用 Processing Time。Processing Time 的一个常见的用途是,我们要根据现实时间来统计整个系统的吞吐,比如要计算现实时间一个小时处理了多少条数据,这种情况只能使用 Processing Time

参考链接

状态保存与迁移

基于Savepoint机制实现,Savepoint跟checkpoint类似,不同在于Savepoint是手动触发用于全局状态保存的,具体参考链接:
Flink实时计算-深入理解 Checkpoint和Savepoint

Flink基本概念

  • Streams: 流,分为有限数据流与无限数据流,unbounded stream 是有始无终的数据流,即无限数据流;而 bounded stream 是限定大小的有始有终的数据集合,即有限数据流,二者的区别在于无限数据流的数据会随时间的推演而持续增加,计算持续进行且不存在结束的状态,相对的有限数据流数据大小固定,计算最终会完成并处于结束的状态。

  • State: 状态是计算过程中的数据信息,在容错恢复和 Checkpoint 中有重要的作用,流计算在本质上是 Incremental Processing,因此需要不断查询保持状态;另外,为了确保 Exactly- once 语义,需要数据能够写入到状态中;而持久化存储,能够保证在整个分布式系统运行失败或者挂掉的情况下做到 Exactly- once,这是状态的另外一个价值。

  • Time: 分为 Event timeIngestion timeProcessing time,Flink 的无限数据流是一个持续的过程,时间是我们判断业务状态是否滞后,数据处理是否及时的重要依据。

  • API: API 通常分为三层,由上而下可分为 SQL / Table APIDataStream APIProcessFunction 三层,API 的表达能力及业务抽象能力都非常强大,但越接近 SQL 层,表达能力会逐步减弱,抽象能力会增强,反之,ProcessFunction 层 API 的表达能力非常强,可以进行多种灵活方便的操作,但抽象能力也相对越小

  • 以事件数量驱动的Count Window
  • 以会话间隔驱动的Session Window
  • 以时间驱动的Time Window