使用 Apache Dubbo 实现远程通信(微服务架构)


Posted in Servers onFebruary 12, 2022
目录

前言

参考资料:
《Spring Microservices in Action》
《Spring Cloud Alibaba 微服务原理与实战》
《B站 尚硅谷 SpringCloud 框架开发教程 周阳》

Apache Dubbo 是一个分布式服务框架,主要实现多个系统之间的高性能、透明化调用;
Dubbo 相关内容笔者之前写过一篇入门笔记:Dubbo快速上手笔记 - 环境与配置。入门笔记强调的是 Dubbo 的一些基本特性,以与 Zookeeper 的整合。因此这里将重点放在 Dubbo 与 Spring Cloud 的联系、区别以及整合;

1. Dubbo 基础知识

1.1 Dubbo 是什么

  • Apache Dubbo 是一个分布式服务框架,主要实现多个系统之间的高性能、透明化调用;
  • 简单来说它就是一个 RPC 框架,但是和普通的 RPC 框架不同的是,它提供了服务治理功能,比如服务注册、监控、路由、容错等;

1.2 Dubbo 的架构图

使用 Apache Dubbo 实现远程通信(微服务架构)

1.3 Spring Cloud 与 Dubbo 的区别

参考:https://segmentfault.com/a/1190000038320266

比较项 Dubbo Spring Cloud
通信协议 基于 TCP 协议传输,使用 Netty 配合以Hession序列化完成RPC通信 基于 HTTP 协议 + REST 接口调用远程过程的通信
服务调用方式 RPC REST API
定位 SOA 时代的产物 微服务架构时代
关注点 服务的重用性及解决信息孤岛问题;服务治理 解耦,降低业务之间的耦合度;微服务治理整套方案
模块 服务注册中心、服务提供者、服务消费者、管控中心 分布式一站式框架
  • HTTP 请求会有更大的报文,占的带宽也会更多。但是 REST 相比 RPC 更为灵活,服务提供方和调用方的依赖只依靠一纸契约,不存在代码级别的强依赖,这在强调快速演化的微服务环境下,显得更为合适;
  • 模块组件的具体比较如下:
组件 Dubbo Spring Cloud (Netflix)
注册中心 以前是 Zookeeper,现在推广 Nacos Spring Cloud Eureka
服务监控 Dubbo-monitor Spring Boot Admin
熔断器 6种容错模式 Spring Cloud Hystrix
负载均衡 4 种负载均衡策略 Spring Cloud Ribbon
服务降级 Mock 机制 Hystrix 的 @HystrixCommand 注解
网关 Spring Cloud Zuul
配置 Spring Cloud Config
服务跟踪 Spring Cloud Sleuth
数据流 Spring Cloud Stream
批量任务 Spring Cloud Task
消息总线 Spring Cloud Bus

1.4 Dubbo 的特点

  • 支持多种协议的服务发布,默认是 dubbo://,还可以支持 rest://、webservice://、thrift:// 等;
  • 支持多种不同的注册中心,如:Nacos、ZooKeeper、Redis,未来还将会支持 Consul、Eureka、Etcd 等;
  • 支持多种序列化技术,如:avro、fst、fastjson、hessian2、kryo 等;
  • 在服务治理方面的功能非常完善,如:集群容错、服务路由、负载均衡、服务降级、服务限流、服务监控、安全验证等;
  • 中文文档;

1.5 Dubbo 的 6 种容错模式容错模式

