一文上手Dubbo

1 什么是分布式系统

把一个系统按模块分拆成多个子系统,每个子系统部署到不同的服务器上,分布式系统就是这些子系统的集合,但对用户是透明的,用户使用时,感觉只是一个系统。

2 Dubbo是什么

一款高性能的、轻量级的、开源的java RPC框架。
就是后台调用后台时用的。

3 Dubbo官网

http://dubbo.apache.org/zh-cn/

4 Zookeeper的作用

注册中心

5 Zookeeper安装

1、 下载zookeeper-3.4.11.tar.gz
2、 解压
3、 配置文件:
1) 将conf文件夹下的zoo_sample.cfg改名为zoo.cfg
2) clientPort=2181(Zookeeper端口号)
3) dataDir=…/data(数据存储路径)
4、 启动Zookeeper,命令:zkServer.cmd(Windows)或 zkServer.sh(Linux)

6 安装Dubbo管理控制台

1、 下载 incubator-dubbo-ops-master.zip(在dubbo的GitHub上找)
2、 解压
3、 使用Maven打包 dubbo-admin工程,生成dubbo-admin-0.0.1-SNAPSHOT.jar
4、 运行:java –jar dubbo-admin-0.0.1-SNAPSHOT.jar
5、 登录:localhost:7001 默认用户名:root 密码:root
注意:管理控制台依赖Zookeeper服务,因此使用此管理控制台,必须开启Zookeeper服务。

7 Maven+Spring工程下使用Dubbo

7.1 总流程

1、将服务提供者注册到注册中心(暴露服务)
1)导入Dubbo依赖(2.6.2) 和 Zookeeper客户端
2)配置服务提供者

2、让服务消费者去注册中心订阅服务提供者

7.2 场景

创建3个工程,分别是 common-server、user-server、order-server
common-server 用于存放所有的 bean 和 service 接口
user-server 是服务提供者
order-server 是服务消费者

7.3 提供者端步骤

7.3.1 编写Service接口和实现类

com.hongyu.dubbo.service.UserService
com.hongyu.dubbo.service.impl.UserServiceImpl

7.3.2 引入Dubbo依赖和Zookeeper客户端依赖

<!-- 引入Dubbo -->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>dubbo</artifactId>
      <version>2.6.2</version>
    </dependency>
    <!-- 引入操作Zookeeper的客户端 -->
    <dependency>
      <groupId>org.apache.curator</groupId>
      <artifactId>curator-framework</artifactId>
      <version>2.12.0</version>
    </dependency>

7.3.3 Spring中配置Dubbo

<!-- 1、指定当前应用的名字 (同样的服务名字相同,不同的服务名字不同) -->
    <dubbo:application name="user-service"/>

    <!-- 2、指定注册中心的位置 -->
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
    <!--  或者这么写也行
    <dubbo:registry protocol="zookeeper" address="127.0.0.1:2181" />
    -->

    <!-- 3、指定通信规则 通信协议?通信端口 -->
    <dubbo:protocol name="dubbo" port="20880" />

    <!-- 4、暴露服务 ref:指向服务的实现 -->
<dubbo:service interface="com.hongyu.dubbo.service.UserService" 
ref="userServiceImpl" />
    <!-- 服务的实现 -->
<bean id="userServiceImpl" 
class="com.hongyu.dubbo.service.impl.UserServiceImpl" />

7.4 消费者端步骤

7.4.1 编写Service接口和实现类

com.hongyu.dubbo.service.OrderService
com.hongyu.dubbo.service.impl.OrderServiceImpl

7.4.2 将UserService接口拷贝到消费者工程

注意:接口所在的包不能变
也可以把接口和bean单独放在一个单独的工程中

7.4.3 在实现类中依赖注入UserService

@Autowired
private UserService userService;

7.4.4 引入Dubbo依赖和Zookeeper客户端依赖

<!-- 引入Dubbo -->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>dubbo</artifactId>
      <version>2.6.2</version>
    </dependency>
    <!-- 引入操作Zookeeper的客户端 -->
    <dependency>
      <groupId>org.apache.curator</groupId>
      <artifactId>curator-framework</artifactId>
      <version>2.12.0</version>
    </dependency>

7.4.5 Spring中配置Dubbo

<context:component-scan base-package="com.hongyu.dubbo" />

    <!-- 1、指定当前应用的名字 (同样的服务名字相同,不同的服务名字不同) -->
    <dubbo:application name="order-service"/>

    <!-- 2、指定注册中心的位置 -->
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
    <!--  或者这么写也行
    <dubbo:registry protocol="zookeeper" address="127.0.0.1:2181" />
    -->

    <!-- 声明需要调用的远程服务的接口 生成远程服务代理 -->
