Spring Cloud 系列之 Dubbo RPC 通信
Dubbo 介绍
官网:http://dubbo.apache.org/zh-cn/
Github:https://github.com/apache/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
:依赖服务接口,远程调用服务,服务消费者
依赖关系
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 协议 更多协议信息请参考:http://dubbo.apache.org/zh-cn/docs/user/references/protocol/introduction.html
dubbo:service
:声明需要暴露的服务接口dubbo:reference
:配置订阅的服务(生成远程服务代理)
更多配置信息请参考:http://dubbo.apache.org/zh-cn/docs/user/references/xml/introduction.html
注册中心
注册中心我们已经学习了不少,例如: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 官网:https://nacos.io/zh-cn/
Github:https://github.com/alibaba/nacos
预备工作
当您将 Nacos 整合到您的 Dubbo 工程之前,请确保后台已经启动 Nacos 服务。关于 Nacos 的安装和其他详细内容可参考我之前的文章 Spring Cloud 系列之 Alibaba Nacos 注册中心(一)、Spring Cloud 系列之 Alibaba 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
模块中定义实体类和服务接口信息。
实体类
Product.java
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;
}
Order.java
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)对服务动态的指定权重,官方文档:http://dubbo.apache.org/zh-cn/docs/admin/introduction.html
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 通信所有的知识点就讲解结束了。
本文采用 知识共享「署名-非商业性使用-禁止演绎 4.0 国际」许可协议
。
大家可以通过 分类
查看更多关于 Spring Cloud
的文章。
Spring Cloud 系列之 Dubbo RPC 通信的更多相关文章
- spring cloud系列教程第四篇-Eureka基础知识
通过前三篇文章学习,我们搭建好了两个微服务工程.即:order80和payment8001这两个服务.有了这两个基础的框架之后,我们将要开始往里面添加东西了.还记得分布式架构的几个维度吗?我们要通过一 ...
- Spring Cloud系列(二) 介绍
Spring Cloud系列(一) 介绍 Spring Cloud是基于Spring Boot实现的微服务架构开发工具.它为微服务架构中涉及的配置管理.服务治理.断路器.智能路由.微代理.控制总线.全 ...
- Spring Cloud 系列之 Spring Cloud Stream
Spring Cloud Stream 是消息中间件组件,它集成了 kafka 和 rabbitmq .本篇文章以 Rabbit MQ 为消息中间件系统为基础,介绍 Spring Cloud Stre ...
- Spring Cloud 系列之 Consul 注册中心(二)
本篇文章为系列文章,未读第一集的同学请猛戳这里:Spring Cloud 系列之 Consul 注册中心(一) 本篇文章讲解 Consul 集群环境的搭建. Consul 集群 上图是一个简单的 Co ...
- spring cloud系列教程第一篇-介绍
spring cloud系列教程第一篇-介绍 前言: 现在Java招聘中最常见的是会微服务开发,微服务已经在国内火了几年了,而且也成了趋势了.那么,微服务只是指spring boot吗?当然不是了,微 ...
- spring cloud系列教程第六篇-Eureka集群版
spring cloud系列教程第六篇-Eureka集群版 本文主要内容: 本文来源:本文由凯哥Java(kaigejava)发布在博客园博客的.转载请注明 1:Eureka执行步骤理解 2:集群原理 ...
- Spring Cloud系列教程第九篇-Eureka自我保护机制
Spring Cloud系列教程第九篇-Eureka自我保护机制 本文主要内容: 1:自我保护介绍 2:导致原因分析 3:怎么禁止自我保护 本文是由凯哥(凯哥Java:kagejava)发布的< ...
- Spring Cloud系列文,Feign整合Ribbon和Hysrix
在本博客之前的Spring Cloud系列里,我们讲述了Feign的基本用法,这里我们将讲述下Feign整合Ribbon实现负载均衡以及整合Hystrix实现断路保护效果的方式. 1 准备Eureka ...
- Spring Cloud 系列之 Gateway 服务网关(二)
本篇文章为系列文章,未读第一集的同学请猛戳这里:Spring Cloud 系列之 Gateway 服务网关(一) 本篇文章讲解 Gateway 网关的多种路由规则.动态路由规则(配合服务发现的路由规则 ...
随机推荐
- Istio Sidecar
概念及示例 Sidecar描述了sidecar代理的配置.默认情况下,Istio 让每个 Envoy 代理都可以访问来自和它关联的工作负载的所有端口的请求,然后转发到对应的工作负载.您可以使用 sid ...
- 解决ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO) 这种问题需要强行重新修改密码,方法 ...
- Fragment简介及使用
概述 Fragment是 Android 3.0(API 11)引入的一种设计,用于大屏幕的设备. Fragment依托于Activity,受宿主Activity生命周期的影响.但它也有自己的生命周期 ...
- Sniffer截包工具的使用
Sniffer软件的安装 sniffer需要在xp或者win2003环境下才能正常运行,如果没有这两个系统,可以安装虚拟机,在虚拟机上使用sniffer.如果没有这两个系统就会出现找不到网卡或者打不开 ...
- 【题解】P6218 [USACO06NOV] Round Numbers S
题目传送门 这是一道数位DP. 令 \(dp_{i,j,k}\) 为满足由 \(i\) 位组成,且其中有 \(j\) 个1,第 i 位(从右往左数)为 \(k\) 的二进制数的数量. 可以得出状态转移 ...
- css 图片宽度、居中、倒影
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- RocketMQ系列(一)基本概念
RocketMQ是阿里出品的一款开源的消息中间件,让其声名大噪的就是它的事务消息的功能.在企业中,消息中间件选择使用RocketMQ的还是挺多的,这一系列的文章都是针对RocketMQ的,咱们先从Ro ...
- Java实现 LeetCode 773 滑动谜题(BFS)
773. 滑动谜题 在一个 2 x 3 的板上(board)有 5 块砖瓦,用数字 1~5 来表示, 以及一块空缺用 0 来表示. 一次移动定义为选择 0 与一个相邻的数字(上下左右)进行交换. 最终 ...
- Java实现 蓝桥杯 算法提高 矩阵乘法(暴力)
试题 算法提高 矩阵乘法 问题描述 小明最近刚刚学习了矩阵乘法,但是他计算的速度太慢,于是他希望你能帮他写一个矩阵乘法的运算器. 输入格式 输入的第一行包含三个正整数N,M,K,表示一个NM的矩阵乘以 ...
- Java 第十一届 蓝桥杯 省模拟赛十六进制转换成十进制
问题描述 请问十六进制数1949对应的十进制数是多少?请特别注意给定的是十六进制,求的是十进制. 答案提交 这是一道结果填空的题,你只需要算出结果后提交即可.本题的结果为一个整数,在提交答案时只填写这 ...