开发者学堂课程【开源 Flink 极客训练营:走进 Apache Flink】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/760/detail/13337
走进 Apache Flink
三、秉轴持钧–流计算的核心
1.面临的问题
流计算就是实时计算,实时意味着快,流计算首先要解决批计算计算延时的问题。所以流计算的第一个问题是微秒、毫秒的计算延时,第二个是持续更新和撤回问题,第三个问题是容错续跑(流计算作业要常年不断的进行测检,难免有机器问题或者网络问题发生异常。面对该异常问题,流计算要具备自动恢复的容错能力)。第四个问题是透明升级(流计算作业要持续进行,但是往往不是一成不变的,业务改变在升级,当某个作业需要升级作业时,流计算的引擎要有能力升级作业,这时要可以继续之前的流计算的状态进行续跑,不能影响到业务的作业升级)。第五个问题是流计算中非常典型的问题,乱序问题,流计算数据如流水般流入,在系统中由于网络或业务的种种原因会导致业务数据的乱序,如果乱序 影响到业务计算,那么流计算应该有机制来解决这种乱序第业务的影响。第六个问题是正确性问题,需要有计算正确性的保障,当流计算异常恢复时如何精确的知道上一次计算到哪个位置,只有精准的记录了从上一次计算位置进行计算并且基于原有的状态进行计算才能真正的解决计算正确性的问题。第七个问题和第八个问题是部署和扩容的问题,这是所有计算引擎需要面临的基础问题。
2.Flink 是以什么样的机制来解决流计算的问题?
Flink 要做到微秒、毫秒的延时,首先就是架构的模式,纯流架构。省去了 Micro-Batching 的瓒批和批调入的时间,同时 Flink 还具备 Early-fire 的机制。
Early-fire :假设用户点击事件不断的流入,对于一个 count 的计算用户点击事件永远不会结束。不能等待所有点击事件到齐再开始计算,只有在数据没到来之前计算,像这种事件来一个就计算一个并把结果下发的触发机制就是典型的 Early-fire。
对于更新和撤回问题,流计算要持续的计算,每次发出的结果对于上一次来说,上一次发出的结果就是应该老的计算结果,那么应该有某种机制告诉他这个结果是无效的,如果不告诉,可能会产生业务逻辑上的计算错误。
在 Flink 中,告诉从业务节点上一次的计算结果是失效的这种机制叫做撤回机制。同样没有撤回机制会造成的问题可以举个例子:
假设有一张区域订单表,id 为订单信息,region 为地区信息。需求是先按地区分组,统计每个地区的订单数量,再按照订单数量统计相对订单数量的地区数量。本质上是 select 的嵌套语句,内层的 select 是按地区分组,外层是按订单数量分组。
如果没有订单撤回机制会出现的问题:
该图中的 SH 表示上海,BJ 表示北京,SZ 表示深圳。
方向其中共有2个上海,3个北京,1个深圳。如果相同订单的地区数量为一个订单的只有深圳,两个订单的只有上海,上个订单的只有北京。
按照每个订单都产生一个计算结果,第二次按照订单数进行统计时,发现一个订单的地区有三个,两个订单的地区有两个,三个订单的地区有一个,该结果是正确的,为什么前两个订单的地区数量是错误的?该计算结果发生在每一次都 Early-fire 这个数据到下一步,但是在更新该结果时没有对以前的数据进行处理就会造成刚才的统计错误。正确的处理为:
在数据更新后,将上一次数据告诉下一步。当上海的订单为2时,需要把之前上海订单数量为1的结果标记为失效,在 Flink 中标记失效是加引号或者正负表示正常记录还是撤回记录。
对于容错续跑问题,该问题最核心的是需要在发生异常时可以自动的恢复作业,但是恢复作业不能重新计算(例如 v1 进行了两天的业务计算,不能由于作业恢复就从两天前重新进行计算)。所以需要记录当前的计算状态,同时要有某种机制在合适的时间进行状态的持续化。在 Flink 中,状态的存储和保证状态的持续化机制在 Flink 的 state 或者Checkpoint 存放机制。(更细致的讲解会在第四节)
对于透明升级问题,透明升级是必不可少的功能,业务功能和程序
bug 会自动的升级代码逻辑进行作业的升级,进行自动的升级要取
保业务升级的正确性,尤其是语义的支持。
3.对于该问题,Flink 内部依靠 state 的 Savepoint 机制进行解决。
对于乱序问题,由于网络的问题(例如手机信号的强弱造成实际得到的数据的乱序问题),如何通过计算手段解决或缓解乱序围问题?
如上图,图中有两个传感器在收集数据,小圆圈内的数据代表产生的时间,小圆圈的位置代表进入流系统的时间。如果这时想要0到5或者5到10的窗口进行划分的话,其中的事件4和事件8、9是乱序的,如果不进行数据处理,会出现计算出错的问题。也就是说8、9和4无法分到正确的窗口中。
面对该问题,Flink 利用 EventTime 和 Watermark 。
EventTime:Flink 中有三种时间类型,分别是:EventTime、ProcessingTime、IngestionTime ,这三种类型是根据时间产生的位置不同来划分的。EventTime 是时间产生时标记的,IngestionTime 是时间进入 Flink 系统时产生的,ProcessingTime 是时间被处理时标记的。
Watermark:是流计算中处理乱序的非常重要的机制,也是非常重要的概念。Watermark 的设计是计算延时和数据完整性的权衡
上图左要求所有数据完整,不丢任何一条数据。数据9的延时很强,进入触发计算的时间会推迟,延时性增强。
上图右是一个折中的 Watermark 生成策略,延时会缩小,但是会有局部的数据会丢失(9被丢失)。
对于数据正确性问题,该问题的核心是参与计算的数据是否有丢失,是否这些数据精准的被计算了一次。
目前有 At-Least-once 和Exactly-once 机制。
At-Least-once 是参与计算的数据保证都参与计算,但是数据又重复计算。
Exactly-once 是参与了并且只参与一次。
对于流计算核心问题的认识,先不关心该机制的内部,要知道问题和对应的技术手段,在后面的学习课程中,先形成一个系统上的认知。
四、学以致用一Flink应用场景
1.事件驱动型应用
第一类应用场景是事件驱动型应用。Flink 本身是有状态的的计算引擎,事件驱动型应用非常适合 Flink 进行解决。
举个例子:
如图,如果点击关注,该点击事件会触发驱动一系列的动作,比如正在关注的数量会发生变化,对方关注者的数量也会发生变化,还可能会收到被关注的一个通知等等。
第二个例子:
在网络平台,如果连续恶意的差评,可能会造成封号。或者连续多次投诉一个店家的商品,该商品可能会自动下架。
第三个例子:
金融场景,在 ATM 机上进行欺诈行为,在金融领域就应该有反欺诈的手段来解决正在业务问题。
总结一下,事件驱动型应用是一类具有状态的应用,会根据事件流中的事件触发计算、更新状态或进行外部系统操作。事件驱动型应用常见于实时计算业务中,比如:实时推荐,金融反欺诈,实时规则预警等。
2. 数据分析型应用
第二类典型应用场景是数据分析型应用,如双11成交额实时汇总,包括PV、UV的统计。
包括上方图中所示,是Apache开源软件在全世界不同地区的一个下载量,其实也是一个信息的汇总。
数据分析型应用是从原始数据之中提取有价值的信息和指标,也就是在应该数据集合中,通过统计分析、数据转换、聚合分析得到业务上想要的指标数据。
举例:
疫情防控
场景描述(简化) :
疫情数据上报是分级上报的,由社区村镇汇报到县市数据中心,最终数据会汇总到疫情防控云端统计监控系统。我们假设计算的疫情数据是在云端数据中心,我们计算的需求就是根据地区确诊病例情况进行地区防控分级管理。基本的数据流如下:
假设所有疫情数据都上报,然后由 Flink 进行应该数据分级指标,然后将数据存储到 MySQL 中,疫情防控再根据 MySQL 数据库中地区的等级进行防疫的资源部署。
计算需求:
计算频度:实时(每条)
数据集合:近14天新增报告本地感染确诊病例
分级规则:
一级:100例或者爆发性20例以上
二级:10-99例或者爆发5-19例
三级:1-9例或者爆发1-4例
四级∶0例
对前半部分需求的解决:
Flink 是支持 SQL 的,分析型应用非常便捷,比如当前疫情数据流到 Kafka,就可以定义应该 Kafka 的数据原表。和标准创建数据库几乎一样,唯一一个流计算特有的地方是需要定义一个 watermark 来控制其中的乱序问题。在定义 MySQL 表时,也要定义一个刷写的时间参数,这可以影响向下流写的实时性。
其表结构有 city(城市)、ts(时间初)、cnt(疫情感染人数)、type(等级)、level(跨地区的防疫的等级)
空间的逻辑:
近14天的含义是从当前开始到倒退14天的数据结果,对应 Flink 的实现本质上是一个 over winder 的语义,over winder 是一个标准的数据库开荒的语义。
Flink 中如何定义一个over winder ?
按数量分类,在 SQL 上面是一个CASE WHEN,同时加上另一个变量“普通案例”(SUM(cnt))和“爆发性案例”(SUM(type)),在 SQL 语句中表达会稍微臃肿了一些,在实际的业务开发中,我们最好将这些核心规则逻辑,封装为 UDF,SQL 语句表达关系计算,UDF 表达复杂的业务数据变换。
object LevelUDF extends ScalarFunction {
def eval(commonCase: Int, burstCase: Int): Int = {
…
}
完整的 SQL 逻辑:
先有一个 UDF 的过程,然后 select 语句。
3.数据管道型应用
数据管道型应用,即ETL。
在数据仓库中,是一个必不可少的环节。ETL(Extract-Transform-Load)是从数据源抽取/转换/加载/数据至目的端的过程。
在传统的数据的 ETL 中 ,转换的部分非常耗时。如果需要构建一个实时的数仓,在前面预处理的部分也要一个实时的 ETL。实时的 ETL ,Flink 不管是从架构上还是内部丰富的算子都非常适合做实时的 ETL 这部分的业务逻辑。
Flink 进行 ETL 的优势
实际的 ETL 有多源、噪音(异常数据分流/规则过滤/统一格式)和聚合 Reduce 等问题。
对于这些问题,一方面Flink有非常丰富的外部数据源的支持(例如文件系统、队列系统、数据库等等),解决多源问题。同时支持 Multi-Sink ,将结果可以入库,支持多种内置的聚合函数以及内置标量函数以及含有很多丰富的语义的算子(Join、Window等等)。无论从架构到内部功能 Flink 都非常适合构建一个实时 ETL 。
4.怎样理解流批一体/流批融合?(开放性问题)
从用户、运行和运维三个视角看:
用户并不关心是流还是批,只在意用 API 描述业务逻辑,流和批由引擎决定。
真正的流批运行,其流和批是能自动切换的,流批的选择是计算引擎内部的事情,是流批计算的优化结果。
用户 |
流批2套——>流批1套API |
流批对用户透明 |
运行 |
流批二选一——>流批自动切换 |
流批计算是优化 |
运维 |
多引擎——>单引擎 |
1引擎/1API/Auto流批(流批一体/流批融合) |