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 架构
Apache Dubbo概述_第1张图片

 

        虚线都是异步访问,实线都是同步访问 蓝色虚线: 在启动时完成的功能 红色虚线 ( 实线 ) 都是程序运行过 程中执行的功能
调用关系说明 :
        0. 服务容器负责启动,加载,运行服务提供者。
        1. 服务提供者在启动时,向注册中心注册自己提供的服务。
        2. 服务消费者在启动时,向注册中心订阅自己所需的服务。
        3. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给 消费者。
        4. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失 败,再选另一台调用。
        5. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
服务注册中心 Zookeeper
        通过前面的Dubbo 架构图可以看到, Registry (服务注册中心)在其中起着至关重要的作用。 Dubbo 官 方推荐使用Zookeeper 作为服务注册中心。
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.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/zookeeper- 3.4.6/data
3.3 启动、停止 Zookeeper
进入 Zookeeper bin 目录,启动服务命令 ./zkServer.sh start
停止服务命令 ./zkServer.sh stop
查看服务状态: ./zkServer.sh status
客户端连接
./zkCli.sh
Dubbo 快速入门
        Dubbo作为一个 RPC 框架,其最核心的功能就是要实现跨网络的远程调用。本小节就是要创建两个应 用,一个作为服务的提供方,一个作为服务的消费方。通过Dubbo 来实现服务消费方远程调用服务提供
