1.1 异步IO的需求
? Async I/O 是阿里巴巴贡献给社区的一个呼声非常高的特性,于1.2版本引入。主要目的是为了解决数据流与外部系统交互时的通信延迟(比如等待外部系统的响应)成为了系统瓶颈的问题。对于实时处理,当需要使用外部存储数据的时候,需要小心对待,不能让与外部系统之间的交互延迟对流处理的整个工作进度起决定性的影响。
? 例如,在mapfunction等算子里访问外部存储,实际上该交互过程是同步的:比如请求a发送到数据库,那么mapfunction会一直等待响应。在很多案例中,这个等待过程是非常浪费函数时间的。与数据库异步交互,意味着单个函数实例可以并发处理很多请求,同时并发接收响应。那么,等待的时候由于也会发送其它请求和接收其它响应,被重复使用而节省了时间。至少,等待时间在多个请求上被摊销。这就使得很多使用案例具有更高的吞吐量。
? 图1.1 flink--异步IO
注意:通过增加MapFunction的到一个较大的并行度也是可以改善吞吐量的,但是这就意味着更高的资源开销:更多的MapFunction实例意味着更多的task,线程,flink内部网络连接,数据库的链接,缓存,更多内部状态开销。
1.2 使用异步IO的前提条件
使用flink的异步IO时,需要所连接的数据库支持异步客户端。幸运的是很多流行的数据库支持这样的客户端。假如没有异步客户端,也可以创建多个同步客户端,放到线程池里,使用线程池来完成异步功能。当然,该种方式相对于异步客户端更低效。
二、flink异步IO的使用
2.1 异步IO的使用方式
? flink异步IO的API支持用户在data stream中使用异步请求客户端。API自身处理与数据流的整合,消息顺序,时间时间,容错等。
假如有目标数据库的异步客户端,使用异步IO,需要实现一下三步:
1、实现AsyncFunction或者RichAsyncFunction,该函数实现了请求异步分发的功能。
2、一个callback回调,该函数取回操作的结果,然后传递给ResultFuture。
3、对DataStream使用异步IO操作。
可以看看AsyncFunction这个接口的源码
public interface AsyncFunction extends Function, Serializable {
void asyncInvoke(IN var1, ResultFuture var2) throws Exception;
default void timeout(IN input, ResultFuture resultFuture) throws Exception {
resultFuture.completeExceptionally(new TimeoutException("Async function call has timed out."));
}
}
主要需要实现两个方法:
void asyncInvoke(IN var1, ResultFuture var2):
这是真正实现外部操作逻辑的方法,var1是输入的参数,var2则是返回结果的集合
default void timeout(IN input, ResultFuture resultFuture)
这是当异步请求超时的时候,会调用这个方法。参数的用途和上面一样
而RichAsyncFunction由于继承了RichAsyncFunction类,所以还提供了open和close这两个方法,一般我们的用法是,open方法中创建连接外部存储的client连接(比如连接mysql的jdbc连接),close 用于关闭client连接,至于asyncInvoke和timeout两个方法的用法和上面一样,这里不重复。一般我们常用的是RichAsyncFunction。
2.2 异步IO官网模板实例
class AsyncDatabaseRequest extends RichAsyncFunction> {
/** The database specific client that can issue concurrent requests with callbacks */
private transient DatabaseClient client;
@Override
public void open(Configuration parameters) throws Exception {
client = new DatabaseClient(host, post, credentials);
}
@Override
public void close() throws Exception {
client.close();
}
@Ov