Dubbo的使用背景
随着公司的业务复杂度日渐上涨,技术架构的发展从单体到分布式,是一种顺势而为的架构演进,也是一种被逼无奈的技术变革。和传统的单体架构相比,分布式多了一个远程服务之间的通信,不管是soa还是微服务,他们本质上都是对于业务服务的提炼和复用。远程服务之间的调用是实现分布式的关键因素。而在远程通信这个领域,其实有很多的技术,比如 Java 的 RMI、WebService、 Hessian、Dubbo、Thrift 等RPC框架,现在接触得比较多的应该就是RPC框架 Dubbo 以及应用协议Http。其实每一个技术都是在某一个阶段产生它的价值,随着架构的变化以及需求的变化,技术的解决方案也在变。
RPC
RPC,全称为Remote Procedure Call,即远程过程调用,是一种计算机通信协议。
比如现在有两台机器:A机器和B机器,并且分别部署了应用A和应用B。假设此时位于A机器上的A应用想要调用位于B机器上的B应用提供的函数或是方法,由于A应用和B应用不在一个内存空间里面,所以不能直接调用,此时就需要通过网络来表达调用的方式和传输调用的数据。也即所谓的远程调用。
如何实现一个RCP框架呢
主要有以下几个步骤:
1、建立通信
首先要解决通讯的问题:即A机器想要调用B机器,首先得建立起通信连接。主要是通过在客户端和服务器之间建立网络连接,远程过程调用的所有相关的数据都在这个连接里面进行传输交换。这就需要考虑到底层网络通信协议的处理。
2、服务寻址
解决寻址的问题:即A机器上的应用A要调用B机器上的应用B,那么此时对于A来说如何告知底层的RPC框架所要调用的服务具体在哪里呢?
通常情况下我们需要提供B机器(主机名或IP地址)以及特定的端口,然后指定调用的方法或者函数的名称以及入参出参等信息,这样才能完成服务的一个调用。
3、网络传输
3.1、序列化
当A机器上的应用发起一个RPC调用时,调用方法和其入参等信息需要通过底层的网络协议如TCP传输到B机器,由于网络协议是基于二进制的,所有我们传输的参数数据都需要先进行序列化(Serialize)或者编组(marshal)成二进制的形式才能在网络中进行传输。然后通过寻址操作和网络传输将序列化或者编组之后的二进制数据发送给B机器。
3.2、反序列化
当B机器接收到A机器的应用发来的请求之后,又需要对接收到的参数等信息进行反序列化操作(序列化的逆操作),即将二进制信息恢复为内存中的表达方式,然后再找到对应的方法(寻址的一部分)进行本地调用(一般是通过生成代理Proxy去调用, 通常会有JDK动态代理、CGLIB动态代理、Javassist生成字节码技术等),之后得到调用的返回值。
4、服务调用
B机器进行本地调用(通过代理Proxy)之后得到了返回值,此时还需要再把返回值发送回A机器,同样也需要经过序列化操作,然后再经过网络传输将二进制数据发送回A机器,而当A机器接收到这些返回值之后,则再次进行反序列化操作,恢复为内存中的表达方式,最后再交给A机器上的应用进行相关处理(一般是业务逻辑处理操作)。
通常,经过以上四个步骤之后,一次完整的RPC调用算是完成了,另外可能因为各种原因需要有容错策略。
这些工作本身应该是通用的,应该是一个中间件服务。为整个公司提供远程通信的服务。而不应该由业务开发人员来自己去实现,所以才有了这样的RPC框架,使得我们调用远程方法时就像调用本地方法那么简单,不需要关心底层的通信逻辑。
到此为止,只是实现了远程通信的功能,但是当企业开始大规模的服务化以后,远程通信带来的弊端就越来越明显了。比如:
- 服务链路变长了,如何实现对服务链路的跟踪和监控。
- 服务的大规模集群使得服务之间需要依赖第三方注册中心来解决服务的
发现和服务的感知问题。 - 服务通信之间的异常,需要有一种保护机制防止一个节点故障引发大规模
的系统故障,所以要有容错机制。 - 服务大规模集群会是的客户端需要引入负载均衡机制实现请求分发。
Dubbo 的基本使用
创建三个项目
dubbo-consumer :使用服务
dubbo-client : 提供接口
dubbo-server:提供服务
添加jar包依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.2</version>
</dependency>
dubbo-client
打包提交至maven本地仓库中,为dubbo-consumer 和 dubbo-server提供接口。
定义接口
public interface UserService {
/**
*
*/
String login(String username, String password);
}
dubbo-server
实现dubbo-client中定义的接口,提供服务。
public class LoginServiceImpl implements LoginService{
@Override
public String login(String username, String password) {
if(username.equals("admin")&&password.equals("admin")){
return "SUCCESS";
}
return "FAILED";
创建配置文件发布服务,具体的配置参数可在dubbo文档查看
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- 提供方应用信息,用于计算依赖关系 -->
<dubbo:application name="dubbo-server" />
<!--配置注册中心,如果是 zookeeper 集群,则配置的方式是
address=”zookeeper ://ip:host?backup=ip:host,ip:host” -->
<dubbo:registry check="${check-rpc:false}" address="zookeeper://192.168.13.102:2181" protocol="zookeeper" id="zkreg" >
<dubbo:parameter key="qos.enable" value="false"/>
</dubbo:registry>
<!-- 用 dubbo 协议在 7895 端口暴露服务 -->
<dubbo:protocol name="dubbo" port="7895" />
<!---->
<dubbo:consumer check="${check-rpc:false}" timeout="2000" registry="zkreg" group="test" retries="0"/>
<!-- 和本地bean一样实现服务 -->
<bean id="LoginService" class="com.learn.practice.LoginServiceImpl" />
<dubbo:service interface="com.learn.practice.LoginService" ref="loginService" registry="zkreg"
timeout="5000" group="test" version="1.0.0"/>
</beans>
dubbo-consumer
@Service
public class ApiUserService{
//调用dubbo服务提供的loginService
@Resource
private LoginService loginService;
public void login(){
loginService.login();
}
}
调用方的配置中心
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<dubbo:application name="dubbo-consumer" />
<dubbo:registry check="${check-rpc:false}" address="zookeeper://192.168.13.102:2181" protocol="zookeeper" id="zkreg" >
<dubbo:parameter key="qos.enable" value="false"/>
</dubbo:registry>
<dubbo:protocol name="dubbo" port="9006" />
<dubbo:reference interface="com.learn.practice.LoginService" check="false" id="userService" timeout="20000" registry="zkreg" group="test" version="1.0.0" />
</beans>
以上是dubbo 的基础使用过程,但是dubbo不仅仅是一个RPC框架。
Dubbo的多协议支持
dubbo 对于 RPC 通信协议的支持,不仅仅是原生的 dubbo 协议,它还支持着 rmi、hessian、http、webservice、thrift、rest。
有了多协议的支持,使得其他 rpc 框架的应用程序可以快速的切入到 dubbo 生态中。 同时,对于多协议的支持,使得不同应用场景的服务,可以选择合适的协议来发布服务,并不一定要使用 dubbo 提供的长连接方式。
网友评论