容错模式 模式名称 说明 适用场景
Failover Cluster 【默认】失败自动切换 当服务调用失败后,会切换到集群中的其他机器进行重试,默认重试次数为2,通过属性 retries=2 可以修改次数 通常用于读操作(查),因为事务型操作会带来数据重复问题
Failfast Cluster 快速失败 当服务调用失败后,立即报错,也就是只发起一次调用 通常用于一些幂等的写操作(增删改),比如新增数据;以避免在结果不确定的情况下导致数据重复插入的问题
Failsafe Cluster 失败安全 出现异常时,直接忽略异常 使用 Failover Cluster(retries="0"),应对(增删改)操作
Failback Cluster 失败后自动回复 服务调用出现异常时,在后台记录这条失败的请求定时重发 适合用于消息通知操作,保证这个请求一定发送成功
Forking Cluster 并行提交 并行调用集群中的多个服务,只要其中一个成功就返回。可以通过forks=2来设置最大并行数  
Broadcast Cluster 广播通知 广播调用所有的服务提供者,任意一个服务报错则表示服务调用失败 通常用于通知所有的服务提供者更新缓存或者本地资源信息
  • 可以自行扩展容错模式;
  • 配置也很简单,在 @Service 接口里添加一个 cluster 参数即可;
@Service(cluster = "failfast") //更改容错方式为快速失败
public class TestServiceImpl implements TestService {
	@Override
	public String test() {
	    ...
	}
}

1.6 Dubbo 的 4 种负载均衡策略

负载均衡策略 策略名称 说明
Random LoadBalance 随机算法 可以针对性能较好的服务器设置较大的权重值,权重值越大,随机的概率也会越大
RoundRobin LoadBalance 轮询 按照公约后的权重设置轮询比例
LeastActive LoadBalance 最少活跃调用 处理较慢的节点将会收到更少的请求
ConsistentHash LoadBalance 一致性Hash 相同参数的请求总是发送到同一个服务提供者
  • 可以基于 Dubbo 中的 SPI 机制来扩展负载均衡策略;
  • 配置也很简单,在 @Service 接口里添加一个 loadbalance 参数即可;
@Service(loadbalance = "roundrobin") //更改负载均衡策略为轮询
public class TestServiceImpl implements TestService {
	@Override
	public String test() {
	    ...
	}
}

1.7 主机绑定规则

  • 主机绑定表示的是 Dubbo 服务对外发布的 IP 地址,默认情况下 Dubbo 会按照以下顺序来查找并绑定主机 IP 地址:
    • 查找环境变量中 DUBBO_IP_TO_BIND 属性配置的 IP 地址;
    • 查找 dubbo.protocol.host 属性配置的 IP 地址,默认是空,如果没有配置或者IP地址不合法,则继续往下查找;
    • 通过 LocalHost.getHostAddress 获取本机 IP 地址,如果获取失败,则继续往下查找;
    • 如果配置了注册中心的地址,则使用 Socket 通信连接到注册中心的地址后,使用 for 循环通过 socket.getLocalAddress().getHostAddress() 扫描各个网卡获取网卡 IP 地址;
  • 获取的 IP 地址并不是写入注册中心的地址。默认情况下,写入注册中心的 IP 地址优先选择环境变量中 DUBBO_IP_TO_REGISTRY 属性配置的 IP 地址。在这个属性没有配置的情况下,才会选取前面获得的 IP 地址并写入注册中心;
  • 问题:使用默认的主机绑定规则,可能会存在获取的 P 地址不正确的情况;
    • 原因:Dubbo 检测本地 IP 地址的策略是先调用 LocalHost.getHostAddress,这个方法的原理是通过获取本机的 hostname 映射 IP 地址,如果它指向的是一个错误的 IP 地址,那么这个错误的地址将会作为服务发布的地址注册到 ZooKeeper 节点上;
    • 解决方案
      • 在 /etc/hosts 中配置机器名对应正确的 IP 地址映射;
      • 在环境变量中添加 DUBBO_IP_TO_BIND 或者 DUBBO_IP_TO_REGISTRY 属性,Value 值为绑定的主机地址;
      • 通过 dubbo.protocolhost 设置主机地址;

2. 构建 Dubbo 服务提供方

  • 同样,这里使用 Zookeeper,就需要先下载 Zookeeper 服务器

