作者:justmine
头条号:大数据与云原生
微信公众号:大数据与云原生
创作不易,在满足创作共用版权协议的基础上可以转载,但请以超链接形式注明出处。
为了方便大家阅读,可以关注头条号或微信公众号,后续所有的文章将在移动端首发,想学习更多云原生知识,请关注我。
前言
这是分布式数据处理系统系列的第一篇,也是当下实时流计算引擎实现的奠基石,为了帮助大家从理论到实现形成一个完整的知识体系,计划分为理论篇(剖析分布式数据处理系统的核心思想)和实现篇(详解当下实时流计算引擎如何实现核心思想);大数据的核心是分布式数据处理,建议大家关注[大数据达摩院],后期更精彩哦。
先来一睹理论篇系列:
- 通俗易懂,揭秘分布式数据处理系统的核心思想(一)
- 通俗易懂,揭秘分布式数据处理系统的窗口模型(二)
- 通俗易懂,揭秘分布式数据处理系统的触发器模型(三)
- 通俗易懂,揭秘分布式数据处理系统的增量处理模型(四)
- 敬请期待...
为了分享对大规模、无边界、乱序数据流的处理经验 ,2015年谷歌发表了《The Dataflow Model》论文,剖析了流式(实时)和批量(历史)数据处理模式的本质,即分布式数据处理系统,并抽象出了一套先进的、革新式的通用数据处理模型。在处理大规模、无边界、乱序数据集时,可以灵活地根据需求,很好地平衡数据处理正确性、延迟程度、处理成本之间的相互关系,从而可以满足任何现代数据处理场景,如:游戏行业个性化用户体验、自媒体平台视频流变现、销售行业的用户行为分析、互联网行业实时业务流处理、金融行业的实时欺诈检测等。
目标
- 抽象出一个具有足够普遍性,灵活性的通用数据处理模型,统一 批量处理和流式处理,从而简化大规模数据处理管道的构建。
- 允许用户根据使用场景配置进行适应,数据处理引擎自动平衡数据的准确性、延迟程度和处理成本。
核心的设计原则
从数据类型角度,数据处理系统要处理的数据只有两种:有限数据集和无限数据集流,故应该使用有边界/无边界等词汇来描述数据源,而不是批/流;同时,为了统一数据处理类型,应该将有限数据集视为无限数据流的特例,故永远不知道数据流何时终结,新的数据只会源源不断地来,源源不断地被处理,然后源源不断地修正老的数据处理结果,而不是像传统批处理系统需要等待一个批次的数据到达完整后才处理,把关注点从等待数据完整性转变为自动适应持续变化的数据源。
Refocusing the approach from one of finding completeness in data to one of adapting to the ever present changes manifest in realworld datasets.
话外音1:不用再为了等待数据而担心失去数据的实效性,过时的计算结果可能一文不值。
话外音2:核心设计原则就是谷歌提出的一种新的数据处理思维模式。
基于这样的原则而设计出的数据处理系统,既可以处理无限数据流,也可以处理有限数据集。从数据处理逻辑角度来看,区分流/批毫无意义,因此仅保留这组词汇(流、批)用来区分数据处理引擎。
话外音1:这就是分布式数据处理系统的通用解决方案,即实时流式处理系统。
话外音2:看完这篇你就知道当下实时流计算系统(如:flink)是如何处理乱序数据了。
通用的数据处理流程
基于上面提出的核心设计原则,从数据处理逻辑上提出了通用的数据处理流程,如下:
-
What results are being computed.
计算什么结果?
-
Where in event time they are being computed.
在哪里计算?
-
When in processing time they are materialized.
何时计算?
-
How earlier results relate to later refinements.
旧的计算结果如何在后期被修正?
从四个维度上归纳了实时流式计算的所有问题,完全实现了数据处理逻辑与底层物理实现的解耦,将对数据处理引擎(批、微批、流)的选择转变为简单的对数据准确性、延迟程度和处理成本之间的选择,不仅解决了当前大数据处理引擎选型难,学习成本高的问题,也解放了高层用户的大脑,即用户只需根据实际的数据和资源情况对准确性、延迟、处理成本的要求进行评估,而无需了解底层系统,这些都是大数据工作者的事情。
话外音1:中文不是字面翻译,而是精髓哦,直接翻译英文原语大家感受不到抽象而通用的魅力,嘿嘿。
话外音2:任何底层实现(数据处理引擎)只管实现上面的处理流程,并说明擅长的特点,高层用户都能很好地选型,不仅促进了整个大数据领域朝着良性的方向持续地发展,也更切合实际。
切合实际的解决方案
再温习一遍核心的设计原则:
假设永远不知道数据流何时终结,唯一确信的是新的数据会源源不断地来,源源不断地被处理,然后源源不断地修正老的数据处理结果,而不是等待一个批次的数据完整后再处理,把关注点从等待数据完整性转变为自动适应持续变化的数据源。
流式系统中的时间语义
1、事件发生时间
事件发生时,该事件所在系统的时间戳。
2、事件处理时间
处理事件时,该事件所在系统的时间戳。
一个事件的发生时间是永远不变的,但是处理时间会随着它在数据处理管道中一步步被处理时持续变化。也就是说基于事件时间的处理为确定性计算,即每次计算结果都一样;而基于处理时间的处理为非确定性计算,即每次的计算结果可能不同。
一、计算什么结果?
计算,即加工数据, 结果,即输出数据,翻译过来就是:如何将输入数据加工成下游所需的输出数据。从数据处理的角度,Dataflow将加工过程定义数据转换,即Transformation,同时归纳出了两大类的数据转换操作,如下:
1、非聚合操作
针对每个输入元素,直接转换输出0或多个输出元素,如:Map(),FlatMap(),Reduce()函数。
对于非聚合函数,每条数据都是独立的,计算引擎只需将它转换为下游需求的格式即可,天生适用于处理无边界数据流。
话外音1:非聚合操作,Dataflow叫ParDo操作。
2、聚合操作
先按键分组聚合数据,等数据到齐后计算结果,如:Sum()、Max()、Min()函数。
对于聚合函数,在把数据发送到下游进行汇总前,为了聚合,需要先收集到指定的键对应的所有数据。如果输入源是无边界的,不知道何时才能收集到所有的数据,故Dataflow提出了窗口模型(The Window Model)来解决在哪里计算的问题。
话外音1:聚合操作,Dataflow叫GroupByKey操作。
二、在哪里计算?
从上一个步骤可以看到,聚合操作只能作用于有限数据集,故需要一种将无限数据流切分成一段段有限数据集的机制,解决计算位置的问题,于是窗口模型(windowing model)应运而生。
为了能够平衡数据准确性,必须按照数据本身的特征进行计算,即基于事件的发生时间顺序计算出的结果才是准确的,故必须按照事件时间来确定计算位置,即在哪段事件发生时间范围内计算,请看原文,如下:
Where in event time they are being computed.
话外音:为了以简洁明了的方式讲明白分布式数据处理系统的核心思想,这里不做过多阐述,感兴趣的同学,可以继续阅读《通俗易懂,揭秘分布式数据处理系统的窗口模型(二)》。
三、何时计算?
解决了在哪里计算的问题,只是向前迈了一大步,何时关闭窗口并计算出结果发往下游呢?
话外音:这是分布式数据处理的难题之一,呵呵。
方案一:水位线
为了解决窗口数据完整性的问题,那么就需要一种描述全局事件处理进度指标的机制,来等待数据完全到达,这就是水位线(watermark),可以简单理解为一个可以体现数据总体处理进度的时间戳,比如:水位线为12.00,表示早于12.00的事件已经被完全处理了,理论上讲水位线解决了窗口数据何时完整的问题。
话外音:计算机领域有句著名的名言:“没有什么解决不了的问题,如果有那就引入第三者”。
水位线真能完美的描述数据总体处理进度吗?
我们都知道,分布式存储系统为了解决强一致性问题,通常会引入协调器来管理集群,但是一旦协调器挂掉,整个系统就不能读写了,所以协调器的高可用又成了另一个问题。
同理,水印作为一个引入的组件,也存在着以下问题:
1、缺乏足够的信息来建立一个100%准确的水位标记
假如为了实现个性化推荐,自媒体平台需要收集每个视频的浏览数据,但是当有人把在没有网络的地带离线播放视频时,系统根本没有办法知道他们何时会回到有网络连接的地带,然后开始上传他们在没有网络连接时观看视频的数据,这种情况下的水位线只能通过猜测来构建。
话外音:为什么不等待的数据完整,再生成的水位线呢?这是一个鸡生蛋蛋生鸡的问题,楼主不想解释,嘿嘿。
2、本身存在延迟
考虑到分布式系统的不确定性,水印在数据处理管道中流动存在两种情况,如下:
-
太快
即在水位标记达到后仍然有记录到达,而窗口已收到数据完整信号,且触发了计算,延时的数据如何处理?
-
太慢
窗口的数据早已到齐,而水印却迟迟不到,大家都在等待水印到来触发计算,等还是不等?等多久?
综上所述,数据的完整性和数据的准确性天生都是阻抗的,水位线根本无法解决数据完整性的问题,那么就需要一种对任意窗口能够提供多种策略的触发机制,让用户能够全面参与进来,根据自己的需求来解决上面描述的所有问题,于是触发器模型(triggering model)应运而生。
话外音1:这里保留一个问题,既然水位线没有解决数据完整性的问题,为什么还需要引入,岂不是很鸡肋吗?大家评论区发表自己的看法吧。
话外音2:这里的多种策略可以是水印(事件时间),还可以记录数、会话、处理时间等,也可以实现自定义的触发器来满足任何数据聚合场景。
方案二:触发器
方案一已经讲明白了窗口触发器的来源,不明白的建议多读几遍,简单地讲,触发器可以灵活地定义在什么处理时间真正地触发计算,以及如何输出窗口的聚合结果,把关注点从保证数据的完整性转移到了对迟到数据的可适应性,从而允许数据工作者可以灵活地确定在什么处理时间点将窗口内容物化,请看原文,如下:
When in processing time they are materialized.
话外音:为了以简洁明了的方式分布式数据处理的核心思想,这里不做更多阐述,感兴趣的同学,可以继续阅读《通俗易懂,揭秘分布式数据处理系统的触发器模型(三)》。
四、 旧的计算结果如何在后期被修正?
通过引入触发器机制解决了数据完整性的问题,但并没有解决数据准确性的问题,于是增量处理模型(incremental processing model)应运而生,提出了三种修正策略,如下:
1、抛弃(Discarding)
窗口触发后,窗口内容被抛弃,之后窗口计算的结果和之前的结果彼此独立,没有相关性。
2、累积(Accumulating)
窗口触发后,窗口内容(一般保存窗口结果即可)被完整保留在后端状态中,后面窗口再次触发计算时,先取出上一次计算的窗口结果,然后根据数据处理逻辑修正结果,最后覆盖掉后端状态中的结果,同时发往下游。
3、累积和撤回(Accumulating & Retracting)
窗口触发后,窗口内容(一般保存窗口结果即可)被完整保留在后端状态中,后面窗口再次触发计算时,先取出上一次计算的窗口结果,先发给下游作撤回处理,再根据数据处理逻辑修正结果,最后覆盖掉后端状态中的结果,同时发往下游。
话外音:为了以简洁明了的方式分布式数据处理的核心思想,这里不做更多阐述,感兴趣的同学,可以继续阅读《通俗易懂,揭秘分布式数据处理系统的增量处理模型(四》。
总结
首先,该论文提出一种指导通用数据处理模型设计的核心原则,即把关注点从等待数据完整性转变为自动适应持续变化的数据源,纠正了假设输入数据(不管是无边界或者有边界的)在某个时间点后会变完整的错误思想。
其次,根据核心设计原则,从四个维度提出了通用的数据处理流程,实现了数据处理逻辑和底层物理实现(即数据处理引擎)的完全解耦,使数据处理流程更灵活,且可组合,并提出了切合实际的解决方案,如下:
- What results are being computed - Transformation(转换).
- Where in event time they are being computed - Windowing Model (窗口).
- When in processing time they are materialized - Triggering Model(触发器).
- How earlier results relate to later refinements - Incremental Processing Model(增量处理).
通过窗口+触发器+增量处理模型,不仅实现了对大规模、无边界、乱序数据集的实时处理,而且还能满足数据消费者各种复杂的语义和时间线上的各种需求。
先通过流式处理管道实时计算出一个接近精确的结果,再通过增量处理模型动态修正,最终提供一个完全准确的结果,实现了数据正确性、延迟程度、处理成本之间的自适应,完美地权衡了现实世界中多样化的数据处理场景。
话外音:目前已有go、java、python语言的SDK实现了该模型,实现该模型的数据处理引擎有Apache Apex, Apache Flink, Apache Spark, Google Cloud Dataflow and Hazelcast Jet,可以说《The Dataflow Model》是构建现代分布式数据处理系统的基石,特别是实时流式处理系统,也把分布式数据处理领域带入了新的高度,可谓是功在当代,利在千秋。
延伸阅读
最后
如果有什么疑问和见解,欢迎评论区交流。
如果你觉得本篇文章对您有帮助的话,感谢您的【推荐】。
如果你对大数据感兴趣的话可以【关注我】或头条APP搜索【大数据达摩院】
我会定期在博客园和头条同步更新后续文章。