Dubbo基本使用

639 阅读11分钟

一、RPC简介

1. 分布式

分布式系统就是若干独立计算机(服务器) 的集合

传统单一应用架构的缺点:

  1. 性能扩展比较困难
  2. 不利于多人同时开发
  3. 不利于升级维护
  4. 整个系统的空间占用比较大

2. RPC

RPC 【Remote Procedure Call】 是指远程过程调用, 是一种进程间通信方式,是一种技术思想,而不是规范。 它允许程序调用另一个地址空间(网络的另一台机器上)的过程或函数。可以简单的理解为分布式计算机(服务器)之间的通信方式

RPC 的特点:

  1. 简单:使用简单,建立分布式应用更容易。
  2. 高效:调用过程看起来十分清晰,效率高。

二、dubbo框架

Apache Dubbo (incubating) |ˈdʌbəʊ| 是一款高性能、轻量级的开源 Java RPC 框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。 Dubbo 是一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案、 服务治理方案。

官网: dubbo.apache.org/zh-cn/

1. 基本架构

在这里插入图片描述

2. 架构组件

  • 服务容器(Container):管理服务提供者。
  • 服务提供者( Provider): 暴露服务的服务提供方, 服务提供者在启动时,向注册中心注册自己提供的服务。
  • 服务消费者( Consumer) : 调用远程服务的服务消费方, 服务消费者在启动时,向注册中心订阅自己所需的服务, 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  • 注册中心(Registry): 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者
  • 监控中心( Monitor): 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心

3. 调用过程

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

4. dubbo 支持的协议

支持多种协议: dubbo , hessian , rmi , http, webservice , thrift , memcached , redis。

dubbo 官方推荐使用 dubbo 协议。 dubbo 协议默认端口 20880 使用 dubbo 协议, spring 配置文件加入:<dubbo:protocol name="dubbo" port="20880" />

三、直连方式的简单实现

点对点的直连项目:消费者直接访问服务提供者,没有注册中心。消费者必须指定服务提供者的访问地址(url)。 消费者直接通过 url 地址访问固定的服务提供者。这个 url 地址是不变的。

1. 分包、粒度、版本

  • 分包:建议将服务接口、服务模型、服务异常等均放在公共包中。
  • 粒度:服务接口尽可能大粒度,每个服务方法应代表一个功能,而不是某功能的一个步骤,服务接口建议以业务场景为单位划分,并对相近业务做抽象,防止接口数量爆炸。
    • 不建议使用过于抽象的通用接口,如: Map query(Map),这样的接口没有明确语义(不知道要查询什么),会给后期维护带来不便。
  • 版本:每个接口都应定义版本号, 区分同一接口的不同实现,如: <dubbo:service interface="com.xxx.XxxService" version="1.0" />

现在实现一个简单的需求,以理解Dubbo的工作原理。这里先不使用注册中心,通过直连的方式完成。某电商平台系统需求,用户购买商品,通过订单系统生成订单;用户访问用户信息系统,查看自己的信息(订单系统与用户信息系统在两台服务器上,且两个系统共用的部分单独放在一个项目中)

2. 公共资源项目

新建一个Maven的javaSE工程项目,在项目上定义接口和实体类,项目的目录结构:

3. 用户信息服务模块

新建一个maven的Web模块

(1)加入依赖和编译插件

<dependencies>
    <!--加入第二步中创建的公共资源模块-->
    <dependency>
        <groupId>com.wkcto.dubbo</groupId>
        <artifactId>003-node-interface</artifactId>
        <version>1.0.0</version>
    </dependency>
    <!--SpringMVC依赖-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>4.3.16.RELEASE</version>
    </dependency>
    <!--spring框架依赖-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.16.RELEASE</version>
    </dependency>
    <!--Dubbo依赖-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>dubbo</artifactId>
        <version>2.6.2</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <!--JDK1.8编译插件-->
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
</build>

(2)创建公共模块中接口的实现类

注意:实体bean要进行序列化,即需要实现Serializable接口

(3)配置文件(服务提供者)

  • <dubbo:application/>:配置应用信息
    • name:服务名称,。当前的服务名称,具有唯一性
  • <dubbo:protocol/>:配置注册中心
    • name:传输协议(dubbo)
    • port:端口号。端口号是用来在服务提供者中找到要访问的服务,在同一个电脑上,一个服务(模块)对应一个端口
  • <dubbo:service/>:配置暴露的服务
    • interface:要暴露的接口的全限定类名
    • ref:接口的实现类(接口对外服务的功能)
    • registry:用N/A来表示直接,不使用注册中心
    • version:如果接口有多个实现类,通过该参数指定不同的实现类(多态)
    • timeout:调用远程服务超时时间(毫秒)
    • retries:设置访问失败时的重试次数(不含第一次)
