当前位置:首页 > 资讯 > info5 > 正文

服务框架多形式的服务调用:同步、异步、并用、泛化

发表于: 2016-01-09   作者:chenglinhust   来源:转载   浏览:
摘要: 服务框架多形式的服务调用:同步、异步、并用、泛化服务框架支持多种形式的服务调用,我们对下面这几种服务调用的原理和设计进行讲解。同步服务调用同步服务调用是最常用的一种服务调用方式,它的工作原理和使用都非常简单,分布式服务框架默认都需要支持这种调用形式。它的工作原理如下:客户端发起远程服务调用请求,用户线程完成消息序列化之后,将消息投递到通信框架,然后同步阻塞,等待通信线程发送请求并接收到应答之后,唤
服务框架多形式的服务调用:同步、异步、并用、泛化

服务框架支持多种形式的服务调用,我们对下面这几种服务调用的原理和设计进行讲解。

同步服务调用

同步服务调用是最常用的一种服务调用方式,它的工作原理和使用都非常简单,分布式服务框架默认都需要支持这种调用形式。

它的工作原理如下:客户端发起远程服务调用请求,用户线程完成消息序列化之后,将消息投递到通信框架,然后同步阻塞,等待通信线程发送请求并接收到应答之后,唤醒同步等待的用户线程,用户线程获取到应答之后返回。

它的工作原理图如图。

服务框架多形式的服务调用:同步、异步、并用、泛化_第1张图片

1)消费者调用服务端发布的接口,接口调用由分布式服务框架包装成动态代理,发起远程服务调用。

2)消费者线程调用通信框架的消息发送接口之后,直接或者间接调用 wait()方法,同步阻塞等待应答。

3)通信框架的 I/O线程通过网络将请求消息发送给服务端。

4)服务端返回应答消息给消费者,由通信框架负责应答消息的反序列化。 5)I/O线程获取到应答消息之后,根据消息上下文找到之前同步阻塞的业务线程, notify()阻塞的业务线程,返回应答给消费者,完成服务调用。

为了防止服务端长时间不返回应答消息导致客户端用户线程被挂死,用户线程等待的时候需要设置超时时间,这个超时时间与服务端或者客户端配置的超时时间对应。

异步服务调用

基于 JDK的 Future机制,可以非常方便地实现异步服务调用, JDK的 Future接口定义如图 。

服务框架多形式的服务调用:同步、异步、并用、泛化_第2张图片

JDK Future Doc

JDK原生的 Future主要用于异步操作,它代表了异步操作的执行结果,用户可以通过调用它的 get方法获取结果。如果当前操作没有执行完, get操作将阻塞调用线程。

在实际项目中,往往会扩展 JDK的 Future,提供 Future-Listener机制,它支持主动获取和被动异步回调通知两种模式,适用于不同的业务场景。

以Netty的 Future接口定义为例,新增了监听器管理接口,监听器主要用于异步通知回调,它的接口定义如图 。

服务框架多形式的服务调用:同步、异步、并用、泛化_第3张图片

异步服务调用的工作原理如图 。

服务框架多形式的服务调用:同步、异步、并用、泛化_第4张图片

异步服务调用的工作流程如下:

1)消费者调用服务端发布的接口,接口调用由分布式服务框架包装成动态代理,发起远程服务调用。

2)通信框架异步发送请求消息,如果没有发生 I/O异常,返回。

3)请求消息发送成功后, I/O线程构造 Future对象,设置到 RPC上下文中。

4)用户线程通过 RPC上下文获取 Future对象。

5)构造 Listener对象,将其添加到 Future中,用于服务端应答异步回调通知。

6)用户线程返回,不阻塞等待应答。

7)服务端返回应答消息,通信框架负责反序列化等。 8)I/O线程将应答设置到 Future对象的操作结果中。

9)Future对象扫描注册的监听器列表,循环调用监听器的operationComplete方法,将结果通知给监听器,监听器获取到结果之后,继续后续业务逻辑的执行,异步服务调用结束。

需要指出的是,还有另外一种异步服务调用形式,就是不添加 Listener,用户连续发起 N次服务调用,然后依次从 RPC上下文中获取 Future对象,昀终再主动 get结果,业务线程阻塞,相比于老的同步服务调用,它的阻塞时间更短,其工作原理如图。

服务框架多形式的服务调用:同步、异步、并用、泛化_第5张图片

异步服务调用的代码示例如下:

服务框架多形式的服务调用:同步、异步、并用、泛化_第6张图片

