聊聊Flink异步I/O机制的原理

在不久前的这篇文章中,提出了一种用Flink做流处理时join外部维度数据的简单方法。但是它的适用情境毕竟有限,通用的方法则是从Flink 1.2版本引入的异步I/O(Async I/O)机制。

异步I/O专门用来解决Flink计算过程中与外部系统的交互问题。在默认情况下,算子向外部系统发出请求后即阻塞,等待结果返回才能发送下一个请求,可能会造成较大的延迟,吞吐量下降。有了异步I/O之后,就可以并发地发出请求和接收响应,延迟大大降低。下图来自官方文档,一看便知。

要享受异步I/O带来的便利,前提就是我们有一个能异步请求外部系统的客户端。如果原生没有提供,就得自己创建有限大小的线程池,将客户端放到线程池里调用。

异步I/O的原始设计文档见FLIP-12。但是随着时间的推移,它里面的内容与目前最新的Flink 1.9版本的实现有了一定出入,所以就不参考它了,直接讲讲笔者读过1.9版本的相关源码之后总结出的东西吧。

在调用AsyncDataStream.orderedWait()/unorderedWait()方法时,本质上是产生了一个AsyncWaitOperator算子,它是异步I/O的核心。每个AsyncWaitOperator都由三个主要的部分组成。

  • AsyncFunction:执行异步操作的函数,用户需要覆写其asyncInvoke()方法并传入。
  • StreamElementQueue:包含StreamElementQueueEntry的队列,底层由ArrayDeque实现。
  • Emitter:单独的守护线程,将异步调用完成后的结果发送给下游算子。

所谓StreamElementQueueEntry就是StreamElement(Flink基础概念,可以是流中的一条数据,或是一个水印等)的简单封装,通过j.u.c.CompletableFuture实现异步返回。CompletableFuture是JDK 8提供的新特性,可以认为是非常好用的Future改进版,这里就不再展开讲了。

以下是以StreamElementQueueEntry为中心展开的类图。看官会注意到它有两种实现:代表数据的StreamRecordQueueEntry,和代表水印的WatermarkQueueEntry。它们都持有CompletableFuture。

AsyncWaitOperator的机制可以用下面的简图来表示。

  1. 来自上游的StreamElement进入AsyncWaitOperatorStreamElementQueue,并被封装成StreamElementQueueEntry
  2. AsyncWaitOperator调用传入的AsyncFunction的asyncInvoke()方法,该方法异步地与外部系统交互。
  3. 异步操作完成后,由asyncInvoke()方法显式地调用ResultFuture.complete()方法,将结果返回;或者调用completeExceptionally()方法表示出现了异常。ResultFuture就是CompletableFuture的代理接口。
  4. Emitter线程从StreamElementQueue中拉取那些已经完成了的StreamElementQueueEntry,并输出到下游算子。

以上的分析说明了AsyncWaitOperator的工作流程,但是没有考虑输出流的顺序性。实际上会有以下两种情况:

  • 调用AsyncDataStream.orderedWait():创建OrderedStreamElementQueue队列,保持请求的顺序与输出结果的顺序相同,亦即先进先出。
  • 调用AsyncDataStream.unorderedWait():创建UnorderedStreamElementQueue队列,不保持顺序。在采用处理时间时,先返回的结果先输出。而采用事件时间时,需要额外保证水印的边界不错乱。

简单讨论一下。

  • 有序
    有序是最简单的情况,只需要将元素按照到来的顺序放入OrderedStreamElementQueue。只有当队列中的队头请求异步操作返回了结果,才会触发Emitter输出,后面的请求先返回也只能等待。
  • 无序(处理时间)
    这种情况也不难办。在UnorderedStreamElementQueue中维护两个子队列,一个是未完成请求的队列(uncompletedQueue),一个是已完成请求的队列(completedQueue)。所有请求都先进入uncompletedQueue并执行异步操作,并按照操作完成的顺序进到completedQueue中。Emitter从completedQueue拉取并输出结果即可。如下图所示。
  • 无序(事件时间)
    这是比较复杂的情况:我们允许两个水印之间的元素乱序,但是水印不能乱。所以在使用两个队列的同时,uncompletedQueue中还必须存储水印,这就是上面的WatermarkQueueEntry的由来。在水印之间存储的也不再是单个StreamElementQueueEntry,而是它们的集合。只有当uncompletedQueue中的队头集合有元素的异步操作返回了,才能将其移动到completedQueue里面。这样就可以保证在通过某个水印之前,它前面的所有异步请求都完成。如下图所示。

异步I/O的检查点做起来很容易。由上面的分析可以知道,StreamElementQueue保存的就是尚未完成异步请求的元素,以及已完成异步请求但还没有送到Emitter发送的元素,只要遍历该队列,并将它们都放入状态后端就OK。

转载链接:https://www.jianshu.com/p/98ffb9ad0177

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容

  • 在不久前的这篇文章中,提出了一种用Flink做流处理时join外部维度数据的简单方法。但是它的适用情境毕竟有限,通...
    LittleMagic阅读 1,748评论 4 12
  • 背景 Async I/O 是阿里巴巴贡献给社区的一个呼声非常高的特性,于1.2版本引入。主要目的是为了解决与外部系...
    尼小摩阅读 966评论 0 3
  • 本页阐述了使用Flink的API来进行外部数据存储的异步I/O,对于不熟悉异步或者事件驱动编程的用户,一篇关于Fu...
    写Bug的张小天阅读 6,443评论 1 3
  • 1 概述 流计算系统中经常需要与外部系统进行交互,我们通常的做法如向数据库发送用户a的查询请求,然后等待结果返回,...
    薛定谔的猫Plus阅读 4,645评论 0 5
  • 爷爷和奶奶是包办婚姻。当时奶奶家比较贫困,但是有七个孩子,奶奶正好是卡在中间不大也不小的那个孩子,因为迫于生活压力...
    一渔_阅读 315评论 12 2