<?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:dubbo="http://dubbo.apache.org/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo 
       http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
	<!--服务名称,服务名称要保证它的唯一性-->
    <dubbo:application name="005-node-orderservice-provider"/>
	<!--dubbo指定使用的协议和端口号-->
    <dubbo:protocol name="dubbo" port="20884"/>

	<!--暴露服务
        interface:要暴露服务的接口名称
        ref:接口实现类的标识
        registry:不使用注册中心,值为N/A
    -->
    <dubbo:service interface="com.wkcto.dubbo.service.OrderService" ref="orderServiceImpl" registry="N/A"/>
	<!--这里使用手动的方式,声明服务接口的实现类bean-->
    <bean id="orderServiceImpl" class="com.wkcto.dubbo.service.impl.OrderServiceImpl"/>

</beans>

(4)配置Tomcat(web.xml)

在idea中配置Tomcat的地方,配置Tomcat的端口为:8081,Idea JMX端口为:1097,防止后面用idea用debug模式开启多个Tomcat时,产生端口冲突。

再配置web.xml文件:

  • 加入全局作用域对象的监听器,自动加载dubbo的配置文件,创建dubbo服务
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:orderservice-provider.xml</param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

4、创建订单系统

创建订单系统的前两步与 3 中的创建步骤一样

(1)Dubbo配置文件

与 3 中的第(3)步差不多,需要改一下dubbo的端口号、暴露的接口和对应的接口实现类

(2)Tomcat(web.xml)

Tomcat的端口和Idea JMX(IDEA Debug服务运行的端口)的端口改一下,不要重

5. 创建服务消费者

(1)配置文件(服务消费者)

关键步骤:

  • <dubbo:reference/>:配置服务消费者引用的远程服务
    • id:本地的该接口的名字
    • interface:远程的接口的全限定接口名
    • url:访问的远程接口的url,使用dubbo协议
    • version:通过该参数指定相同接口的不同版本(实现类、多态)
    • registry:"N/A" 表示使用直连的方式
    • timeout:调用远程服务超时时间(毫秒)
    • retries:设置访问失败时的重试次数(不含第一次)
    • check="true":false为关闭检查,默认为true。dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动,则可以设置该属性为false。
<dubbo:application name="006-node-consumer-web"/>

<dubbo:reference id="remoteOrderService"
                 interface="com.wkcto.dubbo.service.OrderService"
                 url="dubbo://localhost:20884"
                 registry="N/A"/>

<dubbo:reference id="remoteAddressService"
                 interface="com.wkcto.dubbo.service.AddressService"
                 url="dubbo://localhost:20883"
                 registry="N/A"/>

<bean id="shopService" class="com.wkcto.dubbo.service.impl.ShopServiceImpl">
    <property name="orderService" ref="remoteOrderService"/>
    <property name="addressService" ref="remoteAddressService"/>
</bean>

(2)其它步骤

在获取到了远程的服务接口后,就可以在当前项目中进行使用,剩下的步骤与SSM中的一样,此处就省略不写了。

四、注册中心

Dubbo 提供的注册中心有如下几种类型可供选:

  • Multicast 注册中心:组播方式
  • Redis 注册中心:使用 Redis 作为注册中心
  • Simple 注册中心:就是一个 dubbo 服务。作为注册中心。提供查找服务的功能。
  • Zookeeper 注册中心:使用 Zookeeper 作为注册中心

推荐使用 Zookeeper 注册中心。

1. 注册中心工作方式

在这里插入图片描述

2. 配置zookeeper

Zookeeper 是一个高性能的, 分布式的,开放源码的分布式应用程序协调服务。 简称 zk。Zookeeper 是翻译过来是动物管理员。可以理解为 windows 中的资源管理器或者注册表。他是一个树形结构。这种树形结构和标准文件系统相似。 ZooKeeper 树中的每个节点被称为Znode。和文件系统的目录树一样, ZooKeeper 树中的每个节点可以拥有子节点。每个节点表示一个唯一服务资源。 Zookeeper 运行需要 java 环境 官网下载地址:zookeeper.apache.org/

配置步骤(Linux与Windows的配置步骤一样):

  • 下载的文件 zookeeper-3.5.4-beta.tar.gz. 解压后到目录

  • 修改 zookeeper-3.5.4/conf/ 目录下的配置文件。复制 zoo-sample.cfg 改名为 zoo.cfg

  • 配置文件中几项重要的参数:

    • tickTime:心跳的时间,单位毫秒。Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳。表明存活状态。默认即可
    • dataDir:数据目录,可以是任意目录。 存储 zookeeper 的快照文件、 pid 文件,默认为/tmp/zookeeper,建议在 zookeeper 安装目录下创建 data 目录,将 dataDir 配置改为/usr/local/zookeeper-3.4.10/data
    • clientPort:客户端连接 zookeeper 的端口,即 zookeeper 对外的服务端口,默认为 2181
    • check="true":关闭(false)注册中心启动时检查,默认启动服务时检查注册中心存在并已运行(true)。注册中心不启动会报错。一般开发时配,生产上不配
  • 另外因为 zookeeper 3.5.x 内部默认会启动一个应用服务器,默认占用 8080 端口,所以需要设置:

    • admin.serverPort=8888

