铺垫

先简单介绍下一次完整的Dubbo调用所经历的线程阶段。几个信息这里罗列下

  1. Biz~代表业务线程,即便是业务逻辑处理所处的线程,Biz~线程池可能是业务自己创建维护,大多数的可能是系统框架自身管理的(比如web型的业务系统跑在Tomcat容器下,Biz~线程就是Tomcat维护);IO~代表网络数据处理线程,是IO框架(比如Netty,Grizzly)创建维护,Dubbo Remoting所默认Netty实现是NioEventloopLoopGroup;另外按照Channel与IO线程的绑定关系,也可以直接把IO~看成一个可接受事件消息的Channel。像Biz和IO这样的异步处理阶段在JDK8中有个很精确地抽象描述,叫CompletionStage。
  2. 大家知道,线程与线程之间做数据通信的方式是共享变量,Biz和IO两个stage之间的数据通信是Queue,具体到Dubbo实现,在客户端一侧的实现(即上图中用1所标注的步骤)中Biz是通过向EventLoop的LinkedBlockingQueue放置一个Task,而EventLoop有对应的Thread会不停的迭代Queue来执行Task中所包含的信息,具体代码可以看SingleThreadEventExecutor(顺便提下,Netty中默认是用无上限的LinkedBlockingQueue,在Biz的速率高于网络速率情况下,似乎好像有Memory Leak的风险)。
  3. 如上图所示,标准的一次RPC调用经过了图中所示的1,2,3,4的四次消息(事件)传递,分别是客户端业务线程到IO线程的请求发出,服务端IO线程到业务逻辑线程的__请求接受,__服务端处理完成后由业务逻辑线程到IO线程的响应写出,客户端收到结果后从IO线程到业务逻辑的响应处理。除了1与4之间一般需要维护响应和请求的映射对应关系,四次的事件处理都是完全独立的,所以一次RPC调用天然是异步的,而同步是基于异步而来。

客户端异步

实现背景

在Java语言(其他语言不清楚)下一次本地接口的调用可以透明地通过代理机制转为远程RPC的调用,大多数业务方也比较喜欢这种与本地接口类似的编程方式做远程服务集成,所以虽然RPC内部天然是异步的,但使用Dubbo的用户使用最广泛的还是同步,而异步反而成为小众的使用场景。同步的优点是编程模型更加符合业务方的“传统”习惯,代价是在图中的1代表的请求发出事件后需要阻塞当前的Biz~线程,一直等到4代表的响应处理后才能唤醒。在这个短则微秒级别,长则秒级的1,2,3,4处理过程中都要阻塞Biz~线程,就会消耗线程资源,增加系统资源的开销。

所以,客户端异步的出发点是节省线程资源开销,代价是需要了解下异步的使用方式:)。在同步方式下API接口的返回类型是代表着某个业务类,而当异步情况下,响应返回与请求发出是完全独立的两个事件,需要API接口的返回类型变为上述中说的CompletionStage才是最贴合的,这是Dubbo在异步上支持的必然异步。回到最近的Dubbo发布版,是不改变接口的情况下,需要在服务创建时注册一个回调接口来处理响应返回事件。

下面以示例来说。

示例

事件通知的示例代码请参考:https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-notify

事件通知允许 Consumer 端在调用之前、调用正常返回之后或调用出现异常时,触发 oninvokeonreturnonthrow 三个事件。

可以通过在配置 Consumer 时,指定事件需要通知的方法,如:

<bean id="demoCallback" class="com.alibaba.dubbo.samples.notify.impl.NotifyImpl" /><dubbo:reference id="demoService" check="false" interface="com.alibaba.dubbo.samples.notify.api.DemoService" version="1.0.0" group="cn"><dubbo:method name="sayHello" onreturn="demoCallback.onreturn" onthrow="demoCallback.onthrow"/>
</dubbo:reference>

其中,NotifyImpl 的代码如下:

public class NotifyImpl implements Notify{public Map<Integer, String> ret = new HashMap<Integer, String>();public void onreturn(String name, int id) {ret.put(id, name);System.out.println("onreturn: " + name);}public void onthrow(Throwable ex, String name, int id) {System.out.println("onthrow: " + name);}
}

这里要强调一点,自定义 Notify 接口中的三个方法的参数规则如下:

  • oninvoke 方法参数与调用方法的参数相同;
  • onreturn方法第一个参数为调用方法的返回值,其余为调用方法的参数;
  • onthrow方法第一个参数为调用异常,其余为调用方法的参数。

上述配置中,sayHello方法为同步调用,因此事件通知方法的执行也是同步执行。可以配置 async=true让方法调用为异步,这时事件通知的方法也是异步执行的。特别强调一下,oninvoke方法不管是否异步调用,都是同步执行的。

实践建议

  • RPC调用后的逻辑非强依赖结果:异步回调是在客户端非强依赖服务端的结果情况下,是适用客户端的异步调用。
  • rx场景:自从了解到reactive的编程模型后,认为只要编程思维能够拥抱reactive,并且业务模型的状态机设计能做适当的调整,任何场景下都比较适用异步来解决,从而得到更好的终端响应体验。 对于Dubbo来说,当下的异步接口模型是需要像reactive的模型接口做改进,才能使得用户更自然地适用异步接口。