2.1 构建服务接口模块

  • Dubbo 官方推荐把服务接口打成 Jar 包发布到仓库上;
  • 这样服务消费者可以依赖该 Jar 包,通过接口调用方式完成远程通信。对于服务提供者来说,也需要依赖该 Jar 包完成接口的实现;
  • 做法如下:
  • 新建 spring-cloud-dubbo-sample-api 模块,添加 pom.xml 依赖文件;
<!-- Dubbo -->
<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo</artifactId>
    <version>${dubbo.version}</version>
</dependency>

在 service 包下新建接口:

public interface TestService {
	String test(String message);
}

执行 mvn install 命令将接口 jar 包安装到本地仓库;

2.2 添加 pom.xml 依赖文件

<!-- Spring Cloud 核心包-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter</artifactId>
</dependency>

<!-- Dubbo Spring Cloud Starter -->
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-dubbo</artifactId>
<!-- Sample API 接口声明-->
    <artifactId>spring-cloud-dubbo-sample-api</artifactId>
<!-- Spring Cloud Nacos Service Discovery -->
    <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>

2.3 修改 application.yml 配置文件

spring:
  application:
    name: spring-cloud-dubbo-provider
  cloud:
    zookeeper:
      discovery:
        register: true  #表示该服务要注册进注册中心
      connect-string: localhost:2181  #zookeeper 服务器位置
dubbo:     
  protocol:
    name: dubbo
    port: 20880

2.4 在主程序类上添加注解

  • @DubboComponentScan:扫描主程序类所在包及其子包下的所有注解,将 @Servicr 注解下类注册进容器里;

2.5 实现 2.1 定义的接口

@Service
public class TestServiceImpl implements TestService {
    @Value("${dubbo.application.name}")
    private String serviceName;
    
	@Override
	public String test(String message) {
		return serviceName;
	}
}
  • 可以在 @Service 注解里添加两个属性配置 clusterloadbalance,分别用来配置容错模式和负载均衡策略;
  • 详情请见本篇《1.5 Dubbo 的 6 种容错模式》和《1.6 Dubbo 的 4 种负载均衡策略》

3. 构建 Dubbo 服务消费方

3.1 添加 pom.xml 依赖文件同服务提供方;

<!-- Spring Cloud 核心包-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter</artifactId>
</dependency>

<!-- Dubbo Spring Cloud Starter -->
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-dubbo</artifactId>
<!-- Sample API 接口声明-->
    <artifactId>spring-cloud-dubbo-sample-api</artifactId>
<!-- Spring Cloud Nacos Service Discovery -->
    <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>

3.2 修改 application.yml 配置文件

spring:
  application:
    name: spring-cloud-dubbo-consumer
  cloud:
    zookeeper:
      discovery:
        register: false #表示该服务不要注册进注册中心
      connect-string: localhost:2181  
dubbo:     
  cloud:
    subscribed-services: spring-cloud-dubbo-provider  #表示服务调用者订阅的服务提供方的应用名称列表。默认值为“*”,不推荐使用默认值

3.3 修改业务类

在服务类中使用 @Reference 注解注入 TestService 即可;

@RestController
public class TestController{
    @Reference 
    private TestService testService;
    
    @GetMapping("/message")
    public String testController(){
        return testService.test("message");
}

4. 在消费者端使用 Mock 配置实现服务降级

  • 在本示例中将对 2.1 中定义的 TestService 接口配置服务降级策略;
  • 降级策略的配置都是在基于服务消费者之上的;

4.1 为接口实现一种服务降级方法

public class MockTestService implements TestService {
	@Override
	public String test(String message) {
		return "当前无法访问";
	}
}

4.2 给 @Reference 注解增加 mock 参数

@RestController
public class TestController{
    @Reference(mock = "com.dlhjw.springcloud.mock.MockTestService", cluster="failfast")
    private TestService testService;
    
    @GetMapping("/message")
    public String testController(){
        return testService.test("message");
}
  • 在 TestController 类中修改 @Reference 注解增加 mock 参数;
  • 其中设置了属性 cluster="failfast",因为默认的容错策略会发起两次重试,等待的时间较长;

5. Dubbo 使用 Zookeeper 作为注册中心(Spring Boot)