<dubbo:reference id="userService" 
interface="com.hongyu.dubbo.service.UserService" />

7.4.6 将OrderService也放入Spring容器

@ org.springframework.stereotype.Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private UserService userService;

7.4.7 验证

先启动user-server服务
再启动order-server服务
调用order-server的Service接口方法,order-server再远程RPC调用user-service的方法
如果能拿到结果,证明配置成功,否则配置失败
此时查看Dubbo控制台,可以看到有一个提供者和一个消费者

8 安装Dubbo监控中心

1、 下载 incubator-dubbo-ops-master.zip(在dubbo的GitHub上找)
2、 解压
3、 使用Maven打包 dubbo-monitor-simple工程,生成dubbo-monitor-simple-2.0.0.jar 和 dubbo-monitor-simple-2.0.0-assembly.tar.gz
4、 解压 dubbo-monitor-simple-2.0.0-assembly.tar.gz 文件
5、 修改 conf/ dubbo.properties
dubbo.registry.address=zookeeper://127.0.0.1:2181
6、 运行: assembly.bin/start.bat
7、 验证:http://localhost:8080/
8、 在提供者和消费者工程的Spring文件中配置监控中心

<!-- 发现监控中心 自动发现 -->
    <dubbo:monitor protocol="registry" />
    <!--  或者这么写,指定监控中心的地址
    <dubbo:monitor address="127.0.0.1:7070" />
    -->

9 Dubbo与SpringBoot整合

9.1 创建提供者和消费者的Springboot工程

9.2 在提供者和消费者的pom.xml文件中引入Dubbo依赖

<dependency>
			<groupId>com.alibaba.boot</groupId>
			<artifactId>dubbo-spring-boot-starter</artifactId>
			<version>0.2.0</version>
		</dependency>

9.3 配置提供者的application.properties文件

dubbo.application.name=boot-user-service
dubbo.registry.protocol=zookeeper
dubbo.registry.address=127.0.0.1:2181
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
dubbo.monitor.protocol=registry

9.4 提供者在需要暴露接口的Service实现类上,加入注解

@org.springframework.stereotype.Component
@com.alibaba.dubbo.config.annotation.Service

9.5 配置消费者的application.properties文件

dubbo.application.name=boot-order-service
dubbo.registry.protocol=zookeeper
dubbo.registry.address=127.0.0.1:2181
dubbo.monitor.protocol=registry
server.port=8081

9.6 在消费者的Service中引入提供者的Service接口

@com.alibaba.dubbo.config.annotation.Reference
private UserService userService;

9.7 在提供者和消费者的SpringBoot启动类中加入@EnableDubbo注解

@com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo

10 Dubbo配置提取优先级

1、 取Java虚拟机参数,例如:-Ddubbo.protocol.port=20883
2、 取spring配置文件
3、 取 dubbo.properties

11 配置消费者启动时不检查远程的Service引用

Spring配置文件中,引用的标签加入 check=”false”

<dubbo:reference id="userService" 
interface="com.hongyu.dubbo.service.UserService" check="false" />

<!—统一配置消费者策略 -->
<dubbo:consumer check="false" />

<!— 注册中心是否存在,也可以启动时不检查 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181" check=”false” />

12 Dubbo的超时设置

默认是1秒

<!-- 声明需要调用的远程服务的接口 生成远程服务代理 设置3秒超时 -->
<dubbo:reference id="userService" 
interface="com.hongyu.dubbo.service.UserService" timeout="3000" />


<!-- 声明需要调用的远程服务的接口 生成远程服务代理 -->
<dubbo:reference id="userService"
 interface="com.hongyu.dubbo.service.UserService" timeout="4000">
        <!-- 超时也可以设置在方法上 -->
        <dubbo:method name="getUserAddressList" timeout="3000" />

    </dubbo:reference>

配置的优先级:
方法级优先,接口级次之,全局配置再次之。
级别一样,则消费方优先,提供方次之

13 Dubbo的重试次数设置

重试次数不包含第1次调用

<dubbo:reference id="userService" 
interface="com.hongyu.dubbo.service.UserService" timeout="4000" retries="3">

优先级与超时相同

如果同一服务起了多个副本,则会重试不同的副本

通常幂等方法中会设置重试,非幂等方法通常不设置重试

14 Dubbo的多版本

14.1 作用

实现灰度发布,只升级部分机器,防止新版本的不稳定

14.2 配置步骤

14.2.1 提供者暴露多个版本的接口

