dubbo是一个分布式服务中间件,是高性能和透明化的RPC远程服务调用解决方案,主要通过资源调度和服务治理来解决分布式架构下服务资源浪费以提高集群的使用率。核心部分包含:
在深入架构前,先了解一下dubbo的组件角色,如下图:
调用关系分析:
问:各组件角色之间是采用长连接还是短连接交互的?为什么? 答:服务提供者->消费者,服务提供者->注册中心,服务消费者->注册中心。以上三个交互环节采用的是长连接。至于为什么?笔者分析是因为基于注册中心的动态服务发现与注册机制,所以需要通过心跳的方式实时检测节点的状态
先来看一下dubbo这个中间件的领域模型分层结构,如下图:
中间件架构分层设计:
各层之间关系总结:
在看源码之前,先看一下dubbo服务调用链路过程。如下图:
首先服务消费者通过代理对象 Proxy 发起远程调用,接着通过网络客户端 Client 将编码后的请求发送给服务提供方的网络层上,也就是 Server。Server 在收到请求后,首先要做的事情是对数据包进行解码。然后将解码后的请求发送至分发器 Dispatcher,再由分发器将请求派发到指定的线程池上,最后由线程池调用具体的服务。这就是一个远程调用请求的发送与接收过程。
dubbo支持同步和异步两种调用方式,其中异步调用分为“有返回值”的异步调用和“无返回值”的异步调用。所谓“无返回值”异步调用是指服务消费方只管调用,但不关心调用结果,此时 dubbo 会直接返回一个空的 RpcResult。若要使用异步特性,需要服务消费方手动进行配置。默认情况下,Dubbo 使用同步调用方式。
异步调用方式如下:
/* 异步方法配置 */ <dubbo:reference id="asyncService" check="false" interface="com.alibaba.dubbo.demo.AsyncService" url="localhost:20880"> <dubbo:method name="sayHello" async="true" /> </dubbo:reference>
Consumer端调用方式如下:
String result = asyncService.sayHello("world");
asyncService.sayHello("world"); Future<String> future = RpcContext.getContext().getFuture(); String result = future.get();
asyncService.sayHello("world"); ResponseFuture responseFuture = ((FutureAdapter)RpcContext.getContext().getFuture()).getFuture(); responseFuture.setCallback(new ResponseCallback() { @Override public void done(Object response) { System.out.println("done"); } @Override public void caught(Throwable exception) { System.out.println("caught"); } }); try { System.out.println("result = " + responseFuture.get()); } catch (RemotingException e) { e.printStackTrace(); }
Dubbo实现了服务治理的基础,但是要完成一个完备的微服务架构,还需要在各环节去扩展和完善以保证集群的健康,以减轻开发、测试以及运维各个环节上增加出来的压力,这样才能让各环节人员真正的专注于业务逻辑。而Spring Cloud依然发扬了Spring Source整合一切的作风,以标准化的姿态将一些微服务架构的成熟产品与框架揉为一体,并继承了Spring Boot简单配置、快速开发、轻松部署的特点,让原本复杂的架构工作变得相对容易上手一些。所以,如果选择Dubbo请务必在各个环节做好整套解决方案的准备,不然很可能随着服务数量的增长,整个团队都将疲于应付各种架构上不足引起的困难。而如果选择Spring Cloud,相对来说每个环节都已经有了对应的组件支持,可能有些也不一定能满足你所有的需求。
5.1.Reference注解
使用@Reference注解在消费者端注入提供者依赖的时候,MVC容器获取对象时可能出现Null的情况。Reference注解生成的实例是不会交给Spring容器托管的,只是作为Spring管理bean的一个属性赋值去操作,所以无法通过BeanFactory.getBean()获得。如果容器初始化时先加载了MVC容器,随后加载Dubbo实例,这时在Controller层引用的dubbo对象会造成空指针的异常,所以加载时需要进行编排,先加载dubbo实例,再加载MVC容器。另外一种方案是设计一个组件层,将dubbo和业务层在组件层进行组装,提供Controller层使用。
5.2.Dubbo超时和重连机制
Dubbo默认有超时和重连机制,在异常场景下如果不注意会引起异常或者幂等性的异常情况。超时机制是在指定时间内Provider没有返回,则认定本次调用失败。默认重连2次,超时1000ms。另外Dubbo可以以服务,接口,方法3个纬度配置参数,值得注意的是配置以消费者端为准,如果消费者端未配置则以提供者端为准。
5.3.Dubbo序列化协议
Dubbo适合高并发量小数据传输的RPC场景,默认dubbo协议交互,但是出于性能考虑很多公司会采用kryo序列化方式来提升性能,kryo确实性能要高出很多,但是有一个弊端,就是序列化对象修改后不能向上向下兼容,换句话来说就是DTO对象增加了一个字段,服务提供者和消费者两端需要同时升级版本,否则接口调用就会报错。这里可以自己扩展Dubbo预留的Serialization接口在kryo的基础上完善序列化协议。