Flink基本概念之数据流编程模型(DataFlow Programming Model)

功能层级抽象(Levels of Abstraction)

  Flink为开发Streaming、batch等不同的应用提供了四种不同层次的抽象:

  • Stateful Streaming是Flink提供的最低层次的抽象,并通过Process Function嵌入在DataStream API中。它允许使用者自由地处理来自一个或多个流的事件,并使用一致的容错状态。除此之外,使用者可以通过注册event time和processing time回调,使程序实现复杂的计算任务。

  • DataStream/DataSet API是Flink提供的一种层级位于Stateful Streaming智商的抽象。通常情况下,在实际生产中绝大多数应用不需要使用上述的低level的抽象,而是直接面向Flink的核心API编程,如DataSet API或DataStream API。这些连贯API为数据处理提供了常见的构建块,比如用户指定的各种形式的转换、连接、聚合、窗口、状态等。在特定的编程语言中,这些API中处理的数据类型通常用类来表示。DataStream API通过集成和嵌入低层次的Process Function,使得仅对某些操作进行低层抽象成为可能,而DataSet API在有界数据集上提供了额外的原语,比如循环/迭代。

  • Table API是一个以表为中心的声明性DSL(Domain-Specific Language),层级在DataStream/DataSet之上,它可以(在表示流时)动态地更改表。Table API遵循关系模型:Tables有一个附加的schema,这点类似于关系型数据库中的表,且API也提供了类似的操作,如select、project、join、group-by、aggregate等。Table API程序显式地定义应该执行什么逻辑操作,而不是确切地指定操作代码看起来是什么样子的。虽然Table API可以通过各种类型的用户定义函数进行扩展,但是它的表达能力不如Core API,但是相比较Core API使用起来更简洁(需要编写的代码更少)。此外,Table API程序在执行前会经过一个应用了优化规则的优化器进行优化。Tables在DataStream/DataSet之间可以进行无缝的转换,程序中可以混合使用Table API和DataStream/DataSet API。

  • SQL是Flink提供的最高层级的功能抽象,这种抽象在语义和表达方面与Table API类似,但将程序实现表示为SQL的查询表达式。SQL抽象与Table API交互密切,SQL查询可以在Table API定义的表上执行。

Levels Of Abstraction

数据流(Dataflows)

  Stream和Transformation是Flink程序的最基础构建块,而常用的用来进行批处理的DataSet API的底层实现也是基于Stream的,具体的我们会在后面详细介绍。 从概念上来说,Stream就是一个数据记录流(默认是无界的),而Transformation是一个将一条或多条数据流作为输入并输出一条或多条数据流作为结果的过程。在执行的时候,Flink程序会被映射成由Streams和Transformation操作构成的流式的数据流转(Dataflows),Stream在每个Transformation操作之间流转。每一个Dataflow从一个或多个数据源(source)开始,结束于一个或多个数据接收池(sink),Dataflow通常类似于一个任意的有向无环图(DAG)。虽然通过迭代构造可以允许特殊形式的循环存在,但为了简单起见,我们在大多数情况下会忽略这一点。通常,程序中的转换与数据流中的操作之间存在一对一的对应关系,但是有时候一个转换可能包含多个转换操作。


并行数据流(Parallel Dataflows)

  Flink中的程序本质上是并行和分布式的。在程序的执行过程中,一个Stream可以有一个或多个Stream分区,一个Operator也有一个或多个Operator子任务。每个子任务之间是相互独立的,且在不同的线程中执行,也可能在不同的机器或容器中执行。Operator子任务的个数表示当前Operator的并行度(Parallelism),而Stream的并行度总是其产生的Operator的个数。同一个程序中的不同Operator往往具有不同的并行度。

