分布式RPC框架Apache Dubbo

Dubbo简介

Apache Dubbo是一款高性能的Java RPC框架。其前身是阿里巴巴公司开源的、轻量级的开源Java RPC框架,可以和Spring框架无缝集成,2018年阿里巴巴把这个框架捐献给了apache基金会。

什么是RPC?

RPC全称为remote procedure call,即远程过程调用。比如两台服务器A和B,A服务器上部署一个应用,B服务器上部署一个应用,A服务器上的应用想调用B服务器上的应用提供的方法,由于两个应用不在一个内存空间,不能直接调用,所以需要通过网络来表达调用的语义和传达调用的数据。

需要注意的是RPC并不是一个具体的技术,而是指整个网络远程调用过程。

RPC是一个泛化的概念,严格来说一切远程过程调用手段都属于RPC范畴。各种开发语言都有自己的RPC框架。Java中的RPC框架比较多,广泛使用的有RMI、Hessian、Dubbo等。

Dubbo官网地址:http://dubbo.apache.org
Dubbo提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

Dubbo的架构


节点角色说明:
Provider:暴露服务的服务提供方
Consumer: 调用远程服务的服务消费方
Registry: 服务注册与发现的注册中心
Monitor: 统计服务的调用次数和调用时间的监控中心
Container: 服务运行容器

虚线都是异步访问,实线都是同步访问 蓝色虚线:在启动时完成的功能 红色虚线(实线)都是程序运行过程中执行的功能

调用关系说明:
0. 服务容器负责启动,加载,运行服务提供者。

  1. 服务提供者在启动时,向注册中心注册自己提供的服务。
  2. 服务消费者在启动时,向注册中心订阅自己所需的服务。
  3. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  4. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  5. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟送一次统计数据到监控中心。

Dubbo采用全Spring配置方式,透明化接入应用,对应用没有任何API侵入,只需用Spring加载Dubbo的配置即可,Dubbo基于Spring的Schema扩展进行加载。如果不想使用Spring配置,而希望通过API的方式进行调用(不推荐)
Dubbo采用全Spring配置方式,透明化接入应用,对应用没有任何API侵入,只需用Spring加载Dubbo的配置即可,Dubbo基于Spring的Schema扩展进行加载。

服务注册中心Zookeeper

通过前面的Dubbo架构图可以看到,Registry(服务注册中心)在其中起着至关重要的作用。Dubbo官方推荐使用Zookeeper作为服务注册中心。

Zookeeper介绍

Zookeeper 是 Apache Hadoop 的子项目,是一个树型的目录服务,支持变更推送,适合作为 Dubbo服务的注册中心,工业强度较高,可用于生产环境,并推荐使用 。
为了便于理解Zookeeper的树型目录服务,我们先来看一下我们电脑的文件系统(也是一个树型目录结构):

我的电脑可以分为多个盘符(例如C、D、E等),每个盘符下可以创建多个目录,每个目录下面可以创建文件,也可以创建子目录,最终构成了一个树型结构。通过这种树型结构的目录,我们可以将文件分门别类的进行存放,方便我们后期查找。而且磁盘上的每个文件都有一个唯一的访问路径,例如:C:\Windows\kkb\hello.txt。
Zookeeper树型目录服务:
流程说明:
服务提供者(Provider)启动时: 向 /dubbo/com.foo.BarService/providers 目录下写入自己的URL 地址
服务消费者(Consumer)启动时: 订阅 /dubbo/com.foo.BarService/providers 目录下的提供者URL 地址。并向 /dubbo/com.foo.BarService/consumers 目录下写入自己的 URL 地址
监控中心(Monitor)启动时: 订阅 /dubbo/com.foo.BarService 目录下的所有提供者和消费者URL 地址

安装Zookeeper

下载地址:http://archive.apache.org/dist/zookeeper/

此处使用的Zookeeper版本为3.4.6,下载完成后可以获得名称为zookeeper-3.4.6.tar.gz的压缩文件。

第一步:安装 jdk(略)
第二步:把 zookeeper 的压缩包(zookeeper-3.4.6.tar.gz)上传到 linux 系统
第三步:解压缩压缩包 tar -zxvf zookeeper-3.4.6.tar.gz -C /usr
第四步:进入zookeeper-3.4.6目录,创建data目录 mkdir data
第五步:进入conf目录 ,把zoo_sample.cfg 改名为zoo.cfg cd conf
mv zoo_sample.cfg zoo.cfg
第六步:打开zoo.cfg文件, 修改data属性dataDir=/usr/zookeeper3.4.6/data

启动、停止Zookeeper

进入Zookeeper的bin目录,启动服务命令 ./zkServer.sh start
停止服务命令 ./zkServer.sh stop
查看服务状态: ./zkServer.sh status
客户端连接
./zkCli.sh

Dubbo快速入门