假如 xxxService1和 xxxService2发布成异步服务,则调用xxxMethod之后当前业务线程不阻塞,立即返回 null。用户不能直接使用它的返回值,而是通过当前线程上下文RPCContext获取异步操作结果 Future。获取到 Future之后继续发起其他异步服务调用,然后获取另一个 Future……昀后,通过 Future的 get方法集中获取结果。无论有多少个 Future,采用此种方式用户线程昀长阻塞时间为耗时昀长的 Future,即 T = Max t(future1....N)。如果采用同步服务调用,用户线程的阻塞时间T = t(future1) + t(future2) + ……+ t(futureN)。

异步服务调用相比于同步服务调用有两个优点:

◎化串行为并行,提升服务调用效率,减少业务线程阻塞时间。

◎化同步为异步,避免业务线程阻塞。

串行到并行的优化原理如图 。

服务框架多形式的服务调用:同步、异步、并用、泛化_第7张图片

由于每次服务调用都是同步阻塞,三个服务调用总耗时为T = T1 + T2 + T3。下面我们看下采用异步服务调用之后的优化效果,如图。

服务框架多形式的服务调用:同步、异步、并用、泛化_第8张图片

采用异步服务调用模式,昀后调用三个服务异步操作结果 Future的 get方法同步等待应答,它的总执行时间 T = Max(T1, T2, T3),相比于同步服务调用,性能提升效果非常明显。

第二种基于 Future-Listener的纯异步服务调用,它的代码示例如下:

xxxService1.xxxMethod(Req);

Future f1 =RpcContext.getContext().getFuture();

Listener l = new xxxListener();f1.addListener(l); ......后续代码省略 }

基于 Future-Listener的异步服务调用相比于 Future-get模式更好,但是在实际使用中有一定的局限性,具体的使用限制留给读者自己思考。

并行服务调用

在大多数业务应用中,服务总是被串行地调用和执行,例如 A调用 B服务,B服务调用C服务,昀后形成一个串行的服务调用链: A→B服务→C服务→……

串行服务调用比较简单,但在一些业务场景中,需要采用并行服务调用来降低 E2E的时延:

◎多个服务之间逻辑上不存在互相依赖关系,执行先后顺序没有严格的要求,逻辑上可以被并行执行。

◎长流程业务,调用多个服务,对时延比较敏感,其中有部分服务逻辑上无上下文关联,可以被并行调用。

并行服务调用的目标主要有两个:

1)降低业务 E2E时延。

2)提升整个系统的吞吐量。我们以手游购买道具流程为例,对并行服务调用进行说明,如图。

服务框架多形式的服务调用:同步、异步、并用、泛化_第9张图片

在购买道具时,三个鉴权流程实际可以并行执行,昀终执行结果做个 Join即可。如果采用传统的串行服务调用,耗时将是三个鉴权服务时延之和,显然是没有必要的。计费之后的通知类服务亦如此(注意:通知服务也可以使用MQ做订阅/发布),单个服务的串行调用会导致购买道具时延比较长,影响游戏玩家的体验。

要解决串行调用效率低的问题,有两个解决对策:

◎异步服务调用。

◎并行服务调用。在上一节中已经对异步服务调用进行了讲解,下面我们对并行服务调用进行详细介绍。并行服务调用的原理:一次同时发起多个服务调用,先做流程的 Fork,再利用 Future

等主动等待获取结果,进行结果汇聚( Join)。实现并行服务调用的几种技术方案:

◎ JDK 7的 Fork/Join,可以实现子任务的并行执行和结果汇聚。

◎ BPM的 Parallel Gateway。

◎批量串行服务调用。

JDK7的 Fork/Join底层会开启多个线程来分解任务,在服务框架中使用会导致依赖线程上下文传递的变量丢失、线程膨胀不可控等问题,因此在并行服务调用时不适合使用 JDK的 Fork/Join并行执行框架。

BPM流程引擎支持并行流程(子流程)调用,它的执行示意图如图。

服务框架多形式的服务调用:同步、异步、并用、泛化_第10张图片

 Parallel Gateway(并行网关)能在一个流程里用来对并发建模。在一个流程模型里引入并发昀直接的网关就是并行网关( Parallel Gateway),它允许 Fork执行多个路径,或者 Join多个执行的到达路径。

并行网关的功能基于即将到达的和即将离开的流程顺序流。

◎ Fork:所有即将离开的顺序流将以并行方式,为每个顺序流程建立一个并发执行器。

◎ Join:所有的并发执行到达并行网关,在网关里面等待直到每个来到的顺序流的执行到达,条件满足后流程继续通过合并网关。