  • 这里仅使用到了 Spring Boot 的自动配置;
  • 有两种配置方式,一种是使用 .xml,另一种是使用 .yml;

5.1 下载 Zookeeper 服务器

5.2 引入 pom.xml 依赖文件服务提供者与服务消费者需要引入的依赖相同;

<!-- Zookeeper 相关依赖 -->
<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.5.3-beta</version>
</dependency>
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>4.0.1</version>
</dependency>
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>4.0.1</version>
</dependency>

<!-- Dubbo 相关依赖 -->
<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-spring-boot-starter</artifactId>
    <version>2.7.5</version>
</dependency>

<!-- Spring Boot 依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>

5.3 服务提供者

5.3.1 修改 application.yml 配置文件

spring:
  application:
    name: springboot-dubbo-demo 
dubbo:
  #服务提供方的信息
  application:
    name: springboot-provider      
  protocol:
    name: dubbo
    port: 20880
  registry:
    address: zookeeper://localhost:2181  #zookeeper地址
  #scan:
    #base-packages: com.dlhjw.dubbo.service.impl  #指定 Dubbo 服务实现类的扫描基准包,作用等同于 主程序类上的 @DubboComponentScan

5.3.2 在主程序类上添加注解

  • @DubboComponentScan:作用同 Spring Boot 的 @ComponentScan,不过这里要扫描 Dubbo 提供的 @Service 注解;
  • @DubboComponentScan(basePackages = "com.dlhjw.dubbo.service.impl")
  • 如果上面 application 中已经做了配置,这里可以不用添加;

5.3.3 编写业务类

创建接口及其实现类:

public interface TestService {
    void testDubbo();
}
@Service(version = "1.0.0",timeout = 3000)
public class TestServiceImpl implements TestService{
    @Override
    public void testDubbo() {
    }
}

注意:@Service 注解是 com.alibaba.dubbo.config.annotation.Service 包下的;

5.4 服务消费者

5.4.1 修改 application.yml 配置文件

dubbo:
  #服务消费方的信息
  application:
    name: springboot-consumer 
  registry:
    #zookeeper地址
    address: zookeeper://localhost:2181

5.4.2 在主程序类上添加注解

5.4.3 编写业务类

这里直接在 controller 接口里直接调用服务提供者提供的 TestService 即可;

@Reference(version = "1.0.0",timeout = 300)
private TestService testService;

@Reference 注解可以获得一个远程代理对象;

6. Dubbo 使用 Nacos 作为注册中心(Spring Boot)

  • 这里仅使用到了 Spring Boot 的自动配置;
  • 这里仅提供服务提供者的示例,服务消费者类似;

6.1 下载 Nacos 服务器

6.2 工程结构

