流/批/OLAP一体的Flink引擎 | 青训营笔记

159 阅读13分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 18 天

这里主要是Flink相关内容的解读。Flink 当前架构天然就可以支持流批一体的场景,可以做到数据同源、计算同源和结果一致,也能够覆盖 OLAP 的业务场景,大大节省了开发和维护成本。

Flink概述

大数据

  • 四个V:

    • Value
    • Volumes
    • Velocity
    • Variety
  • 发展历史:

    • 史前阶段~2006:

      • 传统数仓
      • Oracle
      • 单机
      • 黑箱使用
    • Hadoop:

      • 分布式
      • Map-Reduce
      • 离线计算
    • Spark:

      • 批处理
      • 流处理
      • SQL高阶API
      • 内存迭代计算
    • Flink:

      • 流计算(实时性很棒)
      • 实时、更快
      • 流批一体
      • Streaming/Batch SQL(支持SQL,用起来舒服)
  • Why流式计算?

    • 大数据的实时性带来价值更大,比如:
    • 监控场景:如果能实时发现业务系统的健康状态,就能提前避免业务故障。
    • 金融风控:如果实时监测出异常交易的行为,就能及时阻断风险的发生。
    • 实时推荐:比如在抖音,如果可以根据用户的行为数据发掘用户的兴趣、偏好,就能向用户推荐更感兴 趣的内容。
  • 实时性要求,带来了大数据计算架构模式的变化:

    • 批式计算

      • 离线计算,非实时
      • 静态数据集
      • 小时/天等周期性计算
    • 流式计算

      • 实时计算,快速、低延迟
      • 无限流、动态、无边界
      • 7*24 h持续运行
      • 流批一体

image-20230202095651142

流式引擎对比

image-20230202095723141

Why Flink

  • Apache Flink is a framework and distributed processing engine for stateful computations over unbounded and bounded data streams. Flink has been designed to run in all common cluster environments, perform computations at in-memory speed and at any scale.

image-20230202095937070

Apache Flink开源生态

image-20230202100027127

Flink整体架构

分层架构

image-20230202100733448

  1. SDK层: Flink的SDK目前主要有三类,SQL/Table、DataStream、Python ;
  2. 执行引擎层( Runtime层) :执行引擎层提供了统一的DAG。用来描述数据处理的Pipeline,不管是流还是批,都会转化为DAG图,调度层再把DAG转化成分布式环境下的Task,Task之间通过Shuffle传输数据;
  3. 状态存储层:负责存储算子的状态信息;
  4. 资源调度层:目前Flink可以支持部署在多种环境。

整体架构

一个Flink集群,主要包含以下两个核心组件:

  1. JobManager ( JM ) : 负责整个任务的协调工作 包括:调度task触发协调Task做Checkpoint、 协调容错恢复等;
  2. TaskManager ( TM ) : 负责执行一个DataFlow Graph的各个task以及data streams的buffer和数据交换。

image-20230202100934543

Flink Architecture: nightlies.apache.org/flink/flink…

  • Client:

    • 将用户的代码(数据处理逻辑),生成一张DAG(逻辑执行图)
    • 将这个Dataflow Graph提交给JM
  • Server

    • JM将逻辑执行图,转换为物理执行图
    • 将这个物理执行图,调度到不同的TM执行。

JobManager的指责

image-20230202101305050

  • Dispatcher:接收作业,拉起JobManager来执行作业,并在JobMaster挂掉之后恢复作业;
  • JobMaster:管理一个job的整个生命周期,会向ResourceManager申请slot,并将task调度到对应TM上;
  • ResourceManager :负责slot资源的管理和调度,Task Manager拉起之后会向RM注册;

作业示例

Flink hands on training: nightlies.apache.org/flink/flink…

  • 流式的WordCount示例,从kafka中读取一个实时数据流 ,每10s统计一次单词出现次数,DataStream实现代码如下:

image-20230202101504907

  • 业务逻辑,转换为一个Streaming DataFlow Graph:

image-20230202101632349

  • 假设作业的sink算子的并发配置为1,其余算子并发为2。紧接着会将上面的Streaming DataFlow Graph转化Parallel Dataflow ( 内部叫Execution Graph) :

image-20230202101719826

  • 为了更高效地分布式执行,Flink 会尽可能地将不同的operator链接( chain )在一起形成Task。这样每个Task可以在一个线程中执行 ,内部叫做OperatorChain,如下图的source和map算子可以Chain在一起。

image-20230202101832577

减少中间的消耗嘛,就是这个意思昂!!!

  • 最后将上面的Task调度到具体的TaskManager中的slot 中执行,一个Slot 只能运行同一个task的subTask:

image-20230202102014636

Flink如何做到流批一体

why 流批一体

