DubboRPC通信
Dubbo 介绍2018 年 2 月 15 日,阿里巴巴的服务治理框架 dubbo 通过投票,顺利成为 Apache 基金会孵化项目。Apache Dubbo 是一款高性能、轻量级的开源 Java RPC 框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。Dubbo 架构Dubbo 提供三个核心功能:基于接口的远程调用、容错和负载均衡,以及服务的自动注
Dubbo 介绍
2018 年 2 月 15 日,阿里巴巴的服务治理框架 dubbo 通过投票,顺利成为 Apache 基金会孵化项目。
Apache Dubbo 是一款高性能、轻量级的开源 Java RPC 框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
Dubbo 架构
Dubbo 提供三个核心功能:基于接口的远程调用、容错和负载均衡,以及服务的自动注册与发现。Dubbo 框架广泛的在阿里巴巴内部使用,以及当当、去哪儿、网易考拉、滴滴等都在使用。
节点角色说明
节点 | 角色说明 |
---|---|
Provider | 暴露服务的服务提供方 |
Consumer | 调用远程服务的服务消费方 |
Registry | 服务注册与发现的注册中心 |
Monitor | 统计服务的调用次数和调用时间的监控中心 |
Container | 服务运行容器 |
调用关系说明
- 服务容器负责启动,加载,运行服务提供者。
- 服务提供者在启动时,向注册中心注册自己提供的服务。
- 服务消费者在启动时,向注册中心订阅自己所需的服务。
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
Dubbo 快速入门
我们先通过一个简单的案例让大家理解一下 Dubbo 的使用,然后基于 Spring Boot 和 Spring Cloud 环境整合 Dubbo。
Dubbo 采用全 Spring 配置方式,透明化接入应用,对应用没有任何 API 侵入,只需用 Spring 加载 Dubbo 的配置即可。
依赖
JDK 1.6 以上和 Maven 3.0 以上,采用 Maven 多模块聚合工程构建 api 模块,provider 模块以及 consumer 模块。
聚合工程
项目结构如下图,简单介绍一下:
dubbo-api
:服务接口dubbo-provider
:依赖服务接口,具体的业务实现,服务提供者dubbo-coonsumer
:依赖服务接口,远程调用服务,服务消费者
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v8VaFKLD-1626229842283)(DubboRPC通信.assets/image-20200614114932671.png)]
依赖关系
dubbo-parent 的 pom.xml 依赖 apache dubbo。
<dependencies>
<!-- apache dubbo 依赖 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.7</version>
</dependency>
</dependencies>
dubbo-provider 和 dubbo-consumer 的 pom.xml 依赖 dubbo-api 服务接口。
<dependencies>
<!-- dubbo-api 依赖 -->
<dependency>
<groupId>org.example</groupId>
<artifactId>dubbo-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
定义服务接口
dubbo-api 中编写 HelloService.java
package org.example.service;
/**
* Hello服务
*/
public interface HelloService {
String sayHello(String name);
}
定义服务提供者
在 provider 模块中实现服务接口
dubbo-provider 中编写 HelloServiceImpl.java
package org.example.service.impl;
import org.example.service.HelloService;
/**
* 服务实现
*/
public class HelloServiceImpl implements HelloService {
public String sayHello(String name) {
return "hello " + name;
}
}
配置服务提供者
dubbo-provider.xml
<?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-4.3.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- 提供方应用信息,用于计算依赖关系 -->
<dubbo:application name="hello-world-app"/>
<!-- 使用 multicast 广播注册中心暴露服务地址 -->
<dubbo:registry address="multicast://224.5.6.7:1234"/>
<!-- 用 dubbo 协议在 20880 端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20880"/>
<!-- 声明需要暴露的服务接口 -->
<dubbo:service interface="org.example.service.HelloService" ref="helloService"/>
<!-- 和本地 bean 一样实现服务 -->
<bean id="helloService" class="org.example.service.impl.HelloServiceImpl"/>
</beans>
加载 Spring 配置启动服务
package org.example;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 发布服务
*/
public class Provider {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:dubbo-provider.xml");
context.start();
System.out.println("服务注册成功!");
System.in.read(); // 按任意键退出
}
}
定义服务消费者
通过 Spring 配置引用远程服务
dubbo-consumer.xml
<?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-4.3.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
<dubbo:application name="consumer-of-helloworld-app" />
<!-- 使用 multicast 广播注册中心暴露发现服务地址 -->
<dubbo:registry address="multicast://224.5.6.7:1234" />
<!-- 生成远程服务代理,可以和本地 bean 一样使用 helloService -->
<dubbo:reference id="helloService" interface="org.example.service.HelloService" />
</beans>
加载 Spring 配置并调用远程服务
package org.example;
import org.example.service.HelloService;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 调用远程服务
*/
public class Consumer {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:dubbo-consumer.xml");
context.start();
HelloService helloService = (HelloService) context.getBean("helloService"); // 获取远程服务代理
String result = helloService.sayHello("world"); // 执行远程方法
System.out.println(result); // 显示调用结果
}
}
Dubbo 常用标签
dubbo:application
:应用程序名称dubbo:registry
:连接注册中心信息(配置注册中心)dubbo:protocol
:服务提供者注册服务采用的协议- Dubbo 协议,默认
- RMI 协议
- Hessian 协议
- HTTP 协议
- WebService 协议
- Thrift 协议
- Memcached 协议
- Redis 协议
- Rest 协议(RESTful)
- Grpc 协议
dubbo:service
:声明需要暴露的服务接口dubbo:reference
:配置订阅的服务(生成远程服务代理)
注册中心
注册中心我们已经学习了不少,例如:ZooKeeper、Eureka、Consul、Nacos 等等,注册中心可以更高效的管理系统的服务:比如服务接口的发布、自动剔除无效的服务、自动恢复服务等。
Dubbo 支持五种注册中心:Multicast、Nacos(推荐)、ZooKeeper(推荐) 、Redis、Simple。本文重点介绍前两个,更多注册中心的信息请参考:http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html
Multicast 注册中心
Multicast 注册中心不需要启动任何中心节点,只要广播地址一样,就可以互相发现。
- 提供方启动时广播自己的地址
- 消费方启动时广播订阅请求
- 提供方收到订阅请求时,单播自己的地址给订阅者,如果设置了
unicast=false
,则广播给订阅者 - 消费方收到提供方地址时,连接该地址进行 RPC 调用。
组播受网络结构限制,只适合小规模应用或开发阶段使用。组播地址段: 224.0.0.0 - 239.255.255.255
配置
<dubbo:registry address="multicast://224.5.6.7:1234" />
或
<dubbo:registry protocol="multicast" address="224.5.6.7:1234" />
为了减少广播量,Dubbo 缺省使用单播发送提供者地址信息给消费者,如果一个机器上同时启了多个消费者进程,消费者需声明 unicast=false
,否则只会有一个消费者能收到消息。
当服务者和消费者运行在同一台机器上,消费者同样需要声明unicast=false
,否则消费者无法收到消息,导致 No provider available for the service 异常。
<dubbo:registry address="multicast://224.5.6.7:1234?unicast=false" />
或
<dubbo:registry protocol="multicast" address="224.5.6.7:1234">
<dubbo:parameter key="unicast" value="false" />
</dubbo:registry>
zookeeper 注册中心
Zookeeper 是 Apache Hadoop 的子项目,是一个树型的目录服务,支持变更推送,适合作为 Dubbo 服务的注册中心,工业强度较高,可用于生产环境,推荐使用。
流程说明:
- 服务提供者启动时: 向
/dubbo/com.foo.BarService/providers
目录下写入自己的 URL 地址。 - 服务消费者启动时: 订阅
/dubbo/com.foo.BarService/providers
目录下的提供者 URL 地址。并向/dubbo/com.foo.BarService/consumers
目录下写入自己的 URL 地址。 - 监控中心启动时: 订阅
/dubbo/com.foo.BarService
目录下的所有提供者和消费者 URL 地址。
支持以下功能:
- 当提供者出现断电等异常停机时,注册中心能自动删除提供者信息;
- 当注册中心重启时,能自动恢复注册数据,以及订阅请求;
- 当会话过期时,能自动恢复注册数据,以及订阅请求;
- 当设置
<dubbo:registry check="false" />
时,记录失败注册和订阅请求,后台定时重试; - 可通过
<dubbo:registry username="admin" password="1234" />
设置 zookeeper 登录信息; - 可通过
<dubbo:registry group="dubbo" />
设置 zookeeper 的根节点,不配置将使用默认的根节点; - 支持
*
号通配符<dubbo:reference group="*" version="*" />
,可订阅服务的所有分组和所有版本的提供者。
作为 Dubbo 的老牌黄金搭档 ZooKeeper,我们在单独讲解 Dubbo 时已经给大家分享过如何使用了,本文系 Spring Cloud Alibaba 系列文章,重点对象是 Nacos,所以 ZooKeeper 这里就不过多赘述了。
Nacos 注册中心
Nacos 是 Alibaba 公司推出的开源工具,用于实现分布式系统的服务发现与配置管理。Nacos 是 Dubbo 生态系统中重要的注册中心实现。
预备工作
当您将 Nacos 整合到您的 Dubbo 工程之前,请确保后台已经启动 Nacos 服务。
快速上手
Dubbo 融合 Nacos 成为注册中心的操作步骤非常简单,大致步骤可分为“增加 Maven 依赖”和“配置注册中心“。
依赖
核心依赖主要是 dubbo-registry-nacos
和 nacos-client
。
<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-registry-nacos -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>2.7.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.nacos/nacos-client -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>1.3.0</version>
</dependency>
配置注册中心
服务提供者和服务消费者只需要调整 address
属性配置即可。
单机配置:
<!-- 使用 Nacos 注册中心,单机版 -->
<dubbo:registry address="nacos://127.0.0.1:8848"/>
<!-- 或 -->
<dubbo:registry protocol="nacos" address="127.0.0.1:2181"/>
集群配置:
<!-- 使用 Nacos 注册中心,集群版 -->
<dubbo:registry address="nacos://192.168.10.101:2181?backup=192.168.10.102:2181,192.168.10.103:2181"/>
<!-- 或 -->
<dubbo:registry protocol="nacos" address="192.168.10.101:2181,192.168.10.102:2181,192.168.10.103:2181"/>
随后,重启您的 Dubbo 应用,Dubbo 的服务提供和消费信息在 Nacos 控制台中即可显示。
Spring Cloud Alibaba Nacos 整合 Dubbo
之前的文章中,无论我们学习 Eureka、Consul 还是 Nacos,负责服务间通信的功能都是由 Ribbon 来完成的,接下来我们使用 Dubbo 来替换 Ribbon。
聚合工程
dubbo-demo
聚合工程。SpringBoot 2.3.0.RELEASE
、Spring Cloud Hoxton.SR5
。
项目结构如下图,简单介绍一下:
service-api
:服务接口product-service
:商品服务,服务提供者,提供了/product/list
接口order-service
:订单服务,服务消费者,远程调用商品服务
依赖关系
dubbo-demo 的 pom.xml。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 项目坐标地址 -->
<groupId>com.example</groupId>
<!-- 项目模块名称 -->
<artifactId>dubbo-demo</artifactId>
<packaging>pom</packaging>
<!-- 项目版本名称 快照版本SNAPSHOT、正式版本RELEASE -->
<version>1.0-SNAPSHOT</version>
<modules>
<module>service-api</module>
<module>product-service</module>
<module>order-service</module>
</modules>
<!-- 继承 spring-boot-starter-parent 依赖 -->
<!-- 使用继承方式,实现复用,符合继承的都可以被使用 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
</parent>
<!--
集中定义依赖组件版本号,但不引入,
在子工程中用到声明的依赖时,可以不加依赖的版本号,
这样可以统一管理工程中用到的依赖版本
-->
<properties>
<!-- Spring Cloud Hoxton.SR5 依赖 -->
<spring-cloud.version>Hoxton.SR5</spring-cloud.version>
<!-- spring cloud alibaba 依赖 -->
<spring-cloud-alibaba.version>2.1.0.RELEASE</spring-cloud-alibaba.version>
</properties>
<!-- 项目依赖管理 父项目只是声明依赖,子项目需要写明需要的依赖(可以省略版本信息) -->
<dependencyManagement>
<dependencies>
<!-- spring cloud 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- spring cloud alibaba 依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
service-api 的 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>dubbo-demo</artifactId>
<groupId>com.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>service-api</artifactId>
<dependencies>
<!-- lombok 依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
product-service 需要依赖 Nacos 和 Dubbo 的依赖,还有 service-api 的依赖,完整依赖如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!-- 继承父依赖 -->
<parent>
<artifactId>dubbo-demo</artifactId>
<groupId>com.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>product-service</artifactId>
<!-- 项目依赖 -->
<dependencies>
<!-- spring cloud alibaba nacos discovery 依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- spring cloud alibaba dubbo 依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dubbo</artifactId>
</dependency>
<!-- spring boot web 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- service-api 依赖 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>service-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- spring boot test 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
order-service 需要依赖 Nacos 和 Dubbo 的依赖,还有 service-api 的依赖,完整依赖如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!-- 继承父依赖 -->
<parent>
<artifactId>dubbo-demo</artifactId>
<groupId>com.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>order-service</artifactId>
<!-- 项目依赖 -->
<dependencies>
<!-- spring cloud alibaba nacos discovery 依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- spring cloud alibaba dubbo 依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dubbo</artifactId>
</dependency>
<!-- spring boot web 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- service-api 依赖 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>service-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- spring boot test 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
定义服务接口
我们在 service-api
模块中定义实体类和服务接口信息。
实体类
package com.example.product.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product implements Serializable {
private Integer id;
private String productName;
private Integer productNum;
private Double productPrice;
}
package com.example.product.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Order implements Serializable {
private Integer id;
private String orderNo;
private String orderAddress;
private Double totalPrice;
private List<Product> productList;
}
服务接口
package com.example.product.service;
import com.example.product.pojo.Product;
import java.util.List;
/**
* 商品服务
*/
public interface ProductService {
/**
* 查询商品列表
*
* @return
*/
List<Product> selectProductList();
}
定义服务提供者
配置文件
配置文件需要配置 Nacos 注册中心和 Dubbo 相关信息,核心配置如下:
server:
port: 7070 # 端口
spring:
application:
name: product-service # 应用名称
# 配置 Nacos 注册中心
cloud:
nacos:
discovery:
enabled: true # 如果不想使用 Nacos 进行服务注册和发现,设置为 false 即可
server-addr: 127.0.0.1:8848 # Nacos 服务器地址,单机版
# Dubbo
dubbo:
# 提供方应用信息,用于计算依赖关系
application:
name: product-service
# 使用 nacos 注册中心暴露服务地址
registry:
protocol: nacos
address: spring-cloud://localhost
# 用 dubbo 协议在 20880 端口暴露服务
protocol:
name: dubbo
port: 20880
# 扫描需要暴露的服务,可以被 @EnableDubbo 注解替代
#scan:
# base-packages: com.example.service
服务提供者
product-service 的 ProductServiceImpl.java
package com.example.service.impl;
import com.example.product.pojo.Product;
import com.example.product.service.ProductService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Service;
import java.util.Arrays;
import java.util.List;
/**
* 商品服务
* timeout 调用该服务的超时时间
* version 为版本号
* group 为分组
* interface、group、version 三者确定一个服务
*/
@Slf4j
@Service(timeout = 5000, version = "1.0", group = "product-service")
public class ProductServiceImpl implements ProductService {
/**
* 查询商品列表
*
* @return
*/
@Override
public List<Product> selectProductList() {
log.info("商品服务查询商品信息...");
return Arrays.asList(
new Product(1, "华为手机", 1, 5800D),
new Product(2, "联想笔记本", 1, 6888D),
new Product(3, "小米平板", 5, 2020D)
);
}
}
值得注意的是 @Service
注解不是 Spring 的注解而是 Dubbo
的注释:
启动类
启动类通过 @EnableDubbo
注解扫描需要暴露的服务,如果配置文件中配置了该选项,那么这里可以省略。
package com.example;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
// 扫描需要暴露的服务
@EnableDubbo(scanBasePackages = "com.example.service")
// 开启 @EnableDiscoveryClient 注解,当前版本默认会开启该注解
//@EnableDiscoveryClient
@SpringBootApplication
public class ProductServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ProductServiceApplication.class, args);
}
}
定义服务消费者
配置文件
配置文件需要配置 Nacos 注册中心和 Dubbo 相关信息,核心配置如下:
server:
port: 9090 # 端口
spring:
application:
name: order-service # 应用名称
# 配置 Nacos 注册中心
cloud:
nacos:
discovery:
enabled: true # 如果不想使用 Nacos 进行服务注册和发现,设置为 false 即可
server-addr: 127.0.0.1:8848 # Nacos 服务器地址,单机版
# Dubbo
dubbo:
# 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样
application:
name: order-service
# 发现 nacos 注册中心暴露的服务
registry:
protocol: nacos
address: spring-cloud://localhost
cloud:
subscribed-services: product-service # 订阅服务,远程调用的服务名称
服务消费者
order-service 的 OrderServiceImpl.java
package com.example.service.impl;
import com.example.product.pojo.Order;
import com.example.product.service.ProductService;
import com.example.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
// dubbo 提供了 @Reference 注解,可替换 @Autowired 注解,用于引入远程服务
// 如果注册服务时设置了版本及分组信息,调用远程服务时也要设置对应的版本及分组信息
@Reference(timeout = 5000, version = "1.0", group = "product-service")
private ProductService productService;
/**
* 根据主键查询订单
*
* @param id
* @return
*/
@Override
public Order selectOrderById(Integer id) {
log.info("订单服务查询订单信息...");
return new Order(id, "order-001", "中国", 22788D,
productService.selectProductList());
}
}
启动类
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
// 开启 @EnableDiscoveryClient 注解,当前版本默认会开启该注解
//@EnableDiscoveryClient
@SpringBootApplication
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
测试
先启动 Nacos 服务器,然后启动服务提供者 product-service,访问:http://localhost:8848/nacos/ 控制台显示如下:
然后启动服务消费者,控制台显示如下:
订单服务调用远程商品服务,结果如下:
Dubbo 负载均衡
在集群负载均衡时,Dubbo 提供了多种均衡策略,缺省为 random
随机调用,也可以自行扩展负载均衡策略。
负载均衡策略
Random LoadBalance
- 随机,按权重设置随机概率。
- 在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
RoundRobin LoadBalance
- 轮询,按公约后的权重设置轮询比率。
- 存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
LeastActive LoadBalance
- 最少活跃调用数,ping 值(延迟低)的调用,相同延迟的情况下随机。
- 使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
ConsistentHash LoadBalance
- 一致性 Hash,相同参数的请求总是发到同一提供者。
- 当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
- 算法参见:http://en.wikipedia.org/wiki/Consistent_hashing
- 缺省只对第一个参数 Hash,如果要修改,请配置
<dubbo:parameter key="hash.arguments" value="0,1" />
- 缺省用 160 份虚拟节点,如果要修改,请配置
<dubbo:parameter key="hash.nodes" value="320" />
配置
一般在项目中不会在代码层面指定权重,而是通过监控中心(dubbo-admin)对服务动态的指定权重,
xml
服务端服务级别
<dubbo:service interface="..." loadbalance="roundrobin" weight="100" />
客户端服务级别
<dubbo:reference interface="..." loadbalance="roundrobin" />
服务端方法级别
<dubbo:service interface="..." weight="100">
<dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:service>
客户端方法级别
<dubbo:reference interface="...">
<dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:reference>
yaml
dubbo:
provider:
loadbalance: roundrobin
weight: 100
consumer:
loadbalance: roundrobin
注解
@Service(loadbalance = "roundrobin", weight = 100)
@Reference(loadbalance = "roundrobin")
至此 Dubbo RPC 通信所有的知识点就讲解结束了。
stent_hashing
- 缺省只对第一个参数 Hash,如果要修改,请配置
<dubbo:parameter key="hash.arguments" value="0,1" />
- 缺省用 160 份虚拟节点,如果要修改,请配置
<dubbo:parameter key="hash.nodes" value="320" />
配置
一般在项目中不会在代码层面指定权重,而是通过监控中心(dubbo-admin)对服务动态的指定权重
xml
服务端服务级别
<dubbo:service interface="..." loadbalance="roundrobin" weight="100" />
客户端服务级别
<dubbo:reference interface="..." loadbalance="roundrobin" />
服务端方法级别
<dubbo:service interface="..." weight="100">
<dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:service>
客户端方法级别
<dubbo:reference interface="...">
<dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:reference>
yaml
dubbo:
provider:
loadbalance: roundrobin
weight: 100
consumer:
loadbalance: roundrobin
注解
@Service(loadbalance = "roundrobin", weight = 100)
@Reference(loadbalance = "roundrobin")
至此 Dubbo RPC 通信所有的知识点就讲解结束了。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)