  • 新建一个父工程 spring-cloud-nacos-sample,包含两个模块:nacos-sample-api 和 nacos-sample-provider;
  • 在 nacos-sample-api 中声明接口;
public interface IHelloService{
    String sayHello(String name);
}

6.3 引入 pom.xml 依赖文件

在 nacos-sample-provider 中添加依赖文件:

<!-- 接口定义类 -->
<dependency>
  <groupId>com.gupaoedu.book.nacos</groupId>
  <version>1.0-SNAPSHOT</version>
  <artifactId>nacos-sample-api</artifactId>
</dependency>
<!-- Nacos 的 starter 组件 -->
<dependency>
  <groupId>com.alibaba.boot</groupId>
  <artifactId>nacos-discovery-spring-boot-starter</artifactId>
  <version>0.2.4</version>
  <exclusions>
    <exclusion>
      <groupId>com.alibaba.spring</groupId>
      <artifactId>spring-context-support</artifactId>
    </exclusion>
  </exclusions>
</dependency>
<!-- Dubbo 的 starter 组件 -->
<dependency>
  <groupId>org.apache.dubbo</groupId>
  <artifactId>dubbo-spring-boot-starter</artifactId>
  <version>2.7.5</version>
</dependency>

6.4 修改 application.yml 配置文件

dubbo:
  application:
    name: spring-boot-dubbo-nacos-sample 
  registry:
    address: nacos://127.0.0.1:8848  #基于 Nacos 协议
  protocol: 
    name: dubbo
    port: 20880

6.5 在主程序类上添加注解

@DubboComponentScan:dubbo 的包扫描注解;

6.6 编写业务类实现

6.2 中定义的接口;

@Service 
public class HelloServiceImpl implements IHelloService{
    @Override 
    public String sayHello(String name){
        return "He1lo World:"+name;
    }

6.7 启动测试

启动服务,访问 Nacos 控制台,进入“服务管理” -> “服务列表”,可以看到所有注册在 Nacos 上的服务;

7. Dubbo 使用 Nacos 作为注册中心(Spring Cloud)

这里仅提供服务提供者的示例,服务消费者类似;

7.1 下载 Nacos 服务器

7.2 工程结构

