使用 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进程管理和重载原理详解
Apr 22 Servers
nginx作grpc的反向代理踩坑总结
Jul 07 Servers
CentOS7安装GlusterFS集群以及相关配置
Apr 12 Servers
idea下配置tomcat避坑详解
Apr 12 Servers
Tomcat执行startup.bat出现闪退的原因及解决办法
Apr 20 Servers
nginx日志格式分析和修改
Apr 28 Servers
如何开启Apache,Nginx和IIS服务器的GZIP压缩功能
Apr 29 Servers
使用Nginx的访问日志统计PV与UV
May 06 Servers
Windows Server 2012 R2服务器安装与配置的完整步骤
Jul 15 Servers
ubuntu端向日葵键盘输入卡顿问题及解决
Dec 24 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 中英文混合排版中处理字符串常用的函数
2007/04/12 PHP
php版微信公众平台之微信网页登陆授权示例
2016/09/23 PHP
php中给js数组赋值方法
2014/03/10 Javascript
Nodejs使用mysql模块之获得更新和删除影响的行数的方法
2014/03/18 NodeJs
JavaScript strike方法入门实例(给字符串加上删除线)
2014/10/17 Javascript
jQuery实现简单下拉导航效果
2015/09/07 Javascript
JS简单编号生成器实现方法(附demo源码下载)
2016/04/05 Javascript
BootStrap入门教程(二)之固定的内置样式
2016/09/19 Javascript
什么是JavaScript中的结果值?
2016/10/08 Javascript
Require.js的基本用法详解
2017/07/03 Javascript
vue实现选项卡及选项卡切换效果
2018/04/24 Javascript
vue.js循环radio的实例
2019/11/07 Javascript
在Vue项目中使用Typescript的实现
2019/12/19 Javascript
JavaScript组合模式---引入案例分析
2020/05/23 Javascript
windows下安装python paramiko模块的代码
2013/02/10 Python
利用Python中的mock库对Python代码进行模拟测试
2015/04/16 Python
Python中输出ASCII大文字、艺术字、字符字小技巧
2015/04/28 Python
python3+PyQt5使用数据库表视图
2018/04/24 Python
python实现nao机器人身体躯干和腿部动作操作
2019/04/29 Python
python GUI图形化编程wxpython的使用
2019/07/19 Python
详解Python用三种方式统计词频的方法
2019/07/29 Python
Django ORM 常用字段与不常用字段汇总
2019/08/09 Python
Python学习笔记之字符串和字符串方法实例详解
2019/08/22 Python
Python如何在DataFrame增加数值
2020/02/14 Python
python识别验证码图片实例详解
2020/02/17 Python
Python Selenium XPath根据文本内容查找元素的方法
2020/12/07 Python
美国知名女性服饰品牌:New York & Company
2017/03/23 全球购物
酒店总经理欢迎词
2014/01/15 职场文书
思想品德自我评价
2014/02/04 职场文书
五一手机促销方案
2014/03/08 职场文书
减负增效提质方案
2014/05/23 职场文书
迎国庆演讲稿
2014/09/15 职场文书
化验员岗位职责
2015/02/14 职场文书
《雷雨》教学反思
2016/02/20 职场文书
OpenCV-Python实现轮廓拟合
2021/06/08 Python
MyBatis核心源码深度剖析SQL语句执行过程
2022/05/20 Java/Android