Dubbo作为一个RPC框架,其最核心的功能就是要实现跨网络的远程调用。本小节就是要创建两个应用,一个作为服务的提供方,一个作为服务的消费方。通过Dubbo来实现服务消费方远程调用服务提供方的方法。

服务提供方开发

  1. 创建maven工程(打包方式为war)dubbodemo_provider,在pom.xml文件中导入如下坐标
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.wh</groupId><artifactId>dubbodemo-provider</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><spring.version>5.0.5.RELEASE</spring.version></properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jms</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId><version>${spring.version}</version></dependency><!-- dubbo相关 --><dependency><groupId>com.alibaba</groupId><artifactId>dubbo</artifactId><version>2.6.0</version></dependency><dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.4.7</version></dependency><dependency><groupId>com.github.sgroschupf</groupId><artifactId>zkclient</artifactId><version>0.1</version></dependency><dependency><groupId>javassist</groupId><artifactId>javassist</artifactId><version>3.12.1.GA</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.47</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>2.3.2</version><configuration><source>1.8</source><target>1.8</target></configuration></plugin><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><configuration><!-- 指定端口 --><port>8081</port><!-- 请求路径 --><path>/</path></configuration></plugin></plugins></build>
</project>
  1. 配置web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><display-name>Archetype Created Web Application</display-name><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext*.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>
</web-app>
  1. 创建服务接口
public interface HelloService {public String sayHello(String name);
}
  1. 创建服务实现类
@Service
public class HelloServiceImpl implements HelloService {public String sayHello(String name) {return "hello " + name;}
}

注意:服务实现类上使用的Service注解是Dubbo提供的,用于对外发布服务

  1. 在src/main/resources下创建applicationContext-service.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"><!-- 当前应用名称,用于注册中心计算应用间依赖关系,注意:消费者和提供者应用名不要一样 --><dubbo:application name="dubbodemo_provider" /><!-- 连接服务注册中心zookeeper ip为zookeeper所在服务器的ip地址--><dubbo:registry address="zookeeper://192.168.229.128:2181"/><!-- 注册 协议和port --><dubbo:protocol name="dubbo" port="20881"></dubbo:protocol><!-- 扫描指定包,加入@Service注解的类会被发布为服务 --><dubbo:annotation package="com.wh.service.impl" />
</beans>
  1. 启动服务
    tomcat7:run

服务消费方开发

  1. 创建maven工程(打包方式为war)dubbodemo_consumer,pom.xml配置和上面服务提供者相同,只需要将Tomcat插件的端口号改为8082即可
  2. 配置web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><display-name>Archetype Created Web Application</display-name><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext*.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><display-name>Archetype Created Web Application</display-name><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 指定加载的配置文件 ,通过参数contextConfigLocation加载 --><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext-web.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>springmvc</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
</web-app>
  1. 将服务提供者工程中的HelloService接口复制到当前工程

  2. 编写Controller

@Controller
@RequestMapping("/demo")
public class HelloController {@Referenceprivate HelloService helloService;@RequestMapping("/hello")@ResponseBodypublic String getName(String name){//远程调用String result = helloService.sayHello(name);System.out.println(result);return result;}
}

注意:Controller中注入HelloService使用的是Dubbo提供的@Reference注解

  1. 在src/main/resources下创建applicationContext-web.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"><!-- 当前应用名称,用于注册中心计算应用间依赖关系,注意:消费者和提供者应用名不要一样 --><dubbo:application name="dubbodemo_consumer" /><!-- 连接服务注册中心zookeeper ip为zookeeper所在服务器的ip地址--><dubbo:registry address="zookeeper://192.168.229.128:2181"/><!-- 扫描指定包,加入@Service注解的类会被发布为服务 --><dubbo:annotation package="com.wh.controller" />
</beans>
  1. 运行测试
    tomcat7:run启动
    在浏览器输入http://localhost:8082/demo/hello.do?name=Jack,查看浏览器输出结果

