异步流都在 org.apache.flink.streaming.api.operators.async 包下面

AsyncResult
AsyncResult是存放在queue的中间结果,可以是watermark(AsyncCollectionResult),也可以是用户record(AsyncCollectionResult)。
方法有四个,分别是判断watermark、判断result、获取watermark、获取result

StreamElementQueueEntry是一个抽象类,实现了大部分逻辑,剩下主要业务逻辑是getFuture和onComplete。
它有两个实现类WatermarkQueueEntry和StreamRecordQueueEntry

watermark不是异步的,所以WatermarkQueueEntry中的future是_CompletableFuture.completedFuture(watermark);表示已经完成的future。_

StreamRecordQueueEntry 用户record是异步的。只有调用complete的时候才会赋值result,表示完成。赋值result在用户自定义异步函数中进行的。

AsyncWaitOperator

将进入的element包装成StreamRecordQueueEntry
处理的时候,首先会根据超时时间timeout,来注册定时器,超时的话会调用户自定义的timeout方法,按时完成会取消对应定时器。
添加到buffer中,这个buffer是有界的,可以控制异步的数量。
调用用户的asyncInvoke方法

addAsyncBufferEntry在添加的时候使用tryPut方法,没有空间的话就会wait。

queue中消息处理是在Emitter类中。
Emitter是在open方法中初始化的,放在emitterThread线程中单独处理。

Emitter的run方法中,取出一个element,这个element是异步已经完成的结果。调用output方法,将结果发送到下游。

output中针对watermark和element分别处理,watermark比较简单。主要看element。
首先是获取result,并发送到下游,再从队列中移除这个result,最后队列腾出一个空间,唤醒可能阻塞的主线程,主线程可以继续放入队列。

可以看到缓存队列StreamElementQueue是异步的关键,正常情况下是来一条数据处理一条数据,它是同步的,现在使用StreamElementQueue将消息先缓存起来,从StreamElementQueue中出去的消息都是已经经过处理的,消息处理耗时整体缩短。
举例现在有10条消息,每条消息处理时间是1s,那么不使用异步,同步处理,处理总时间就是10s。使用异步流的话,就是10条消息会先进入StreamElementQueue中,在StreamElementQueue中同时已经处理,最快处理总时间达到1s。
StreamElementQueue
主要是三个方法,
tryPut添加element,没空间就是false,添加成功就是true
peekBlockingly、poll 两个方法都是获取第一个完成element,区别是是否移除。
它有两个实现类OrderedStreamElementQueue和UnorderedStreamElementQueue,对应有序和无序。
顺序是指的队列弹出element顺序是不是element放入的顺序,即在获取第一个完成的element是不是第一个放入的element。

OrderedStreamElementQueue
比较简单。
capacity是容量大小,queue是实际存放的队列。

tryPut,空间有剩余调用addEntry放入元素。addEntry将元素放入尾部,并注册onCompleteHandler,通知headIsCompleted。



peekBlockingly和poll类似。
在poll中,首先队列是空的或者队列头部没有完成,headIsCompleted阻塞。headIsCompleted在头部完成的时候会回调onCompleteHandler释放。队列poll移除头部。

UnorderedStreamElementQueue
无序,这个效率更高。但是这个无序并不是完全无序,是在watermark之间无序。
- uncompletedQueue中存放是按照watermark划分成的几个批次的没有完成的element
- completedQueue是已经完成的单个element
- firstSet是存放时间最久批次的element
- lastSet是当前进入的element需要存放的批次
基本思路是新的element进入后放到lastSet中,如果是watermark进入的话就新开一个批次。获取第一个完成的element的时候从firstSet中获取。

tryPut还是调用addEntry方法。如果是element,就直接加入lastSet中。是watermark就要新开批次,创建新的lastSet,将新的空的lastSet加入到uncompletedQueue。要是firstSet为空,表示没有未完成的element,将watermark加入firstSet中,firstSet不为空,有没完成的element,这个watermark插入uncompletedQueue中起隔断作用。最后注册回调函数onCompleteHandler,在element完成的时候触发。


onCompleteHandler是在element完成的时候触发。每个element的耗时都是随机的。这里首先要求firstSet中都完成,再处理下一批次。完成的element放入到completedQueue中。

peekBlockingly和poll比较简单,从completedQueue中直接获取即可。

AsyncFunction
最后就是api的使用了。org.apache.flink.streaming.api.functions.async.AsyncFunction

流程总结
