Aysnc I/O 概念
Async I/O 是阿里巴巴贡献给社区的一个呼声非常高的特性
主要目标:是为了解决与外部系统交互时网络延迟成为了系统瓶颈的问题。
具体的概念及使用方式可以看官方文档
flink异步io
原理
先上一张原理图:
再看关键代码:
DataStream<Tuple2<String, String>> resultStream =
AsyncDataStream.unorderedWait(stream, new AsyncDatabaseRequest(), 1000, TimeUnit.MILLISECONDS, 100);
跟代码发现,其实 AsyncDataStream.unorderedWait就是构建AsyncWaitOperator算子,真正的逻辑都在AsyncWaitOperator类。
只要是算子,就看 process方法:
public void processElement(StreamRecord<IN> element) throws Exception {
// add element first to the queue
final ResultFuture<OUT> entry = addToWorkQueue(element);
final ResultHandler resultHandler = new ResultHandler(element, entry);
// register a timeout for the entry if timeout is configured
if (timeout > 0L) {
// ...
resultHandler.setTimeoutTimer(timeoutTimer);
}
userFunction.asyncInvoke(element.getValue(), resultHandler);
}
核心组件:
- StreamElementQueue:正在运行的数据,待查询的任务
- 异步的客户端:AsyncFunction.asyncInvoke,异步的工作器,当获取到结果时,会触发回调动作
注意:在java异步编程我们谈到,异步=多线程(Executors),所以 异步的客户端 可以理解为一个工作引擎。
主要流程:
- element一进来先放入工作队列(StreamElementQueue),代表有多少待处理的数据
- 构建结果回调函数resultHandler,数据来了,要做什么。其内部封装了emitter逻辑
- 调用 异步的客户端 的asyncInvoke方法,并将回调函数传进去
注意:
所以,在AsyncFunction不能做阻塞操作。
例子: 异步io查询hbase,以为hbase没有异步客户端,所以只能用java原生的异步工具。
public class AsyncDatabaseRequest extends RichAsyncFunction<OperationRecord, OperationRecordEs> {
private LyraConfiguration lyraConfiguration;
/**
* 异步执行线程池
*/
private ExecutorService executor;
/***
* 线程池的线程数
*/
private int threadCount = 10;
/**
* 构造方法
* @param lyraConfiguration
*/
public AsyncDatabaseRequest(LyraConfiguration lyraConfiguration) {
this.lyraConfiguration = lyraConfiguration;
threadCount = lyraConfiguration.getInt("threadCount");
}
private Table table1;
@Override
public void open(Configuration parameters) throws Exception {
this.table1 = Hbase11xHelper.getTable(lyraConfiguration);
executor = Executors.newFixedThreadPool(threadCount);
}
@Override
public void close() throws Exception {
Hbase11xHelper.closeTable(table1);
}
@Override
public void asyncInvoke(OperationRecord input, ResultFuture<OperationRecordEs> resultFuture) throws Exception {
CompletableFuture.supplyAsync(new Supplier<String>() {
@SneakyThrows
@Override
public String get() {
String key = "";
Result result = table1.get(new Get(key.getBytes()));
return result.toString();
}
}, executor).thenAccept((String result) -> {
OperationRecordEs operationRecordEs = new OperationRecordEs();
resultFuture.complete(Collections.singleton(operationRecordEs));
});
}
@Override
public void timeout(OperationRecord input, ResultFuture<OperationRecordEs> resultFuture) throws Exception {
}
}