  • 新建一个父工程 spring-cloud-nacos-sample,包含两个模块:spring-cloud-nacos-sample-api 和 spring-cloud-nacos-sample-provider;
  • 在 nacos-sample-api 中声明接口;
public interface IHelloService{
    String sayHello(String name);
}

7.3 添加 pom.xml 依赖

在父工程中显示声明依赖的指定版本;

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-dependencies</artifactId>
  <version>Greenwich.SR2</version>
  <type>pom</type>
  <scope>import</scope>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-dependencies</artifactId>
  <version>2.1.11.RELEASE</version>
  <type>pom</type>
  <scope>import</scope>
</dependency>
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-alibaba-dependencies</artifactId>
  <version>2.1.1.RELEASE</version>
  <type>pom</type>
  <scope>import</scope>
</dependency>

在 spring-cloud-nacos-sample-provider 中添加依赖文件:

<!-- Spring Cloud 核心包 -->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter</artifactId>
  <exclusions>
    <exclusion>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-context</artifactId>
    </exclusion>
  </exclusions>
</dependency>

<!-- Spring Cloud 的 Dubbo 依赖 -->
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-dubbo</artifactId>
<!-- api 模块 -->
  <groupId>com.gupaoedu.book.springcloud</groupId>
  <artifactId>spring-cloud-dubbo-sample-api</artifactId>
  <version>1.0-SNAPSHOT</version>
<!-- 基于 Nacos 的服务注册与发现 -->
  <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
  <artifactId>spring-cloud-context</artifactId>
  <version>2.1.1.RELEASE</version>

7.4 添加 application.yml 依赖文

件与 Spring Boot 这整合方式的主要区别就在 pom.xml 配置文件和 application.yml 依赖文件;

spring: 
  application: 
    name: spring-cloud-nacos-sample 
  cloud: 
    nacos: 
      discovery:
        server-addr: 127.0.0.1:8848  #Nacos 服务注册中心地址

dubbo: 
  scan: 
    base-packages: com.gupaoedu.book.nacos.bootstrap  #功能等同于 @DubboComponentScan   
  protocol: 
    name: dubbo
    port: 20880
  registry:
    address: spring-cloud://localhost  #将服务挂载到 Spring Cloud 注册中心

7.5 主程序类上无需额外注解

7.6 编写业务类实现

7.2 中定义的接口即可;

@Service 
public class HelloServiceImpl implements IHelloService{
    @Override 
    public String sayHello(String name){
        return "He1lo World:"+name;
    }
}

到此这篇关于使用 Apache Dubbo 实现远程通信(微服务架构)的文章就介绍到这了,更多相关Apache Dubbo 远程通信内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Servers 相关文章推荐
Nginx访问日志及错误日志参数说明
Mar 31 Servers
使用nginx配置访问wgcloud的方法
Jun 26 Servers
centos8安装nginx1.9.1的详细过程
Aug 02 Servers
nginx安装以及配置的详细过程记录
Sep 15 Servers
Nginx内网单机反向代理的实现
Nov 07 Servers
nginx从安装到配置详细说明(安装,安全配置,防盗链,动静分离,配置 HTTPS,性能优化)
Feb 12 Servers
Nginx+Windows搭建域名访问环境的操作方法
Mar 17 Servers
Nginx实现会话保持的两种方式
Mar 18 Servers
tomcat正常启动但网页却无法访问的几种解决方法
May 06 Servers
使用Nginx+Tomcat实现负载均衡的全过程
May 30 Servers
Linux在两个服务器直接传文件的操作方法
Aug 05 Servers
Zabbix6通过ODBC方式监控Oracle 19C的详细过程
Sep 23 Servers
Nginx 反向代理解决跨域问题多种情况分析
Jan 18 #Servers
详解nginx location指令
Jan 18 #Servers
图文详解nginx日志切割的实现
Jan 18 #Servers
Nginx防盗链与服务优化配置的全过程
Jan 18 #Servers
使用 Apache 反向代理的设置技巧
NGINX 权限控制文件预览和下载的实现原理
Nginx虚拟主机的搭建的实现步骤
Jan 18 #Servers
You might like
php email邮箱正则
2008/10/08 PHP
php中计算中文字符串长度、截取中文字符串的函数代码
2011/08/09 PHP
yii框架中的Url生产问题小结
2012/01/16 PHP
PHP调用JAVA的WebService简单实例
2014/03/11 PHP
php中in_array函数用法探究
2014/11/25 PHP
Smarty实现页面静态化(生成HTML)的方法
2016/05/23 PHP
PHP实现单条sql执行多个数据的insert语句方法
2019/10/11 PHP
Exitjs获取DataView中图片文件名
2009/11/26 Javascript
在javascript将NodeList作为Array数组处理的方法
2010/07/09 Javascript
js几秒以后倒计时跳转示例
2013/12/26 Javascript
jQuery性能优化的38个建议
2014/03/04 Javascript
JavaScript中数据结构与算法(五):经典KMP算法
2015/06/19 Javascript
js实现无限级树形导航列表效果代码
2015/09/23 Javascript
Jquery ajax 同步阻塞引起的UI线程阻塞问题
2015/11/17 Javascript
基于JavaScript判断浏览器到底是关闭还是刷新(超准确)
2016/02/01 Javascript
javascript self对象使用详解
2016/10/18 Javascript
JS实现一次性弹窗的方法【刷新后不弹出】
2016/12/26 Javascript
浅谈JavaScript异步编程
2017/01/20 Javascript
JavaScript封装的常用工具类库bee.js用法详解【经典类库】
2018/09/03 Javascript
Vue中watch、computed、updated三者的区别及用法
2020/07/27 Javascript
基于vue hash模式微信分享#号的解决
2020/09/07 Javascript
关于angular 8.1使用过程中的一些记录
2020/11/25 Javascript
在Python中画图(基于Jupyter notebook的魔法函数)
2019/10/28 Python
python实现大量图片重命名
2020/03/23 Python
pytorch的batch normalize使用详解
2020/01/15 Python
Bootstrap File Input文件上传组件
2020/12/01 HTML / CSS
世界上最具创新性的增强型知名运动品牌:Proviz
2018/04/03 全球购物
实习销售业务员自我鉴定
2013/09/21 职场文书
升职自荐信
2013/11/28 职场文书
《挑山工》的教学反思
2014/02/16 职场文书
学校三节实施方案
2014/06/09 职场文书
幼儿园2014年度工作总结
2014/11/10 职场文书
婚礼答谢礼品
2015/01/20 职场文书
恋恋笔记本观后感
2015/06/16 职场文书
2015中学政教处工作总结
2015/07/22 职场文书
创新创业项目计划书该怎样写?
2019/08/13 职场文书