发表于 2019-07-15 | 分类于 大数据 | 0 | 本文总阅读量 165次
Flink异步IO源码简析。
使用Redisson框架封装的异步请求API。
对key进行异步累计递增计数和计算业务值并保存在Redis中。
Lua脚本和事务API。
FLINK v2-异步IO的设计与实现
Flink使用异步IO访问外部数据
AsyncRedisJob代码
AsyncFunction
AsyncFunction是一个异步算子接口,本身继承Function和Serializable。
asyncInvoke()方法会对每一个上游任务下发的流数据进行异步操作,操作完了将结果输出到ResultFuture,回调方式是把ResultFuture传入回调API,Future方式是要调用resultFuture.complete才算异步调用完成【回调和Future看外部系统客户端的封装】。
timeout()方法用来处理异步调用超时的问题,有default修饰,有默认实现,可以不做处理,但通常要做进一步处理。
|
|
AsyncFunction的使用:可以通过直接实现AsyncFunction接口的方式来自定义访问外部系统,比如HBase。
使用回调函数的例子:
|
|
使用Future的例子:
|
|
RichAsyncFunction
RichAsyncFunction是个抽象类,由于继承了AbstractRichFunction,也就实现了RichFunction,RichFunction里面有着更多比较有用的方法,比如可以使用重新实现后的RuntimeContext。
Function是在DataStream里的各种算子中被调用的。
异步的AsyncFunction会被传入AsyncWaitOperator中,AsyncWaitOperator的processElement方法会去调用asyncInvoke(),会注册一个定时器去调用timeout()方法。
AsyncWaitOperator是在异步的DataStream辅助类AsyncDataStream中被实例化后传入DataStream的transform()方法中被调用【算子名称是「async wait operator」】。
RichFunction接口
|
|
RichAsyncFunction接口,主要是实现了RichAsyncFunctionIterationRuntimeContext和RichAsyncFunctionRuntimeContext。
RichAsyncFunctionRuntimeContext:这个运行时上下文只支持线程安全的一些基本操作,像状态、全局累加、广播变量和分布式缓存都是不支持的。
RichAsyncFunctionIterationRuntimeContext:本身继承RichAsyncFunctionRuntimeContext,所以限制同上,只是实现了IterationRuntimeContext接口。
|
|
AsyncWaitOperator
主要看下processElement()方法,它是在OneInputStreamOperator接口中定义的,OneInputStreamOperator继承自StreamOperator接口。
另外,如果需要自定义Operator,可以继承AbstractStreamOperator,也可以通过实现OneInputStreamOperator或TwoInputStreamOperator。
AbstractUdfStreamOperator是用于自定义Function的抽象类,主要是用来处理自定义Function的打开和关闭;它也是StreamOperator,因为它继承了AbstractStreamOperator,而AbstractStreamOperator实现了StreamOperator。
|
|
AsyncDataStream
AsyncDataStream是DataStream的辅助类,提供unorderedWait和orderedWait的静态方法,方法里是添加异步算子即AsyncWaitOperator。
其中维护了一个有序和无序的枚举,一个默认的队列容量100。
需要传入一个上游的DataStream、一个自定义的AsyncFunction(RichAsyncFunction)和超时时间,缓冲区队列大小和顺序可以默认。
|
|
AsyncRedisRequest
示例,没有太多逻辑。
继承自RichAsyncFunction。
在open方法中创建RedissonClient。
在close方法中关闭RedissonClient。
在asyncInvoke实现异步调用。
在timeout中处理超时。
|
|
示例Job:异步执行Redisson事务和Lua脚本
数据源Kafka
kafka的server.properties中,num.partitions=3。
|
|
使用事务异步提交
RFuture commitAsync();是没有返回结果的,即Void,对于超时的最好重写timeout进行处理。
|
|
transaction.getMap,transactionMap.isExists()和后续的计数、能量的计算在partition>1即多个线程执行的时候,是非线程安全的。
transaction本身也不是分布式事务,所以并发+异步情况下直接使用redisson的transaction是不合适的。
|
|
异步执行lua脚本
lua脚本,需要注意isExists返回的可能不是false而是0。
异步和同步执行的结果差异:4) “\xfc\x05907.0” These letters are object header written by FstCodec
|
|
|
|
需要注意Codec。
要反复确认whenComplete是否能够拿到异步执行的结果,确定是否走同步执行lua脚本。
|
|
异步执行lua测试,先后发送了5和15条数据,共3中astyle:
|
|
Redis情况:
|
|
来源:oschina
链接:https://my.oschina.net/u/4279029/blog/4474275