在Spring配置文件中配置:

<!-- 4、暴露服务 ref:指向服务的实现 -->
<dubbo:service interface="com.hongyu.dubbo.service.UserService" 
ref="userServiceImpl01" version="1.0.0" />
    <!-- 服务的实现 -->
<bean id="userServiceImpl01" 
class="com.hongyu.dubbo.service.impl.UserServiceImpl" />

    <!-- 4、暴露服务 ref:指向服务的实现 -->
<dubbo:service interface="com.hongyu.dubbo.service.UserService" 
ref="userServiceImpl02" version="2.0.0" />
    <!-- 服务的实现 -->
<bean id="userServiceImpl02" 
class="com.hongyu.dubbo.service.impl.UserServiceImpl2" />

14.2.2 消费者引用时指定版本号

在Spring配置文件中配置:

<dubbo:reference id="userService" 
interface="com.hongyu.dubbo.service.UserService" timeout="4000" retries="3" 
version="2.0.0" />

version 属性指定为 * ,则随机访问所有版本

15 Dubbo的本地存根

15.1 概述

消费者端对远程调用的接口进行二次封装,做一些校验等额外工作。

15.2 具体步骤

15.2.1 创建存根类

com.hongyu.dubbo.service.impl.UserServiceStub

15.2.2 实现提供者的UserService接口

public class UserServiceStub implements UserService {

15.2.3 将提供者的接口作为成员变量并在构造方法中注入

public class UserServiceStub implements UserService {

    private UserService userService;

    /**
     *  传入的是UserService的远程代理对象
     * @param userService
     */
    public UserServiceStub(UserService userService) {
        this.userService = userService;
    }

15.2.4 实现对应的方法逻辑

   @Override
    public List<UserAddress> getUserAddressList(String userId) {

        System.out.println("进入UserService存根");

        if(StringUtils.isBlank(userId)) {
            System.out.println("存根条件不符合");
            return new ArrayList<>();
        }

        System.out.println("执行远程调用");
        return userService.getUserAddressList(userId);
    }

15.2.5 Spring中配置存根

<!-- 声明需要调用的远程服务的接口 生成远程服务代理 -->
<dubbo:reference id="userService" 
interface="com.hongyu.dubbo.service.UserService"
timeout="4000" retries="3" version="*" 
stub="com.hongyu.dubbo.service.impl.UserServiceStub">
        <!-- 超时也可以设置在方法上 -->
        <dubbo:method name="getUserAddressList" timeout="3000" />

