目录
1.对于异步IO的需求
在与外部系统交互(用数据库中的数据扩充流数据)的时候,需要考虑与外部系统的通信延迟对整个流处理应用的影响。
简单地访问外部数据库的数据,比如使用MapFunction,通常意味着同步交互:MapFunction向数据库发送一个请求然后一直等待,直到收到响应。在许多情况下,等待占据了函数运行的大部分时间。
与数据库异步交互是指一个并行函数实例可以并发地处理多个请求和接受多个响应。这样,函数在等待的时间可以发送其他请求和接收其他响应。至少等待的时间可以被多个请求摊分。大多数情况下,异步交互可以大幅度提高流处理的吞吐量。
注意:仅仅提高MapFunction的并行度(parallelism)在有些情况下也可以提升吞吐量,但是这样做通常会导致非常高的资源消耗:更多的并行MapFunction实例意味着更多的Task、更多的线程、更多的Flink内部网络连接、更多的与数据库的网络连接、更多的缓冲和更多程序内部协调的开销。
2.异步IO API
Flink的异步IO API允许用户在流处理中使用异步请求客户端。API处理与数据流的集成,同时还能处理好顺序、事件时间和容错等。
在具备异步数据库客户端的基础上,实现数据流转换操作与数据库的异步IO交互需要以下三部分:
- 实现分发请求的AsyncFunction
- 获取数据库交互的结果并发送给ResultFuture的回调函数
- 将异步IO操作应用于DataStream作为DataStream的一次转换操作
重要提示:第一次调用ResultFunction.complete后ResultFuture就完成了。后续的complete调用都将被忽略。
下面两个参数控制异步操作:
- Timeout:超时参数定义了异步请求发出多久后未得到响应即被认定为失败。它可以防止一直等待得不到响应的请求。
- Capacity:容量参数定义了可以同时进行的异步请求数。即使异步IO通常带来更高的吞吐量,执行异步IO操作的算子仍然可能成为流处理的瓶颈。限制并发请求的数量可以确保算子不会持续累积待处理的请求进而造成积压,而是在容量耗尽时触发反压。
结果的顺序
AsyncFunction发出的并发请求经常以不确定的顺序完成,这取决于请求得到响应的顺序,Flink提供两种模式控制结果记录以何种顺序发出。
- 无序模式:异步请求一结束就立刻发出结果记录。流中记录的顺序在经过异步IO算子之后发生了改变。当使用处理时间作为基本时间特征时,这个模式具有最低的延迟和最少的开销。此模式使用AsyncDataStream.unorderedWait(...)方法。
- 有序模式:这种模式保持了流的顺序。发出结果记录的顺序与触发异步请求的顺序(记录输入算子的顺序)相同。为了实现这一点,算子将缓冲一个结果记录直到这条记录前面的所有记录都发出(或超时)。由于记录或者结果要在checkpoint的状态中保存更长的时间,所以与无序模式相比,有序模式通常会带来一些额外的延迟和checkpoint开销。此模式使用AsyncDataStream.orderedWait(...)方法。
3.封装线程池工具类
pu