举个例子:

  1. 在抖音中,实时统计一个短视频的播放量、点赞数,也包括抖音直播间的实时观看人数等。(实时性强,流式处理)
  2. 在抖音中,按天统计创造者的一些数据信息,比如:昨天的播放量有多少、评论量多少、广告收入多少。(实时性按照天来计算的,较弱了,批处理)

实时数仓&离线数仓

性能不一样,感觉大概逻辑都一样昂。

  • 上述架构有一些痛点:

    • 人力成本比较高:批、流两套系统,相同逻辑需要开发两遍;
    • 数据链路冗余:本身计算内容是一致的,由于是两套链路,相同逻辑需要运行两遍,产生一定的资源浪费;
    • 数据口径不一致:两套系统、两套算子、两套UDF,通常会产生不同程度的误差,这些误差会给业务方带来非常大的困扰。

流批一体的挑战:

  • 流批计算的区别:

image-20230202102522967

如何做到流批一体

  • 为什么可以做到流批- -体呢?

    • 批式计算是流式计算的特例,Everything is Streams,有界数据集(批式数据)也是一种数据流、一种特殊的数据流。

因此,理论上我们是可以用一套引擎架构来解决上述两种场景,只不过需要对不同场景支持相应的扩展性、并允许做不同的优化策略。

image-20230202102843914

  • Apache Flink主要从以下几个模块来做流批一体:

    1. SQL层;
    2. DataStream API层统-,批和流都可以使用DataStream API来开发;
    3. Scheduler 层架构统 ,支持流批场景;
    4. Failover Recovery层架构统一,支持流批场景;
    5. Shuffle Service层架构统一,流批场景选择不同的Shuffle Service ;

流批一体的Scheduler层

  • Scheduler层主要负责将作业的DAG转化为分布式环境中可以执行的Task:

image-20230202103059857

Before version 1.12

  • Flink 1.12版本之前,支持两种调度模式:

image-20230202103319748

  • EAGER模式:

image-20230202103356170

12个Task会一起调度,集群必须要有足够的资源(12个),才能调度昂。

  • LAZY模式:

image-20230202103516398

最小调度一个task即可,集群有一个slot资源可以运行。

After version 1.12

  • 由Pipeline的数据交换方式连接的,Task构成为一个Pipeline Region
  • 本质上,不管是流作业还是批作业,都是按照Pipeline Region粒度来申请资源和调度任务。

image-20230202103726477

流批一体的融合之路

  • ALL EDGES_ BLOCKING:

    • 所有Task之间的数据交换都是BLOCKING模式;
    • 分为12个pipeline region ;

Blocking模式:产生的数据不会立马发送,先落盘,再发送昂!(需要的资源可能会少一些)

  • ALL EDGES_PIPELINED:

    • 所有Task之间的数据交换都是PIPELINE模式;
    • 分为1个pipeline region ;

PIPELINED模式:产生的数据不落盘,立马发送,走内存昂。由于是流式的,和上面一样,需要全部的资源昂!

流批一体的Shuffle Service层

  • Shuffle :在分布式计算中,用来连接上下游数据交互的过程叫做Shuffle。
  • 实际上,分布式计算中所有涉及到上下游衔接的过程,都可以理解为Shuffle.

image-20230202104319041

Shuffle: 设计数据的分发,都可以认为是Shuffle嘛!!!

  • 针对不同的分布式计算框架,Shuffle 通常有几种不同的实现:

    • 基于文件的Pull Based Shuffle ,比如Spark或MR,它的特点是具有较高的容错性,适合较大规模的批处理作业,由 于是基于文件的,它的容错性和稳定性会更好一些 ;
    • 基于Pipeline的Push Based Shuffle,比如Flink、Storm、 Presto 等,它的特点是低延迟和高性能,但是因为shuffle数据没有存储下来,如果是batch任务的话,就需要进行重跑恢复;同时,占用的计算资源也多(需要全部的slot可能才能开始调度,实时性强)
  • 流和批Shuffle之间的差异:

    1. Shuffle 数据的生命周期:流作业的Shuffle数据与Task是绑定的,而批作业的Shuffle 数 据与Task是解耦的。
    2. Shufle 数据存储介质:流作业的生命周期比较短、而且流作业为了实时性,Shuffle 通常存储在内存中,批作业因为数据量比较大以及容错的需求,一般会存储在磁盘里。
    3. Shufle 的部署方式:流作业Shufle服务和计算节点部署在一起,可以减少网络开销,从 而减少latency,而批作业则不同。
  • Flink对于流和批提供两种类型的Shuffle,虽然Streaming和Batch Shufle在具体的策略上存在一定的差异,但本质上都是为了对数据进行Re-Partition ,因此不同的Shuffle之间是存在一定的共性的。
  • 所以Flink的目标是提供一套统- -的 Shuffle 架构,既可以满足不同Shuffle在策略上的定制,同时还能避免在共性需求上进行重复开发。
  • 在Streaming和OLAP场景:为了性能的需要,通常会使用基于Pipeline的Shuffle模式
  • 在Batch场景:一般会选取Blocking的Shufle模式