    查看控制台结果

Dubbo管理控制台

我们在开发时,需要知道Zookeeper注册中心都注册了哪些服务,有哪些消费者来消费这些服务。我们可以通过部署一个管理中心来实现。其实管理中心就是一个web应用,部署到tomcat即可。

安装

安装步骤:
(1)将dubbo-admin-2.6.0.war文件复制到tomcat的webapps目录下
(2)启动tomcat,此war文件会自动解压
(3)修改WEB-INF下的dubbo.properties文件,注意dubbo.registry.address对应的值需要对应当前使用的Zookeeper的ip地址和端口号
dubbo.registry.address=zookeeper://192.168.xxx.xxx:2181 dubbo.admin.root.password=root
dubbo.admin.guest.password=guest
(4)重启tomcat

使用

访问http://localhost:8080/dubbo-admin-2.6.0/,输入用户名(root)和密码(root)

启动服务提供者工程和服务消费者工程,可以在查看到对应的信息


Dubbo相关配置说明

包扫描

<dubbo:annotation package="com.wh.service" />

服务提供者和服务消费者都需要配置,表示包扫描,作用是扫描指定包(包括子包)下的类。
如果不使用包扫描,也可以通过如下配置的方式来发布服务:

<bean id="helloService" class="com.wh.service.impl.HelloServiceImpl" />
<dubbo:service interface="com.wh.api.HelloService" ref="helloService" />

作为服务消费者,可以通过如下配置来引用服务:

<!-- 生成远程服务代理,可以和本地bean一样使用helloService -->
<dubbo:reference id="helloService" interface="com.wh.api.HelloService" />

上面这种方式发布和引用服务,一个配置项(dubbo:service、dubbo:reference)只能发布或者引用一个服务,如果有多个服务,这种方式就比较繁琐了。推荐使用包扫描方式。

协议

<dubbo:protocol name="dubbo" port="20880"/>

一般在服务提供者一方配置,可以指定使用的协议名称和端口号。
其中Dubbo支持的协议有:dubbo、rmi、hessian、http、webservice、rest、redis等。推荐使用的是dubbo协议。
dubbo 协议采用
单一长连接和 NIO 异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。不适合传送大数据量的服务,比如传文件,传视频等,除非请求量很低。
也可以在同一个工程中配置多个协议,不同服务可以使用不同的协议,例如:

<!-- 多协议配置 -->
<dubbo:protocol name="dubbo" port="20880" />
<dubbo:protocol name="rmi" port="1099" />
<!-- 使用dubbo协议暴露服务 -->
<dubbo:service interface="com.wh.api.HelloService" ref="helloService"
protocol="dubbo" />
<!-- 使用rmi协议暴露服务 -->
<dubbo:service interface="com.wh.api.DemoService" ref="demoService"
protocol="rmi" />

负载均衡

负载均衡(Load Balance):其实就是将请求分摊到多个操作单元上进行执行,从而共同完成工作任
务。
在集群负载均衡时,Dubbo 提供了多种均衡策略(包括随机、轮询、最少活跃调用数、一致性
Hash),缺省为random随机调用。
配置负载均衡策略,既可以在服务提供者一方配置,也可以在服务消费者一方配置,如下:

@Controller
@RequestMapping("/demo")
public class HelloController {//在服务消费者一方配置负载均衡策略@Reference(check = false,loadbalance = "random")private HelloService helloService;@RequestMapping("/hello")@ResponseBodypublic String getName(String name){//远程调用String result = helloService.sayHello(name);System.out.println(result);return result;}
}
//在服务提供者一方配置负载均衡
@Service(loadbalance = "random")
public class HelloServiceImpl implements HelloService {public String sayHello(String name) {return "hello " + name;}
}

可以通过启动多个服务提供者来观察Dubbo负载均衡效果。
注意:因为我们是在一台机器上启动多个服务提供者,所以需要修改tomcat的端口号和Dubbo服务的端口号来防止端口冲突。
在实际生产环境中,多个服务提供者是分别部署在不同的机器上,所以不存在端口冲突问题。

解决Dubbo无法发布被事务代理的Service问题

前面我们已经完成了Dubbo的入门案例,通过入门案例我们可以看到通过Dubbo提供的标签配置就可以进行包扫描,扫描到@Service注解的类就可以被发布为服务。
但是我们如果在服务提供者类上加入@Transactional事务控制注解后,服务就发布不成功了。原因是事务控制的底层原理是为服务提供者类创建代理对象,而默认情况下Spring是基于JDK动态代理方式创建代理对象,而此代理对象的完整类名为com.sun.proxy.$Proxy42(最后两位数字不是固定的),导致Dubbo在发布服务前进行包匹配时无法完成匹配,进而没有进行服务的发布。

解决方案:
(1)修改applicationContext-service.xml配置文件,开启事务控制注解支持时指定proxy-target-class属性,值为true。其作用是使用cglib代理方式为Service类创建代理对象

<!--开启事务控制的注解支持-->
<tx:annotation-driven transaction-manager="transactionManager" proxy-targetclass="true"/>

(2)修改HelloServiceImpl类,在Service注解中加入interfaceClass属性,值为HelloService.class,作用是指定服务的接口类型

@Service(interfaceClass = HelloService.class)
@Transactional
public class HelloServiceImpl implements HelloService {public String sayHello(String name) {return "hello " + name;}
}

此处也是必须要修改的,否则会导致发布的服务接口为SpringProxy,而不是HelloService接口,如下:

Apache Dubbo基本使用相关推荐

  1. Apache Dubbo 高危漏洞通告

    前沿技术早知道,弯道超车有希望 积累超车资本,从关注DD开始 作者:360CERT, 图文编辑:xj 来源:https://www.oschina.net/news/178522 报告编号:B6-20 ...