方的方法。
4. 服务提供方开发
开发步骤:
1 )创建 maven 工程(打包方式为 war dubbodemo_provider ,在 pom.xml 文件中导入如下坐标
UTF-8
1.8
1.8
5.0.5.RELEASE
org.springframework
spring-context
${spring.version}
org.springframework
spring-beans
${spring.version}
org.springframework
spring-webmvc
${spring.version}
org.springframework
spring-jdbc
${spring.version}
org.springframework
spring-aspects
${spring.version}
org.springframework
spring-jms
${spring.version}
org.springframework
spring-context-support
${spring.version}
com.alibaba
dubbo
2.6.0
org.apache.zookeeper
zookeeper
3.4.7
com.github.sgroschupf
zkclient
0.1
javassist
javassist
3.12.1.GA
com.alibaba
fastjson
1.2.47
org.apache.maven.plugins
maven-compiler-plugin
2.3.2
1.8
1.8
org.apache.tomcat.maven
tomcat7-maven-plugin
8081
/
2 )配置 web.xml 文件
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
Archetype Created Web Application
contextConfigLocation
classpath:applicationContext*.xml
class> org.springframework.web.context.ContextLoaderListener
3 )创建服务接口
package com . lxs . service ;
public interface HelloService {
public String sayHello ( String name );
}
4 )创建服务实现类
package com . lxs . service . impl ;
import com . alibaba . dubbo . config . annotation . Service ;
import com . lxs . service . HelloService ;
@Service
public class HelloServiceImpl implements HelloService {
public String sayHello ( String name ) {
return "hello " + name ;
}
}
注意:服务实现类上使用的 Service 注解是 Dubbo 提供的,用于对外发布服务
5 )在 src/main/resources 下创建 applicationContext-service.xml
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" 6 )启动服务
tomcat7:run
4.2 服务消费方开发
开发步骤:
1 )创建 maven 工程(打包方式为 war dubbodemo_consumer pom.xml 配置和上面服务提供者
相同,只需要将 Tomcat 插件的端口号改为 8082 即可
2 )配置 web.xml 文件
3 )将服务提供者工程中的 HelloService 接口复制到当前工程
4 )编写 Controller
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" >
name = "dubbodemo_provider" />
address = "zookeeper://192.168.134.129:2181" />
name = "dubbo" port = "20881" >
package = "com.lxs.service.impl" />
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
Archetype Created Web Application
springmvc
org.springframework.web.servlet.DispatcherServlet
class>
contextConfigLocation
classpath:applicationContext-web.xml
1
springmvc
*.do
package com . lxs . controller ;
import com . alibaba . dubbo . config . annotation . Reference ;
import com . lxs . service . HelloService ;
import org . springframework . stereotype . Controller ;
import org . springframework . web . bind . annotation . RequestMapping ;
import org . springframework . web . bind . annotation . ResponseBody ;
@Controller
@RequestMapping ( "/demo" )
public class HelloController {
@Reference
private HelloService helloService ;
@RequestMapping ( "/hello" )
@ResponseBody
public String getName ( String name ){
// 远程调用
String result = helloService . sayHello ( name );
System . out . println ( result );
return result ;
}
}
注意: Controller 中注入 HelloService 使用的是 Dubbo 提供的 @Reference 注解
5 )在 src/main/resources 下创建 applicationContext-web.xml
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" >
name = "dubbodemo-consumer" />
address = "zookeeper://192.168.134.129:2181" />
package = "com.lxs.controller" />
6 )运行测试
tomcat7:run 启动
在浏览器输入 http://localhost:8082/demo/hello.do?name=Jack ,查看浏览器输出结果 思考一: 上面的 Dubbo 入门案例中我们是将 HelloService 接口从服务提供者工程
(dubbodemo_provider) 复制到服务消费者工程 (dubbodemo_consumer) 中,这种做法是否合适?还有
没有更好的方式?
答: 这种做法显然是不好的,同一个接口被复制了两份,不利于后期维护。更好的方式是单独创建一个
maven 工程,将此接口创建在这个 maven 工程中。需要依赖此接口的工程只需要在自己工程的
pom.xml 文件中引入 maven 坐标即可。
思考二: 在服务消费者工程 (dubbodemo_consumer) 中只是引用了 HelloService 接口,并没有提供实现
类, Dubbo 是如何做到远程调用的?
答: Dubbo 底层是基于代理技术为 HelloService 接口创建代理对象,远程调用是通过此代理对象完成
的。可以通过开发工具的 debug 功能查看此代理对象的内部结构。另外, Dubbo 实现网络传输底层是基
Netty 框架完成的。
思考三: 上面的 Dubbo 入门案例中我们使用 Zookeeper 作为服务注册中心,服务提供者需要将自己的服
务信息注册到 Zookeeper ,服务消费者需要从 Zookeeper 订阅自己所需要的服务,此时 Zookeeper 服务
就变得非常重要了,那如何防止 Zookeeper 单点故障呢?
答: Zookeeper 其实是支持集群模式的,可以配置 Zookeeper 集群来达到 Zookeeper 服务的高可用,防
止出现单点故障。
5. Dubbo 管理控制台
我们在开发时,需要知道 Zookeeper 注册中心都注册了哪些服务,有哪些消费者来消费这些服务。我们
可以通过部署一个管理中心来实现。其实管理中心就是一个 web 应用,部署到 tomcat 即可。
5.1 安装
安装步骤:
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.134.129:2181 dubbo.admin.root.password=root
dubbo.admin.guest.password=guest
4 )重启 tomcat
5.2 使用
操作步骤:
1 )访问 http://localhost:8080/dubbo-admin-2.6.0/ ,输入用户名 (root) 和密码 (root) 2 )启动服务提供者工程和服务消费者工程,可以在查看到对应的信息
6. Dubbo 相关配置说明
6.1 包扫描
服务提供者和服务消费者都需要配置,表示包扫描,作用是扫描指定包 ( 包括子包 ) 下的类。
package = "com.lxs.service" /> 如果不使用包扫描,也可以通过如下配置的方式来发布服务:
作为服务消费者,可以通过如下配置来引用服务:
上面这种方式发布和引用服务,一个配置项 ( dubbo:service dubbo:reference ) 只能发布或者引用一个
服务,如果有多个服务,这种方式就比较繁琐了。推荐使用包扫描方式。
6.2 协议
一般在服务提供者一方配置,可以指定使用的协议名称和端口号。
其中 Dubbo 支持的协议有: dubbo rmi hessian http webservice rest redis 等。
推荐使用的是 dubbo 协议。
dubbo 协议采用单一长连接和 NIO 异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机
器数远大于服务提供者机器数的情况。不适合传送大数据量的服务,比如传文件,传视频等,除非请求
量很低。
也可以在同一个工程中配置多个协议,不同服务可以使用不同的协议,例如:
6.3 负载均衡
负载均衡( Load Balance ):其实就是将请求分摊到多个操作单元上进行执行,从而共同完成工作任
务。
在集群负载均衡时, Dubbo 提供了多种均衡策略(包括随机、轮询、最少活跃调用数、一致性
Hash ),缺省为 random 随机调用。
配置负载均衡策略,既可以在服务提供者一方配置,也可以在服务消费者一方配置,如下:
id = "helloService" class = "com.lxs.service.impl.HelloServiceImpl" />
interface = "com.lxs.api.HelloService" ref = "helloService" />
id = "helloService" interface = "com.lxs.api.HelloService" />
name = "dubbo" port = "20880" />
name = "dubbo" port = "20880" />
name = "rmi" port = "1099" />
interface = "com.lxs.api.HelloService" ref = "helloService"
protocol = "dubbo" />
interface = "com.lxs.api.DemoService" ref = "demoService"
protocol = "rmi" />
@Controller
@RequestMapping ( "/demo" )
public class HelloController {
// 在服务消费者一方配置负载均衡策略
@Reference ( check = false , loadbalance = "random" )
private HelloService helloService ; 可以通过启动多个服务提供者来观察 Dubbo 负载均衡效果。
注意:因为我们是在一台机器上启动多个服务提供者,所以需要修改 tomcat 的端口号和 Dubbo 服务的
端口号来防止端口冲突。
在实际生产环境中,多个服务提供者是分别部署在不同的机器上,所以不存在端口冲突问题。
7. 解决 Dubbo 无法发布被事务代理的 Service 问题
前面我们已经完成了 Dubbo 的入门案例,通过入门案例我们可以看到通过 Dubbo 提供的标签配置就可
以进行包扫描,扫描到 @Service 注解的类就可以被发布为服务。
但是我们如果在服务提供者类上加入 @Transactional 事务控制注解后,服务就发布不成功了。原因是事
务控制的底层原理是为服务提供者类创建代理对象,而默认情况下 Spring 是基于 JDK 动态代理方式创建
代理对象,而此代理对象的完整类名为 com.sun.proxy.$Proxy42 (最后两位数字不是固定的),导致
Dubbo 在发布服务前进行包匹配时无法完成匹配,进而没有进行服务的发布。
7.1 问题展示
在入门案例的服务提供者 dubbodemo_provider 工程基础上进行展示
操作步骤:
1 )在 pom.xml 文件中增加 maven 坐标
@RequestMapping ( "/hello" )
@ResponseBody
public 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 ;
}
}
mysql
mysql-connector-java
5.1.47
com.alibaba
druid
1.1.6
org.mybatis
mybatis-spring 1.3.2
2 )在 applicationContext-service.xml 配置文件中加入数据源、事务管理器、开启事务注解的相关配
id = "dataSource" class = "com.alibaba.druid.pool.DruidDataSource" destroy-
method = "close" >
name = "username" value = "root" />
name = "password" value = "root" />
name = "driverClassName" value = "com.mysql.jdbc.Driver" />
name = "url" value = "jdbc:mysql://localhost:3306/test" />
id = "transactionManager"
class = "org.springframework.jdbc.datasource.DataSourceTransactionManager" >
name = "dataSource" ref = "dataSource" />
transaction-manager = "transactionManager" />
上面连接的数据库可以自行创建
3 )在 HelloServiceImpl 类上加入 @Transactional 注解
4 )启动服务提供者和服务消费者,并访问
上面的错误为没有可用的服务提供者
查看 dubbo 管理控制台发现服务并没有发布,如下:
可以通过断点调试的方式查看 Dubbo 执行过程, Dubbo 通过 AnnotationBean
postProcessAfterInitialization 方法进行处理 7.2 解决方案
通过上面的断点调试可以看到,在 HelloServiceImpl 类上加入事务注解后, Spring 会为此类基于 JDK
态代理技术创建代理对象,创建的代理对象完整类名为 com.sun.proxy.$Proxy35 ,导致 Dubbo 在进行
包匹配时没有成功(因为我们在发布服务时扫描的包为 com.lxs.service ),所以后面真正发布服务的代
码没有执行。
解决方式操作步骤:
1 )修改 applicationContext-service.xml 配置文件,开启事务控制注解支持时指定 proxy-target-class
属性,值为 true 。其作用是使用 cglib 代理方式为 Service 类创建代理对象
2 )修改 HelloServiceImpl 类,在 Service 注解中加入 interfaceClass 属性,值为 HelloService.class
作用是指定服务的接口类型
transaction-manager = "transactionManager" proxy-target-
class = "true" /> @Service ( interfaceClass = HelloService . class )
@Transactional
public class HelloServiceImpl implements HelloService {
public String sayHello ( String name ) {
return "hello " + name ;
}
}

你可能感兴趣的:(rpc,zookeeper,java)