为了统一Flink 在Streaming和Batch模式下的 Shuffle架构,Flink实现了一个Pluggable的Shuffle Service框架,抽象出一些公共模块。

image-20230202105935238

  • 对于Shuffle Service, Flink开源社区已经支持:

    1. Netty Shuffle Service :既支持pipeline又支持blocking,Flink默认的shuffle Service策略;
    2. Remote Shuffle Service :既支持pipeline又支持blocking,不过对于pipeline模式,走 remote反而会性能下降,主要是有用在batch的blocking场景,字节内部是基于CSS来实现的RSS。

Flink流批一体总结

  • 经过相应的改造和优化之后,Flink在架构设计 上,针对DataStream层、调度层、Shuffle Service层,均完成了对流和批的支持。
  • 至此,业务已经可以非常方便地使用Flink解 决流和批场景的问题了。

image-20230202110101452

Flink架构优化

流/批/OLAP 业务场景概述

在实际生产环境中,针对不同的应用场景,我们对数据处理的要求是不同的:

  1. 有些场景下,只需离线处理数据,对实时性要求不高,但要求系统吞吐率高,典型的应用是 搜索引擎构建索引;
  2. 有些场景下,需对数据进行实时分析,要求每条数据处理延迟尽可能低,典型的应用是广告推荐、金融风控场景。
  • 对比:

image-20230202110256815

  • 三种场景的解决方案的要求&挑战

image-20230202110328304

三种场景为何能一站式解决

  • 通过前面的对比分析,可以发现:

    1. 批式计算是流式计算的特例,Everything is Streams,有界数据集(批式数据)也是一种数据流、一种特殊的数据流;
    2. 而OLAP计算是一种特殊的批式计算,它对并发和实时性要求更高,其他情况与普通批式作业没有特别大区别。

因此,理论上,我们是可以用一套引擎架构来解决上述三种场景, 只不过需要对不同场景支持相应的扩展性、并允许做不同的优化策略。

  • 批 is special 流,OLAP is special 批

image-20230202110946698

  • batch vs OLAP:

image-20230202111023598

Flink的OLAP的优化之路

优势

image-20230202111102286

  • Flink做OLAP的问题&挑战:

    • 秒级和毫秒级的小作业
    • Latency + QPS的要求
    • 作业频繁启停,资源碎片

image-20230202111403046

现状:

  • Client :提交SQL Query ;

  • Gateway

    • 接收Client提交的SQL Query,对SQL进行语法解析和查询优化,生成Flink作业执行计划,提交给Session集群;
  • Session Cluster

    • 执行作业调度及计算,并返回结果。
  • 作业管理及部署模块:

    1. JobManager 处理和调度作业时,负责的功能比较多,导致单作业处理时间长、并占用了过多的内存;
    2. TaskManager 部署计算任务时,任务初始化部分耗时严重,消耗大量CPU。
  • 资源管理及计算任务调度:

    1. 资源申请及资源释放流程链路过长
    2. Slot 作为资源管理单元, JM管理slot资源,导致JM无法感知到TM维度的资源分布,使得资源管理完全依赖于ResourceManager
  • 其他:

    1. 作业心跳与Failover机制,并不合适AP这种秒级或毫秒级计算场景;
    2. AP目前使用Batch算子进行计算,这些算子初始化比较耗时;

总结

  • Apache Flink最终演进结果如下:

image-20230202111803367

Stateful Computations over Data Streams: flink.apache.org/

精选案例讲解

电商流批一体实践

image-20230202112013556

  • 目前电商业务数据分为离线数仓和实时数仓建设,离线和实时数据源,计算引擎和业务代码没有统一 ,在开发相同需求的时候经常需要离线和实时对齐口径,同时,由于需要维护两套计算路径,对运维也带来压力。

从数据源,业务逻辑,计算引擎完成统一,提高开发和运维效率。

  • 演进目标:

image-20230202112523248

字节Flink OLAP实践

Flink的OLAP在字节内部的场景主要是HTAP场景。

image-20230202112841213

  • 字节内部一个业务实践:

    • 上面是原来的链路;
    • 下面是走HTAP之后的链路,Flink 直接提供数据查询与分析的能力。

image-20230202112934078

TP和AP统一到HTAP,都有了!!!好牛!!!HTAP自带提供了AP和TP的能力,很赞。

  • 原来的链路:在线 -> 离线分析,数据倒一倒。小时or天级别,耗时较长。
  • 下面HTAP一套引擎,链路秒级 or 更低。

References

  1. Flink Architecture: nightlies.apache.org/flink/flink…
  2. Flink hands on training: nightlies.apache.org/flink/flink…
  3. 流批一体的融合之路:flink-learning.org.cn/article/det…
  4. Stateful Computations over Data Streams: flink.apache.org/