客户端的多种异步服务调用方式
——《大型网站系统与Java中间件实践》学习笔记
使用NIO能够完成连接复用以及对调用者的同步调用的支持,其调用方式,除了同步调用外,还有如下的几种调用方式。
1 Oneway方式
原理:单向(Oneway)发送特点为只负责发送消息,不等待服务器回应且没有回调函数触发,即只管发送请求而不关心结果。此方式发送消息的过程耗时非常短,一般在微秒级别。在NIO下使用oneway的话,会比同步调用简单很多,如下图所示:
把发送的数据放入数据队列中就可以继续后面的任务了。IO线程也只用从数据队列中读出数据然后通过Socket发送出去就好了,Oneway不关心对方是否接收到了数据,也不关心对方收到数据之后最什么或则有什么返回。属于不保证可靠送达的通知。
应用场景:适用于某些耗时非常短,但对可靠性要求并不高的场景,例如日志收集。
public void invokeOneway(String addr, RemotingCommand request, long timeoutMillis) throws InterruptedException, RemotingConnectException, RemotingTooMuchRequestException, RemotingTimeoutException, RemotingSendRequestException {
Channel channel = this.getAndCreateChannel(addr);
if (channel != null && channel.isActive()) {
try {
if (this.rpcHook != null) {
this.rpcHook.doBeforeRequest(addr, request);
}
this.invokeOnewayImpl(channel, request, timeoutMillis);
} catch (RemotingSendRequestException var7) {
······
}
} else {
······
}
}
上面的代码是com.aliyun.openservices包中mq的onceway的实现,可以看到invokeOnewayImpl()创建channel发送消息,其他的就不关心了。
2 Callback回调方式
这种方式下请求发送方发送请求之后会继续执行自己的操作,等对方有响应时进行一个回调。设计图如下:
上图分析:
(1)调用者首先设置了回调对象,然后将数据写入数据队列之后就可以做自己的事了。
(2)后面的IO线程也是一样,从数据队列中取出数据,建立Socket然后发送给服务端。
(3)当服务提供者返回之后,IO线程会通知回调对象,这时候就执行回调方法。
(4)如果需要支持超时,同样通过定时任务来处理,如果超时服务提供者还没有返回,这时候也执行回调方法,通知超时没有结果。
(5)这里需要注意的是,回调函数的执行最好是在单独的线程中,不要放在IO线程中执行,防止回调函数的执行时间长等问题影响了IO线程。
producer.sendAsync(msg, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
// TODO
}
@Override
public void onException(OnExceptionContext onExceptionContext) {
// TODO
}
});
上面的代码中sendAsync()方法采用就是Callback回调方式,无论msg是否发送成功,或者是否超时,都会调用SendCallback。
3 Future方式
这种实现的结构如下图:
同样是在数据入队前设置Future对象,接着就在线程中发送数据到服务提供者。等到获取到服务提供者的响应之后,就通过Future来获取通信结果并直接控制超时。
4 可靠异步方式(消息队列中间件)
可靠异步要保证异步请求能够在远程被执行,一般通过消息中间件来完成这个保障。
5 总结
上面四种异步通信方式中:
(1)Oneway是单向的通知;
(2)Callback回调是一种被动的方式,Callback的执行不是在原请求线程中。
(3)Future是一种能够主动控制超时、获取结果的方式,并且它的执行仍然在原请求线程中。
(4)可靠异步方式能保证异步请求在远程被执行。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。