小结

  • 客户端异步的出发点就是请求发出和响应处理本身为两个不同的独立事件,响应如何被处理和在哪个线程中处理等都是不需要和请求发出事件的业务逻辑线程做耦合绑定。
  • 响应事件回调的处理逻辑在哪个线程中做处理是需要根据情况来选择。建议,如果回调逻辑比较简单,建议直接在IO线程中;如果包含了远程访问或者DB访问等IO型的__同步__操作,建议在独立的线程池做处理。

异步接口同步返回_Dubbo客户端异步接口的实现背景和实践相关推荐

  1. js中的异步与同步,解决由异步引起的问题

    js中的异步与同步,解决由异步引起的问题 参考文章: (1)js中的异步与同步,解决由异步引起的问题 (2)https://www.cnblogs.com/zhuchenglin/p/7651990. ...

  2. 异步接口同步返回_同步|异步

    在接口测试过程中,同步.异步也需要首先被关注. 消息通信机制:同步Synchronous communication&异步asynchronous communication 同步,就是调用某 ...

  3. 路由器的异步和同步串行接口

    本文以Cisco路由器为例,介绍了路由器上常用接口的类型.特点和应用场合. 1  EIA/TIA 232 EIA/TIA 232有时又被称作RS-232 C.RS(Recommended Standa ...

  4. RocketMQ高可用机制----同步刷盘、异步刷盘和同步复制、异步复制

    RocketMQ高可用机制----同步刷盘.异步刷盘和同步复制.异步复制 同步刷盘.异步刷盘 RocketMQ的消息是存储到磁盘上的,这样既能保证断电后恢复,又可以让存储的消息量超出内存的限制. Ro ...

  5. rss spring 接口_spring 接口支持返回多种格式

    1. 简介 本文介绍使用SpringMVC的后端服务如何通过配置来支持多种返回值类型(xml,json,html,excel) 这里的代码使用的是springboot,下载地址:https://git ...

  6. verilog异步复位jk触发器_异步复位同步释放原理

    关键词:同步释放,recovery,removal 在数字IC设计中肯定会涉及到异步复位的问题,因为需要对电路进行复位操作.这种复位设计主要依靠前端设计以及工具来检查,从数字IC后端的角度上讲,只要在 ...

  7. 异步复位同步释放原理

    深度揭秘异步复位同步释放原理 文章右侧广告为官方硬广告,与吾爱IC社区无关,用户勿点.点击进去后出现任何损失与社区无关. 明天就放端午小长假了,提前祝大家节日快乐.腾讯官网已经给小编公众号开通了赞赏功 ...

  8. 异步复位同步释放 打两拍

    同步复位问题:复位信号持续时间太短,在clk下没采集到就没了. 异步复位问题:释放时可能会出现亚稳态(见最后两张图). 文章目录 1. 异步复位 2. 同步复位 3. 异步复位同步释放 今天好好理一理 ...

  9. Java基础二十二:函数式接口介绍,函数式接口作为方法参数、返回值,Supplier接口、Consumer接口、Predicate接口、Function接口基本介绍及其案例小练习

    函数式接口 1. 函数式接口概念及基本使用 1.函数式接口:有且仅有一个抽象方法的接口,函数式接口就是Lambda表达式使用的前提 2. Java中的函数式编程体现的就是Lambda表达式,所以函数式 ...

最新文章

  1. python一点基础都没有的怎么办-为什么我会建议每个大学生都学一点python编程?...
  2. html中加盒子,在HTML中各类型盒子的基线应如何确定
  3. 如何在 SAP CRM WebClient UI 里在 Context node 上下文里访问其他 Context Node 的数据
  4. PostgreSQL 10.1 手册_部分 II. SQL 语言_第 12 章 全文搜索_12.4. 额外特性
  5. 关于java 中 的 null。
  6. 明天开始放假了[2.5-2.13],春节期间计划
  7. Chrome插件安装 程序包无效
  8. BUUCTF-Misc-sqltest(happyctf)
  9. Linux —— 动态库和静态库
  10. 帝国时代2哪个服务器稳定,《帝国时代2决定版》新手该选择哪个国家|新手使用国家推荐...
  11. matlab学霸表白公式,怎么表白:数学函数表白
  12. Linux ln -s目录,Linux 中的 ln 命令
  13. css斜切角/内阴影
  14. 加密机是如何工作的_什么是加密,它如何工作?
  15. Java:String转char数组
  16. 在Linux中各类重要文件被丢失的解决方式
  17. 网狐卓越版本内核引擎、卓越内核(源码,源码,源码)
  18. pod update --verbose --no-repo-update 和 pod install --verbose --no-repo-update的区别
  19. feign调用的重试机制,如何关闭
  20. 服务器esxi虚拟机升级,ESXi 服务器安装升级补丁

热门文章

  1. Jmeter添加断言
  2. php 判定pc端與移動端
  3. bzoj 4547: Hdu5171 小奇的集合
  4. CentOS 查看系统 CPU 个数、核心数、线程数
  5. SpringMVC - SpringMVC的概述
  6. Activiti邮件任务
  7. 靠二进制画几何[图论]
  8. Linux sar分析网卡流量
  9. XML在JAVA项目中的作用
  10. 程序员赴美经验谈:本科应届 Kevin - 弗罗里达州 Oracle