3. 启动zookeeper服务

  • Windows下使用zookeeper安装目录下 bin/zsService.cmd
  • Linux 下在zookeeper安装目录 bin 下执行下列命令(需要Linux有JDK):
    • 启动(切换到安装目录的 bin 目录下): ./zkServer.sh start
    • 关闭(切换到安装目录的 bin 目录下): ./zkServer.sh stop

五、将三中的项目改为使用注册中心

1. 新增依赖

<!--zookeeper依赖-->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>4.1.0</version>
</dependency>

2. 更改dubbo配置文件

  • <dubbo:registry address="zookeeper://localhost:2181"/>:配置zookeeper注册中心
  • 去掉所有的registry="N/A"属性
  • 服务提供者不需要通过url来指定服务地址,而是通过注册中心来获取服务地址,所以可以删掉

(1)服务提供者

<?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:dubbo="http://dubbo.apache.org/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <dubbo:application name="004-node-userservice-provider"/>

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

    <!--使用zookeeper注册中心-->
    <dubbo:registry address="zookeeper://localhost:2181"/>

    <!--<dubbo:service interface="com.bjpowernode.dubbo.service.AddressService" ref="addressServiceImpl" registry="N/A"/>-->
    <dubbo:service interface="com.bjpowernode.dubbo.service.AddressService" ref="addressServiceImpl"/>

    <bean id="addressServiceImpl" class="com.bjpowernode.dubbo.service.impl.AddressServiceImpl"/>
</beans>

(2)服务消费者

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
    
    <dubbo:application name="006-node-customer-web"/>
	
	<!--新增了zookeeper的-->
    <dubbo:registry address="zookeeper://localhost:2181"/>

    <dubbo:reference id="remoteAddressService"
                     interface="com.bjpowernode.dubbo.service.AddressService" />

	<!--删除的url和registry-->
    <dubbo:reference id="remoteOrderService"
                     interface="com.bjpowernode.dubbo.service.OrderService"/>
                     
    <bean id="shopService" class="com.bjpowernode.dubbo.service.impl.ShopServiceImpl">
        <property name="orderService" ref="remoteOrderService"/>
        <property name="addressService" ref="remoteAddressService"/>
    </bean>

</beans>

3. dubbo的高可用

高可用性(High Availability):通常来描述一个系统经过专门的设计,从而减少不能提供服 务的时间,而保持其服务的高度可用性。

  1. Zookeeper 是高可用的,健壮的。 Zookeeper 宕机,正在运行中的 dubbo 服务仍然可以正常访问。
  2. 监控中心宕掉不影响使用,只是丢失部分采样数据
  3. 注册中心仍能通过缓存提供服务列表查询,但不能注册新服务
  4. 服务提供者无状态,任意一台宕掉后,不影响使用
  5. 服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复

六、监控中心

1. 下载

下载监控中心:github.com/apache/incu… 这里下载的是源代码,需要手工编译才能使用。

2. 配置监控中心

修改配置 dubbo-admin-0.0.1-SNAPSHOT.jar\BOOT-INF\classes\application-properties 文件: 在这里插入图片描述

3. 运行管理后台 dubbo-admin

到 dubbo-admin-0.0.1-SNAPSHOT.jar 所在的目录。执行下面命令:

java -jar dubbo-admin-0.0.1-SNAPSHOT.jar

4. 运行 dubbo-admin 应用

1) 先启动注册中心 2) 执行提供者项目 3) java -jar dubbo-admin-0.0.1-SNAPSHOT.jar 启动 dubbo 管理后台 4)在浏览器地址栏输入 http://localhost:7001 访问监控中心-控制台。 监控中心的数据来自注册中心(Zookeeper)(配置文件中的dubbo.registry.address=zookeeper://127.0.0.1:2181

七、遇到的异常

1. 循环依赖

Error:Cannot build artifact '07-zk-orderservice:war exploded' because it is included into a circular dependency (artifact '07-zk-orderservice:war exploded', artifact '04-node-orderservice (1):war exploded')

  • 问题说明:包含循环依赖
  • 解决过程:
    • 看pom.xml中maven模块之间是否存在想到依赖
    • 查看 File --> Project Structure --> Project Settings --> Artifacts 中查看是否出现多余的Artifacts

2. java.lang.IllegalStateException

java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [org.apache.zookeeper.ZooKeeperTestable]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.…………

  • 造成原因:没有开启zookeeper注册中心
  • 解决办法:开启zookeeper注册中心