使用 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 location优先级的深入讲解
Mar 31 Servers
Nginx配置Https安全认证的实现
May 26 Servers
Nginx四层负载均衡的配置指南
Jun 11 Servers
Nginx内网单机反向代理的实现
Nov 07 Servers
Nginx的gzip相关介绍
May 11 Servers
nginx设置资源请求目录的方式详解
May 30 Servers
Linux下搭建SFTP服务器的命令详解
Jun 25 Servers
Windows10安装Apache2.4的方法步骤
Jun 25 Servers
使用 DataAnt 监控 Apache APISIX的原理解析
Jul 07 Servers
详解apache编译安装httpd-2.4.54及三种风格的init程序特点和区别
Jul 15 Servers
阿里云服务器(windows)手动部署FTP站点详细教程
Aug 05 Servers
Win10系统搭建ftp文件服务器详细教程
Aug 05 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 在文件指定行插入数据的代码
2010/05/08 PHP
PHP异步调用socket实现代码
2012/01/12 PHP
解析php时间戳与日期的转换
2013/06/06 PHP
深入php socket的讲解与实例分析
2013/06/13 PHP
php获取文章上一页与下一页的方法
2014/12/01 PHP
推荐一本PHP程序猿都应该拜读的书
2014/12/31 PHP
php实现微信企业号支付个人的方法详解
2017/07/26 PHP
php实现微信支付之现金红包
2018/05/30 PHP
再论Javascript的类继承
2011/03/05 Javascript
js判断上传文件的类型和大小示例代码
2013/10/18 Javascript
addEventListener 的用法示例介绍
2014/05/07 Javascript
JS实现网页背景颜色与select框中颜色同时变化的方法
2015/02/27 Javascript
怎么通过onclick事件获取js函数返回值(代码少)
2015/07/28 Javascript
全面解析Bootstrap中scrollspy(滚动监听)的使用方法
2016/06/06 Javascript
AngularJS入门教程之 XMLHttpRequest实例讲解
2016/07/27 Javascript
Bootstrap基本插件学习笔记之Tooltip提示工具(18)
2016/12/08 Javascript
解析NodeJs的调试方法
2016/12/11 NodeJs
Vue中使用 setTimeout() setInterval()函数的问题
2018/09/13 Javascript
微信小程序 setData 对 data数据影响问题
2019/04/18 Javascript
Python中使用logging模块打印log日志详解
2015/04/05 Python
Python处理字符串之isspace()方法的使用
2015/05/19 Python
python Flask 装饰器顺序问题解决
2018/08/08 Python
Python的argparse库使用详解
2018/10/09 Python
Python爬虫实现验证码登录代码实例
2019/05/10 Python
python 19个值得学习的编程技巧
2020/08/15 Python
CSS3实现超酷的黑猫警长首页
2016/04/26 HTML / CSS
CSS 说明横向进度条最后显示文字的实现代码
2020/11/10 HTML / CSS
HTML5网页录音和上传到服务器支持PC、Android,支持IOS微信功能
2019/04/26 HTML / CSS
美国韩国化妆品和护肤品购物网站:Beautytap
2018/07/29 全球购物
介绍一下JNDI的基本概念
2013/07/26 面试题
书法大赛策划方案
2014/06/04 职场文书
个人授权委托书
2014/09/15 职场文书
2014年小学数学教师工作总结
2014/12/03 职场文书
2015年父亲节寄语
2015/03/23 职场文书
MySQL 使用自定义变量进行查询优化
2021/05/14 MySQL
python多次执行绘制条形图
2022/04/20 Python