    </dubbo:reference>

16 Dubbo与SpringBoot整合的其他方式

16.1 三种方式

16.1.1 第一种:在Spring配置文件中配置Dubbo属性

导入 dubbo-starter,在application.properties配置属性,使用@Service暴露服务,使用@Reference引用服务,在SpringBoot启动类加上@EnableDubbo注解

16.1.2 第二种:在原生Dubbo配置文件中配置Dubbo属性

保留Dubbo配置文件,同样需要导入 dubbo-starter
将配置Dubbo属性的Spring文件拷贝到Springboot工程,然后在启动文件处引用。并且删除@EnableDubbo注解

@ImportResource(locations = "classpath:provider.xml")
//@EnableDubbo(scanBasePackages = {"com.hongyu.dubbo"})
@SpringBootApplication(scanBasePackages = {"com.hongyu.dubbo"})
public class BootUserServiceApplication {
	public static void main(String[] args) {
		SpringApplication.run(BootUserServiceApplication.class, args);
	}
}

注意:有一些配置只在Spring配置文件中才能配,注解实现不了,例如在暴露的方法的上配置属性

16.1.3 第三种 使用注解API的方式(写一个配置类)

同样需要导入 dubbo-starter
写一个Dubbo的配置类,例如com.hongyu.dubbo.config.MyDubboConfig

package com.hongyu.dubbo.config;

import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.MonitorConfig;
import com.alibaba.dubbo.config.ProtocolConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyDubboConfig {

    /**
     * <dubbo:application name="user-service"/>
     * @return
     */
    @Bean
    public ApplicationConfig applicationConfig() {
        ApplicationConfig config = new ApplicationConfig();
        config.setName("boot-user-service");
        return config;
    }

    /**
     *  <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
     * @return
     */
    @Bean
    public RegistryConfig registryConfig() {
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setAddress("zookeeper://127.0.0.1:2181");
        return  registryConfig;
    }

    /**
     * <dubbo:protocol name="dubbo" port="20882" />
     * @return
     */
    @Bean
    public ProtocolConfig protocolConfig() {
        ProtocolConfig protocolConfig = new ProtocolConfig();
        protocolConfig.setName("dubbo");
        protocolConfig.setPort(20884);
        return protocolConfig;
    }

    /**
     * <dubbo:monitor protocol="registry" />
     */
    @Bean
    public MonitorConfig monitorConfig() {
        MonitorConfig monitorConfig = new MonitorConfig();
        monitorConfig.setProtocol("registry");
        return monitorConfig;
    }

}

暴露接口,还是使用 @com.alibaba.dubbo.config.annotation.Service 注解

需要在Springboot启动类配置包扫描
@EnableDubbo(scanBasePackages = {“com.hongyu.dubbo”})

17 Dubbo高可用

17.1 缓存机制

当注册中心,例如Zookeeper宕机后,如果消费者访问过一次提供者,则消费者会缓存提供者的地址,提供者地址不变的情况下,仍然可以访问。

17.2 可以直连

可以不通过Zookeeper,直连提供者

@Reference(url=”127.0.0.1:80885”)
private UserService userService;

(多版本的情况下,可能会失效,也不推荐用这种方式)

17.3 负载均衡机制

17.3.1 Random

随机策略,可配权重,权重越高被调用的几率越大

17.3.2 RoundRobin

轮询,可配权重,权重越高被轮询到的次数越多
例如:
3台机器,第一台权重是100,第二台是200,第三台是50
则第一台的访问几率是 100/(100+200+50) = 2/7
则第二台的访问几率是 200/(100+200+50) = 4/7
则第三台的访问几率是 50/(100+200+50) = 1/7

按轮询的机制,机器被访问的顺序是 1 2 3 1 2 2 2
因为是轮询,所以是按顺序访问,但有权重,当第6次访问时,发现3号机已没有几率,然后发现1号机也没有几率了,所以访问了2号机,以此类推

17.3.3 LeastActive

最少活跃调用数,在调用接口后,会记录响应时间,始终访问响应最快的机器

17.3.4 ConsistentHash

一致性Hash
将某一属性的值,进行Hash计算,Hash值相同,会始终访问同一台机器。

17.4 设置负载均衡策略

默认是随机策略

在提供者的暴露处或消费者的引用处制定负载均衡策略

loadbalance = RandomLoadBalance.NAME
loadbalance = RoundRobinLoadBalance.NAME
loadbalance = LeastActiveLoadBalance.NAME

17.5 设置权重

在暴露接口的Service注解中设置,@Service(version = "2.0.0", weight = 100)

或者使用管理控制台设置

17.6 服务降级

可以在控制台,把消费者端某个接口屏蔽,则直接返给客户端的是空页面
把消费者某个接口设置为容错,则在超时等访问失败时,返回为空
(多版本的情况下,会失效)

17.7 服务容错

17.7.1 配置重试

通过前面说的配置重试次数,可以切换到不同的服务器重试

17.7.2 集群容错模式

17.7.2.1 Failover Cluster

失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries=“2” 来设置重试次数(不含第一次)。

重试次数配置如下:

<dubbo:service retries="2" />
或
<dubbo:reference retries="2" />
或
<dubbo:reference>
    <dubbo:method name="findFoo" retries="2" />
</dubbo:reference>

17.7.2.2 Failfast Cluster

快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。

17.7.2.3 Failsafe Cluster

失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。

17.7.2.4 Failback Cluster

失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。

17.7.2.5 Forking Cluster

并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks=“2” 来设置最大并行数。

17.7.2.6 Broadcast Cluster

广播调用所有提供者,逐个调用,任意一台报错则报错 [2]。通常用于通知所有提供者更新缓存或日志等本地资源信息。

17.7.3 集群模式配置

按照以下示例在服务提供方和消费方配置集群模式

<dubbo:service cluster="failsafe" />
或
<dubbo:reference cluster="failsafe" />

默认是 Failover Cluster

17.8 整合Hystrix进行容错

17.8.1 依赖

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
	<version>2.0.1.RELEASE</version>
</dependency>

17.8.2 启动类上加上@EnableHystrix

17.8.3 需要降级的方法上增加@HystrixCommand注解

@HystrixCommand(fallbackMethod = "hello")
public List<UserAddress> getUserAddressList(String userId)
// fallbackMethod是设置回调方法,该方法的参数和返回值都可以和降级的方法一样

17.8.4 编写hello方法

public List<UserAddress> hello(String userId) {

        List<UserAddress> list = new ArrayList<>();

        list.add(new UserAddress(1, "11","11" ,"11","11","Y"));
        return list;
    }
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