Stream可以在两个Operator之间以一对一(One-to-One)或重新分配(Redistributing)的模式传输数据。

  • One-to-One模式的流保存了元素的分区和顺序信息,例如上图中的Source和map()操作之间的流模式。这意味着Operator map()[1]会看到与源操作Source[1]生成的元素顺序相同的元素。
  • Redistributing模式的流会改变流的分区,例如上图的map()操作和keyBy/window/apply操作之间。Operator的每个子任务会根据选择的Transformation方式将数据发送给目标Operator的不同的子任务,例如keyBy(通过哈希key进行重新分区), broadcast(广播)和rebalance(随机进行重新分区)。在一次Redistributing数据传输中,每对发送和接收数据的子任务之间的元素顺序才会得以保留。因此,在上图的例子中,虽然每对子任务之间保留了每个key的顺序,但是并行的引入会导致不同key的聚合结果到达接收器的顺序的不确定性。也就是说,上图中,子任务keyBy[1]和Sink[1]之间数据是可以保证有序的,子任务keyBy[2]和Sink[1]之间数据也是可以保证有序的,但是他们在Sink中聚合的结果,是无法保证有序的。可以参考一下下面的实例:

窗口(Windows)

  在流数据上,聚合事件(如count()、sum())的工作方式与在批处理中的方式有很大不同。因为理论上来说,流数据一般是无界的,因此在无界的数据进行计数是不可能的,而批处理不一样,数据都是有界的,进行计数很容易。因此在流数据的处理上,使用window对流数据进行界限划分,例如只统计过去十分钟以内的数据、只对最新的100条数据进行求和。
Window既可以是基于时间的也可以是基于数据本身的。Window根据类型的不同,分为滚动窗口(Tumbling Window)、滑动窗口(Sliding Window)、会话窗口(Session Window)以及全局串口(Global Window)

时间(Time)

  流处理程序中具有以下几种不同概念的时间:

  • Event Time:事件的创建时间称之为Event time,它通常由事件中的时间戳来描述,例如由生产传感器或生产服务附加的时间戳。Flink通过时间戳分配程序(timestamps assigners)访问事件时间戳。
  • Ingestion Time:Ingestion time是事件在源Operator处进入Flink的Dataflow的时间
  • Processing Time:Processing time是每个operator执行一个基于时间操作的时间。

有状态的操作(Stateful Operations)

  在一个数据流中,虽然大量的操作在某一时刻只关注一个独立的事件,但有些操作能够在多个事件之间记住一些信息,这些操作被称为有状态的操作(Stateful Operations),而这些状态维护在一个内嵌的key/value形式的存储中。这些状态会随着被有状态的操作读取的流数据一起进行严格的分区。因此,只有在keyBy()函数之后才能访问key/value状态,并且只能访问与当前事件的key相关的值,如下图所示。将流的key和状态进行对齐,可以确保所有状态的更新都是本地操作(local operation),从而在不增加事务开销的同时保证一致性。这种对齐还允许Flink重新透明地分配状态并调整流数据的分区。

容错检查点(Checkpoints for Fault Tolerance)

  Flink使用流回放(Stream replay)和检查点(checkpointing)的组合实现容错。检查点与每个输入流中的特定点以及每个操作符的对应状态相关。流式数据流可以在检查点上通过恢复操作符的状态并从检查点重播事件的方式来保持一致性(一次处理语义),进而对当前的数据流进行恢复。检查点间隔是一种用恢复时间(需要重播的事件数量)来平衡执行期间的容错开销的方法。

流的批处理(Batch on Streaming)

  Flink将批处理程序作为一种特殊情况的流程序进行执行,其中流是有界的(元素的数量是有限的)。DataSet在程序内部会被视为流式的数据。因此,上面的流编程模型相关的概念同样适用于批处理程序吗,只有少数例外:

  • 批处理程序的容错不使用检查点。批处理通过完全重播流来实现容错和恢复。因为在批处理中,数据是有界的,因此这种方式是实际可行的。这种方式虽然使得恢复的代价变高,但它使常规处理更简单便捷,因为它避免了检查点。
  • DataSet API中的有状态操作使用简化的in-memory/out-of-core数据结构,而不是key/value索引。
  • DataSet API引入了特殊的同步(基于超步[Superstep])迭代,这些操作可能在有界的流数据上实现。例如Flink的图计算模块的并行计算框架,都是基于SuperStep进行实现的,具体可参考我的另一篇文章Flink-Gelly:Iterative Graph Processing
  1. https://ci.apache.org/projects/flink/flink-docs-release-1.9/concepts/programming-model.html
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,825评论 4 377
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,887评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,425评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,801评论 0 224
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,252评论 3 299
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,089评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,216评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 31,005评论 0 215
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,747评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,883评论 2 255
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,354评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,694评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,406评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,222评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,242评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,017评论 2 281

推荐阅读更多精彩内容