  2. Apache Dubbo 2.7.7 发布!升级 fastjson 等依赖!

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 来源 | oschina.net/news/115796 ...

  3. 10月15日云栖精选夜读 | 阿里巴巴 Apache Dubbo 布道师谈 Service Mesh

    "Service Mesh要解决分布式架构下如何集成的问题,同时它又是云原生的核心,Dubbo Mesh正在做这方面的实践.--- 阿里巴巴Apache Dubbo布道师 吕仁琦 " ...

  4. rmi 反序列化漏洞_提醒:Apache Dubbo存在反序列化漏洞

    背景: 近日监测到Apache Dubbo存在反序列化漏洞(CVE-2019-17564),此漏洞可导致远程代码执行.Apache Dubbo是一款应用广泛的高性能轻量级的Java RPC分布式服务框 ...

  5. 参与 Apache 顶级开源项目的 N 种方式,Apache Dubbo Samples SIG 成立!

    头图来源:https://opensource.guide/ 来源 | 阿里巴巴云原生公众号 ​ 只有贡献代码才算是参与开源项目社区贡献吗? 一说到参与开源项目贡献,一般大家的反应都是代码级别的贡献, ...

  6. 都已经十岁的 Apache Dubbo,还能再乘风破浪吗?

    纵观中国开源历史,你真的没法找到第二个像 Dubbo 一样自带争议和讨论热度的开源项目. 一方面,2011 年,它的开源填补了当时生产环境使用的 RPC 框架的空白,一发布就被广泛采用:另一方面,它经 ...

  7. 架构师成长系列 | 从 2019 到 2020,Apache Dubbo 年度回顾与总结

    作者 | 刘军(陆龟)Apache Dubbo PMC 本文整理自架构师成长系列 2 月 18 日直播课程. 关注"阿里巴巴云原生"公众号,回复 "218",即 ...

  8. apache dubbo 自定义全局统一的异常处理器

    项目使用过的是apache dubbo 2.7.1, 封装了自定义全局统一的异常处理器. 统一异常处理器 需要实现javax.ws.rs.ext.ExceptionMapper接口. import o ...

  9. Apache Dubbo 3.0.0 正式发布 - 全面拥抱云原生

    简介:一个新的里程碑! 一.背景 自从 Apache Dubbo 在 2011 年开源以来,在一众大规模互联网.IT公司的实践中积累了大量经验后,Dubbo 凭借对 Java 用户友好.功能丰富.治理 ...

  10. 参与Apache顶级开源项目的N种方式,Apache Dubbo Samples SIG 成立!

    简介:一说到参与开源项目贡献,一般大家的反应都是代码级别的贡献,总觉得我的代码被社区合并了,我才算一个贡献者,这是一个常见的错误认知.其实,在一个开源社区中有非常多的角色是 non-code cont ...

最新文章

  1. 中国互联网+机器视觉行业商业模式创新与投资机会深度研究报告
  2. 小程序聊天室开发,发送文字,表情,图片,音频,视频,即时通讯,快速部署,可定制开发
  3. 阿里巴巴5月5日综合算法题详解
  4. Two Merged Sequences
  5. 如何将.sof转换成.jic
  6. python打印99乘法表_Python 实例:九九乘法表
  7. Mozilla Firefox 10.0 beta4 发布
  8. 十三、axios框架学习
  9. C语言数组查找(线性查找 折半查找)
  10. 户籍管理系统php,户籍管理系统.rar - 源码下载|Windows编程|数据库编程|源代码 - 源码中国...
  11. 一键自动下载百度美女图片
  12. html视频如何转换成mp4视频格式,如何将把视频文件转换成MP4格式?先说两种方法...
  13. 【云原生之Docker实战】使用Docker部署siyuan个人笔记系统
  14. 移动互联网时代的失意者
  15. STM32学习心得三十四:外部SRAM原理及实验代码解读
  16. EPICS -- autosave模块使用示例
  17. 中病毒spoolsv.exe
  18. 高斯消元法 matlab程序
  19. excel中html批量转化为pdf文件,如何将大量的Excel转换成PDF?
  20. springboot开发微信小程序

热门文章

  1. Maven依赖jar包的查询
  2. mysql与oracle实现行转列并指定分隔符
  3. Linux 必知必会
  4. 论文学习:BP神经网络
  5. linux 对函数的未定义的引用,对libncurses中函数的未定义引用
  6. 【自动控制原理】根轨迹法之绘制根轨迹
  7. 重启随机游走(RWR)算法
  8. (自)协方差矩阵与互协方差矩阵简介
  9. 普通程序员怎么赚多份钱?解锁更多赚钱新姿势
  10. 虹科Pico动态 |【盖世汽车-走进东风商用车技术展】精彩回顾