从技术上看,不同的 BPM流程引擎具体实现细节也不同,但大多数都支持:通过创建子线程的方式实现并行调用、通过批量调用的方式实现伪异步并行调用。对于服务框架而言,BPM Parallel Gateway的功能可以满足需求,但是为了并行服务调用引入 BPM流程引擎显然是得不偿失,我们可以参考 Parallel Gateway的伪异步并行调用来实现服务框架的并行服务调用。

下面我们对批量串行服务调用实现并行服务调用的原理进行讲解,如图。

服务框架多形式的服务调用:同步、异步、并用、泛化_第11张图片

1)服务框架提供批量服务调用接口供消费者使用,它的定义样例如下:

2)平台的并行服务调用器创建并行 Future,缓存批量服务调用上下文信息。

3)并行服务调用器循环调用普通的 Invoker,通过循环的方式执行单个服务调用,获取到单个服务的 Future之后设置到 Parallel Future中。

4)返回 Parallel Future给消费者。

5)普通 Invoker调用通信框架的消息发送接口,发起远程服务调用。

6)服务端返回应答,通信框架对报文做反序列化,转换成业务对象更新 Parallel Future的结果列表。

7)消费者调用 Parallel Future的 get(timeout)方法, 同步阻塞,等待所有结果全部返回。

8) Parallel Future通过对结果集进行判断,看所有服务调用是否都已经完成(包括成功、失败和异常)。

9)所有批量服务调用结果都已经返回, Notify消费者线程,消费者获取到结果列表,完成批量服务调用,流程继续执行。

通过批量服务调用 + Future机制,我们实现了并行服务调用,而且没有创建新的线程,用户不用担心依赖线程上下文的功能出异常。该方案唯一的缺点就是用户需要调用平台提供的并行服务调用接口,这个会导致 API层面的依赖,对于努力构建零依赖的服务框架而言不是昀优的选择。但事实上完全的零依赖是不存在的,即便 100% XML配置也是一种配置依赖,所以在设计过程中要能够识别并抓主要矛盾点,做到有所舍,否则设计工作将步履维艰。

泛化调用

泛化调用通常包含两种模式:泛化引用和泛化实现。泛化引用主要用于客户端没有 API接口及数据模型的场景,参数及返回值中的所有 POJO均用 Map表示,通常用于框架集成,比如实现一个通用的服务测试框架。泛化实现主要用于服务器端没有 API接口及数据模型的场景,参数及返回值中的所有 POJO均用 Map表示,通常用于框架集成,比如实现一个通用的远程服务Mock框架。泛化调用的设计要点如下。

1)分布式服务框架提供泛化接口,供服务提供者实现和消费者引用,它的参考定义如下:

2)消费者如果引用泛化接口,则直接将请求参数转换成 Map,应答消息也自动转换成 Map。

3)服务提供者如果使用泛化实现发布服务,则自动将请求参数转换成 Map,调用GenService的泛化实现类,应答消息自动包装成 Map返回。

泛化调用由于比较灵活,没有服务契约,因此在实际项目中慎用,它通常用于测试集成、系统上线之后的回声测试等。


转载地址:http://mp.weixin.qq.com/s?__biz=MjM5NTk0NjMwOQ==&mid=401933719&idx=1&sn=dadc10aaaf7b308494b7db63a551c15c&scene=25&srcid=0104CmhNfIXHYMaOgYMfFxvc&from=timeline&isappinstalled=0#wechat_redirect

服务框架多形式的服务调用:同步、异步、并用、泛化

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

编辑推荐
我们谈在性能调优时可能存在有很多不同的方面可以进行性能的优化,比如:良好的的编码习惯,最大限
我们谈在性能调优时可能存在有很多不同的方面可以进行性能的优化,比如:良好的的编码习惯,最大限
基于Ajax技术构建的门户是web 2.0这一代中最为成功的Web应用程序。而这块市场上iGoogle和Pageflakes
异步调用Web Service就是避免客户端在调用耗时间的服务方法的时候出现假死状态。那么怎么异步调用呢
基于Ajax技术构建的门户是web 2.0这一代中最为成功的Web应用程序。而这块市场上iGoogle和Pageflakes
轻量级分布式服务化框架 github: https://github.com/lindzh doc: https://github.com/lindzh/rpc/b
Web服务请求异步化测试  Web服务异步化:   包括两部分,数据传输层异步化(大家已经熟知的NIO)
在网站的优化过程中,我们分为两大部分: 1:页面前端优化,这里包括js脚本的合并及压缩,js事件的后绑
 服务端: 新建一个【WCF服务应用程序】,命名为【WcfServiceDemo】 新建【WCF服务】,同时vs会
编者按:InfoQ开设栏目“品味书香”,精选技术书籍的精彩章节,以及分享看完书留下的思考和收获,欢
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号