目录
SpringCloud Alibaba

【注】一切模块均以maven 项目创建
- 父依赖
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.vinjcent</groupId>
<artifactId>springcloud</artifactId>
<packaging>pom</packaging>
<version>0.0.1-SNAPSHOT</version>
<modules>
<module>springcloud-provider-dept-8001</module>
<module>springcloud-consumer-dept-80</module>
</modules>
<name>springcloud</name>
<description>SpringCloud Alibaba</description>
<properties>
<java.version>1.8</java.version>
<spring.cloud.alibaba.version>2.2.5.RELEASE</spring.cloud.alibaba.version>
<spring.boot.version>2.3.11.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR8</spring.cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<!--SpringCloud 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>
<!--SpringBoot 管理-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--SpringCloud 管理-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
1. Alibaba 微服务组件 Nacos 注册中心(Eureka服务注册与发现)
1.1 什么是 Nacos
官方:一个更易于构建云原生态应用的动态服务(Nacos Discovery)、服务配置(Nacos Config)和服务管理平台
Nacos 的关键特性包括:
- 服务发现和服务健康检测
- 动态配置服务
- 动态DNS服务
- 服务及其元数据管理
CAP 理论
C–一致性
- 访问所有的节点,得到的数据结果都是一样的。注意:这里的一致性指的是强一致性,也就是数据更新完,访问任意节点,看到的数据完全一致,要和弱一致性、最终一致性区分开来
A–可用性
- 所有节点都保持高可用性。注意:这里的高可用还包括,不能出现延迟,如节点B由于等待数据同步而阻塞了请求,那么节点B就不满足高可用性
P–分区容错性
- 这里的分区指的是网络意义上的分区。由于网络是不可靠的,所有节点之间很可能出现无法通讯的情况,在节点不能通信时,要保证系统可以继续正常服务
主流的注册中心
| 功能 | Nacos | Eureka | Consul | CoreDNS | Zookeeper |
|---|---|---|---|---|---|
| 一致性 | CP + AP | AP | CP | — | CP |
| 健康检查 | TCP/HTTP/MYSQL/Client/Beat | Client/Beat | TCP/HTTP/gRPC | — | Keep Alive |
| 负载均衡策略 | 权重/metadata/Selector | Ribbon | Fabio | RoundRobin | — |
| 雪崩保护 | 有 | 有 | 无 | 无 | 无 |
| 自动注销实例 | 支持 | 支持 | 支持 | 不支持 | 支持 |
| 访问协议 | HTTP/DNS | HTTP | HTTP/DNS | DNS | TCP |
| 监听支持 | 支持 | 支持 | 支持 | 不支持 | 支持 |
| 多数据中心 | 支持 | 支持 | 支持 | 不支持 | 不支持 |
| 跨注册中心同步 | 支持 | 不支持 | 支持 | 不支持 | 不支持 |
| SpringCloud集成 | 支持 | 支持 | 支持 | 不支持 | 支持 |
| Dubbo集成 | 支持 | 不支持 | 支持 | 不支持 | 支持 |
| K8S集成 | 支持 | 不支持 | 支持 | 支持 | 不支持 |
1.2 服务与注册中心
在Windows上部署
- github下载 Nacos 安装包:https://github.com/alibaba/nacos
选择 2.0.1 版本


- 到
/bin目录下,修改startup.cmd文件,设置为单机模式
set MODE="standalone"

- 运行
startup.cmd文件

- 访问地址命令窗口显示的地址http://192.168.166.1:8848/nacos/index.html
用户名、密码 都为 nacos

- 创建一个项目springcloud-api,用于构建对象与接口API
1)导入依赖
- pom.xml
<dependencies>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
2)编写实体类
- Department
@Data
@NoArgsConstructor
@Accessors(chain = true) // 链式写法
public class Department implements Serializable { // 实体类 orm 类表关系映射
private Long deptId; // 主键
private String deptName; // 部门名
// 这个数据存在哪个数据库的字段 微服务,一个服务对应一个数据库,同一个信息可能存在不同的数据库
private String db_source;
public Department(String deptName) {
this.deptName = deptName;
}
/**
* 链式写法:
* Department dept = new Department();
*
* 原来dept.setName();
*
* 加了之后:
* dept
* .setDeptName()
* .setDeptId()
* .setDb_source();
*
*/
}
- 创建一个项目 springcloud-provider-dept-8001,导入依赖
<dependencies>
<dependency>
<groupId>com.vinjcent</groupId>
<artifactId>springcloud-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--nacos-服务注册与发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
- 配置
application.yml
# 端口号
server:
port: 8001
spring:
application:
name: springcloud-provider-dept # 应用名称
# 配置nacos
cloud:
nacos:
# nacos 服务地址
server-addr: 127.0.0.1:8848
discovery:
username: nacos # nacos用户名
password: nacos
namespace: public # 分隔开发环境和测试环境使用
- 启动 springcloud-provider-dept-8001 项目

- 将我们的 springcloud-provider-dept-8001 项目终止,nacos 会更改服务的健康状态(一般是15s左右),如果一定时间内 nacos 没有接受到心跳,会剔除该注册用户(一般是30s左右)

1.3 使用 nacos 服务与注册,通过应用名访问
创建一个 springcloud-consumer-dept-80 模块(消费端)
导入依赖
- pom.xml
<dependencies>
<dependency>
<groupId>com.vinjcent</groupId>
<artifactId>springcloud-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--nacos-服务注册与发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
- 在类中配置 RestTemplate 模板
@Configuration
public class ConfigBean {
@Bean
public RestTemplate getRestTemplate(RestTemplateBuilder builder){
return builder.build();
}
}
- 再写一个 controller
- DeptController
@RestController
@RequestMapping("/consumer")
@SuppressWarnings("all")
public class DeptController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/dept/msg")
public String getMessage(){
return restTemplate.getForObject("http://springcloud-provider-dept/dept/msg",String.class);
}
}
- 配置
application.yml文件
# 端口号
server:
port: 80
- 在 springcloud-provider-dept-8001 项目中写一个 controller
- DeptController
@RestController
@RequestMapping("/dept")
@SuppressWarnings("all")
public class DeptController {
@Value("${server.port}")
private int port;
@GetMapping("/msg")
public String getMessage(){
return "获取服务成功!"+port;
}
}
- 将 springcloud-consumer-dept-80 启动
- 将 springcloud-provider-dept-8001 启动
- 访问 http://localhost/consumer/dept/msg

- 问题
需要给消费者 springcloud-consumer-dept-80 添加负载均衡

原因:nacos 本身没有办法解析服务名称到我们的 nacos 服务地址
再次访问http://localhost/consumer/dept/msg

具体流程

扩展
默认的负载均衡机制:轮询

1.4 有关 Nacos Discovery Starter 配置的更多信息
| 钥匙 | 默认值 | 描述 | |
|---|---|---|---|
| 服务器地址 | spring.cloud.nacos.discovery.server-addr | Nacos Server监听的IP和端口 | |
| 服务名称 | spring.cloud.nacos.discovery.service | ${spring.application.name} | 命名当前服务 |
| 重量 | spring.cloud.nacos.discovery.weight | 1 | 取值范围:1~100,数值越大,权重越大 |
| 网卡名称 | spring.cloud.nacos.discovery.network-interface | 如果不指定IP地址,则注册的IP地址为网卡的IP地址。如果也没有指定,则默认使用第一块网卡的 IP 地址。 | |
| 注册IP地址 | spring.cloud.nacos.discovery.ip | 最高优先级 | |
| 注册端口 | spring.cloud.nacos.discovery.port | -1 | 默认会自动检测。不需要配置。 |
| 命名空间 | spring.cloud.nacos.discovery.namespace | 一个典型的场景是隔离不同环境的服务注册,例如测试和生产环境之间的资源(配置、服务等)隔离 | |
| 访问密钥 | spring.cloud.nacos.discovery.access-key | 阿里云账号accesskey | |
| 密钥 | spring.cloud.nacos.discovery.secret-key | 阿里云账号秘钥 | |
| 元数据 | spring.cloud.nacos.discovery.metadata | 您可以以 Map 格式为您的服务定义一些元数据 | |
| 日志文件名 | spring.cloud.nacos.discovery.log-name | ||
| 集群名称 | spring.cloud.nacos.discovery.cluster-name | DEFAULT | Nacos的集群名称 |
| 端点 | spring.cloud.nacos.discovery.endpoint | 特定区域中某项服务的域名。您可以使用此域名动态检索服务器地址 | |
| 是否集成 Ribbon | ribbon.nacos.enabled | true | 在大多数情况下设置为 true |
| 启用 Nacos Watch | spring.cloud.nacos.discovery.watch.enabled | true | 设置为 false 监视 |
2. Nacos集群部署(eureka1、eureka2,eureka3)

在Linux虚拟机上部署
2.1 在 Linux 虚拟机中配置 Nacos
Linux配置环境
1)64 bit OS Linux/Unix/Mac,推荐使用Linux系统
2)64 bit JDK 1.8+
3)Maven 3.2.x+
4)nginx 作为负载均衡(SLB)
- 在 github 下载Nacos安装包:
https://github.com/alibaba/nacos/releases
- 选择 2.0.1 版本

- 选择 Linux 系统的安装包

- 使用 XShell 和 Xftp 软件将压缩文件上传至我们的 Linux 虚拟机中

- 在 Linux 虚拟机中找到压缩包的位置,进行解压和重命名,并且复制三份

千万要注意,Nacos 下载的是2.0+版本的,端口号不能相连在一起,必须间隔>=2,如:7002、7004、7006
最后面有张图就是连在一起的报错结果!然后又得重新开始
当然,跟着我的步骤就好了!(端口间隔为10)
# 解压三次 并附带它们的端口号
# nacos-7070
[root@vinjcent nacos]# tar -zxvf nacos-server-2.0.1.tar.gz
[root@vinjcent nacos]# mv nacos nacos-7070
# nacos-7080
[root@vinjcent nacos]# tar -zxvf nacos-server-2.0.1.tar.gz
[root@vinjcent nacos]# mv nacos nacos-7080
# nacos-7090
[root@vinjcent nacos]# tar -zxvf nacos-server-2.0.1.tar.gz
[root@vinjcent nacos]# mv nacos nacos-7090
解压完后的三个文件显示

- 修改 nacos 的端口号,并打开以下几个设置
1)修改 nacos-7070 的application.properties文件
vim ./nacos-7070/conf/application.properties


- 创建数据库(必须创建,不然也会报错,因为上面的图片,我们设置了开启数据库连接)
在 window 版的 nacos 中,该目录nacos-server-2.0.1\nacos\conf下有一个 nacos-mysql.sql 文件

在数据库中创建一个名为 nacos 的数据库,执行这个 sql 文件(使用的是Linux虚拟机下的数据库,不是本地的数据库!)

5)设置 nacos 集群的关联端口
在/usr/local/nacos/nacos-7070/conf下复制一份文件
cp cluster.conf.example cluster.conf # 复制一份名为cluster.conf的文件
编辑 cluster.conf 文件
vim cluster.conf
编辑内容如下

回到\bin目录下编辑startup.sh文件(可以设置,可以不设置)
vim startup.sh
- 由于个人虚拟机内存较小,如果你的虚拟机够大,就不需要更改了。更改内容如图所示

6)测试 nacos-7070 是否可以启动
# 在Linux虚拟机中开启端口7070
[root@vinjcent bin]# firewall-cmd --zone=public --add-port=7070/tcp --permanent
# 重启防火墙
systemctl restart firewalld.service
- 在
\bin目录下启动startup.sh
./startup.sh

使用命令查看是否启动成功(如果这里报错了,就是因为你是用的是你本机的数据库,需要在Linux系统安装数据库!)
[root@vinjcent bin]# tail -f ../logs/start.out
- 这个有点长,慢慢等

启动成功!
在本机(自己电脑)访问 Linux IP:7070/nacos/index.html#/login

- 配置成功!
7)将/nacos-7070/conf/路径下的application.properties文件分别给 nacos-7080、nacos-7090 进行覆盖
# 覆盖nacos-7080/conf/application.properties文件
[root@vinjcent nacos]# cp ./nacos-7070/conf/application.properties ./nacos-7080/conf/application.properties
# 覆盖nacos-7090/conf/application.properties文件
[root@vinjcent nacos]# cp ./nacos-7070/conf/application.properties ./nacos-7090/conf/application.properties
8)将/nacos-7070/conf/路径下的cluster.conf文件也分别复制到 nacos-7080、nacos-7090
[root@vinjcent nacos]# cp ./nacos-7070/conf/cluster.conf ./nacos-7080/conf/cluster.conf
[root@vinjcent nacos]# cp ./nacos-7070/conf/cluster.conf ./nacos-7090/conf/cluster.conf
9)将nacos-7070/bin/路径下的startup.sh文件也分别给nacos-7080、nacos-7090进行覆盖
[root@vinjcent nacos]# cp ./nacos-7070/bin/startup.sh ./nacos-7080/bin/startup.sh
cp: overwrite ‘./nacos-7080/bin/startup.sh’? y
[root@vinjcent nacos]# cp ./nacos-7070/bin/startup.sh ./nacos-7090/bin/startup.sh
cp: overwrite ‘./nacos-7090/bin/startup.sh’? y
10)分别修改nacos-7080、nacos-7090的application.properties文件里的端口号
[root@vinjcent nacos]# vim ./nacos-7080/conf/application.properties
[root@vinjcent nacos]# vim ./nacos-7090/conf/application.properties
- nacos-7080

- nacos-7090

11)在 Linux 虚拟机中,开启防火墙端口 7080、7090
# 开启7080端口
[root@vinjcent nacos]# firewall-cmd --zone=public --add-port=7080/tcp --permanent
# 开启7090端口
[root@vinjcent nacos]# firewall-cmd --zone=public --add-port=7090/tcp --permanent
# 重启防火墙
[root@vinjcent nacos]# systemctl restart firewalld.service

firewall-cmd --list-ports # 只看端口信息

可以看到已经将7080、7090端口开启
12)分别启动 nacos-7080、nacos-7090 的startup.sh文件
[root@vinjcent nacos]# sh ./nacos-7080/bin/startup.sh
[root@vinjcent nacos]# sh ./nacos-7090/bin/startup.sh

下面这个图片就是使用 7001、7002、7003 相连端口报错的信息,所以我不得不重新修改端口再来一遍(请勿模仿!)

个人建议下载一个 XShell 和 Xftp 方便文件的修改
访问
http://虚拟机的IP:7080/nacos/index.html#/login
http://虚拟机的IP:7090/nacos/index.html#/login


用户名、密码都是 nacos
登陆后查看红色区域的页面
出现该页面即搭建 Nacos 集群成功!

修改 springcloud-provider-dept-8001 模块下的application.yml文件

2.2 Nacos自带的微服务负载均衡器 Ribbon
2.2.1 Ribbon 负载均衡策略

IRule
是所有负载均衡策略的父接口,里边的核心方法就是 choose 方法,用来选择一个服务实例
AbstractLoadBalancerRule
AbstractLoadBalancerRule 是一个抽象类,类里主要定义了一个 ILoadBalancer,就是我们上文所说的负载均衡器,用于定义它的目的主要是辅助负责均衡策略选取合适的服务端实例
RandomRule
- 是一种负载均衡策略就是随机选择一个服务实例,看源码可以知道,在 RandomRule 的无参构造方法中初始化了一个 Random 对象,然后在它重写的 choose 方法又调用了,choose(ILoadBalancer lb.Obect key) 这个重载的 choose 方法,在这个重载的 choose 方法中,每次利用 random 对象生成一个不大于服务实例总数的随机数,并将该数作为下标所以获取一个服务实例
RoundRobinRule
- RoundRobinRule 这种负载均衡策略叫做线性轮询负载均衡策略。这个类的 choose(ILoadBalancer lb.Objectkey)整体逻辑是这样的:开启一个计数器 count,在 while 循环中遍历服务清单,获取清单之前先通过 incrementAndGetModulo 方法获取一个下标,这个下标是一个不断自增的数,先加1然后和服务清单总数取模之后获取到的(所以这个下标从来不会越界),拿着下标再去服务清单列表中取服务,每次循环计数器都会加1,如果连续10次都没有取到服务,则会报一个警告
No available alive servers after 10 tries from load balancer:ILoadBalancer
- RoundRobinRule 这种负载均衡策略叫做线性轮询负载均衡策略。这个类的 choose(ILoadBalancer lb.Objectkey)整体逻辑是这样的:开启一个计数器 count,在 while 循环中遍历服务清单,获取清单之前先通过 incrementAndGetModulo 方法获取一个下标,这个下标是一个不断自增的数,先加1然后和服务清单总数取模之后获取到的(所以这个下标从来不会越界),拿着下标再去服务清单列表中取服务,每次循环计数器都会加1,如果连续10次都没有取到服务,则会报一个警告
RetryRule (在轮询的基础上进行重试)
- 这种负载均衡策略带有重试功能。首先 RetryRule 中又定义了一个 subRule,它的实现类是 RoundRobinRule,然后在 RetryRule 的 choose(ILoadBalancer lb,Object key) 方法中,每次还是采用 RoundRobinRule 中的 choose 规则来选择一个服务实例,如果选到的实例正常就返回,如果选择的服务实例为null或者已经失效,则在失效时间 deadline 之前不断的进行重试 (重试时获取服务的策略还是 RoundRobinRule 中定义的策略),如果超过了 deadline 还是没取到则会返回一个null
WeightedResponseTimeRule(权重–nacos 的 NacosRule,Nacos还扩展了一个自己的基于配置的权重扩展)
- WeightedResponseTimeRule 是 RoundRobinRule 的一个子类,在 WeightedResponseTimeRule 中对 RoundRobinRule 的功能进行了扩展, WeightedResponseTimeRule 中会根据每一个实例的运行情况来给计算出该实例的一个权重,然后在挑选实例的时候则根据权重进行挑选,这样能够实现更优的实例调用。WeightedResponseTimeRule 中有一个名叫 DynamicServerWeightTask 的定时任务,默认情况下每隔30秒会计算一次各个服务实例的权重,
权重的计算规则也很简单:如果一个服务的平均响应时间越短则权重越大,那么该服务实例被选中执行任务的概率也就越大
- WeightedResponseTimeRule 是 RoundRobinRule 的一个子类,在 WeightedResponseTimeRule 中对 RoundRobinRule 的功能进行了扩展, WeightedResponseTimeRule 中会根据每一个实例的运行情况来给计算出该实例的一个权重,然后在挑选实例的时候则根据权重进行挑选,这样能够实现更优的实例调用。WeightedResponseTimeRule 中有一个名叫 DynamicServerWeightTask 的定时任务,默认情况下每隔30秒会计算一次各个服务实例的权重,
ClientConfigEnabledRoundRobinRule
- ClientConfigEnabledRoundRobinRule 选择策略内部定义了 RoundRobinRule,choose 方法还是采用了 RoundRobinRule 的 choose 方法,所以它的选择策略和 RoundRobinRule的选择策略一致
BestAvailableRule
- BestAvailableRule 继承自 ClientConfiqEnabledRoundRobinRule,它在ClientConficEnabledRoundRobinRule 的基础上主要增加了根据loadBalancerStats中保存的服务实例的状态信息来过滤掉失效的服务实例的功能,然后顺便找出并发请求最小的服务实例来使用,然而 loadBalancerStats 有可能为null,如果 loadBalancerStats 为null,则 BestAvailableRule 将采用它的父类即 ClientConfigEnabledRoundRobinRule 的服务选取策略(线性轮询)
ZoneAvoidanceRule(默认规则,复合判断server所在区域的性能和server的可用性选择服务器)
- ZoneAvoidanceRule 是 PredicateBasedRule 的一个实现类,只不过这里多了一个过滤条件,ZoneAvoidanceRule 中的过滤条件是以 ZoneAvoidancePredicate 为主过滤条件和以 AvailabilityPredicate 为次过滤条件组成的一个叫做 CompositePredicate 的组合过滤条件,过滤成功之后,继续采用线性轮询(RoundRobinRule)的方式从过滤结果中选择一个出来
AvailabilityFilteringRule(先过滤掉故障实例,再选择并发较小的实例)
- 过滤掉一直连接失败的被标记为 circuit tripped 的后端 Server,并过滤掉那些高并发的后端Server或者使用一个 AvailabilityPredicate 来包含过滤server的逻辑,实质上就是检查status里记录的各个Server的运行状态
2.2.2 修改默认默认负载均衡策略
方式一(使用注解)
1)在消费端 springcloud-consumer-dept-80 模块下,创建一个RibbonStrategy.class类,注入一个 IRule 的bean
注意该包位置必须不在主启动类的包下,因为会被@ComponentScan注解扫描到
测试
@RibbonClients(value = {
@RibbonClient(name = "ProviderApplication1",configuration = xxx.class) //随机策略
@RibbonClient(name = "ProviderApplication2",configuration = xxx.class) //重试策略
})
public class ConfigBean {
...
}
@RibbonClients 指定某个服务提供方使用的均衡策略
被@ComponentScan注解扫描到,对于一个类配置了多个@RibbonClient,相当于全局配置的效果,比如上面一个是随机策略,一个是重试策略,如果将此类放在与主启动类同一个包下,重试策略将会失效,使得所有服务提供者使用同一个策略
如图所示

2)修改模块 springcloud-consumer-dept-80 中的application.yml文件
server:
port: 80
spring:
application:
name: springcloud-consumer-dept
# 配置nacos
cloud:
nacos:
# nacos 服务地址
server-addr: 192.168.159.100:7070,192.168.159.100:7080,192.168.159.100:7090
discovery:
username: nacos # nacos用户名
password: nacos
namespace: public # 分隔开发环境和测试环境使用
3)在主启动类上加上注解@RibbonClients
@SpringBootApplication
@RibbonClients(value = {
/**
* name 提供者应用名称
* configuration 使用的是哪个负载均衡配置类
*/
@RibbonClient(name = "springcloud-provider-dept",configuration = RibbonStrategy.class)
})
public class SpringCloud_Consumer_80 {
public static void main(String[] args) {
SpringApplication.run(SpringCloud_Consumer_80.class,args);
}
}
4)复制两份 springcloud-provider-dept-8001 模块,改名为 springcloud-provider-dept-8002、springcloud-provider-dept-8003
将其application.yml文件的端口分别改为8002、8003
5)
在 Linux 已经启动了 Nacos 的条件下,访问网页
http://192.168.159.100:7070/nacos/index.html#/ 或
http://192.168.159.100:7080/nacos/index.html#/ 或
http://192.168.159.100:7090/nacos/index.html#/ 其中一个启动springcloud-provider-dept-8001
启动springcloud-provider-dept-8002
启动springcloud-provider-dept-8003
启动springcloud-consumer-dept-80
查看输出结果
方式二(使用配置文件)
1)将 springcloud-consumer-dept-80 项目下的主启动类的@RibbonClients注解注释掉

2)在该项目下修改application.yml文件
server:
port: 80
spring:
application:
name: springcloud-consumer-dept
# 配置nacos
cloud:
nacos:
# nacos 服务地址
server-addr: 192.168.159.100:7070,192.168.159.100:7080,192.168.159.100:7090
discovery:
username: nacos # nacos用户名
password: nacos
namespace: public # 分隔开发环境和测试环境使用
# 调用的服务提供方应用名称
springcloud-provider-dept:
ribbon:
# 复制NacosRule类的引用路径,使用的是NacosRule权重策略
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule

3)访问 nacos 注册中心,修改两个提供者的权重


如果报错
caused: errCode: 500, errMsg: do metadata operation failed ;caused: com.alibaba.nacos.consistency.exception.ConsistencyException: com.alibaba.nacos.core.distributed.raft.exception.NoLeaderException: The Raft Group [naming_instance_metadata] did not find the Leader node;caused: com.alibaba.nacos.core.distributed.raft.exception.NoLeaderException: The Raft Group [naming_instance_metadata] did not find the Leader node;
解决办法
- 在 Linux 安装的 nacos 文件夹下删除以下的三个文件即可

而如果使用 windows 系统则删除这两个文件

再次修改,刷新页面

修改成功!
4)测试
启动 springcloud-consumer-dept-80 模块
多次访问 http://localhost/consumer/dept/msg
查看结果(权重越大,就越频繁调用该服务提供者)
2.2.3 自定义负载均衡器
通过实现 IRule 接口可以自定义负载策略,主要的选择服务逻辑是在 choose 方法中
1)在 springcloud-consumer-dept-80 模块的 ribbon 包下创建一个MyRibbon.class类

- MyRibbon
public class MyRibbon extends AbstractLoadBalancerRule {
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
@Override
public Server choose(Object o) {
ILoadBalancer loadBalancer = this.getLoadBalancer();
//获得当前请求服务的实例
List<Server> reachableServers = loadBalancer.getReachableServers();
//根据服务的数量,获取范围内的随机数
int random = ThreadLocalRandom.current().nextInt(reachableServers.size());
//根据随机数获取服务
Server server = reachableServers.get(random);
//可以判断获取该服务是否存活
//不存活就继续获取
return server;
}
}
2)将其配置到Ribbon策略中
方式一:注解
- 在
RibbonStrategy.class类中修改

- 在主启动类开启注解

方式二:配置文件
- 复制自定义的负载均衡策略引用路径

- 在
application.yml修改引用路径

3)测试
重新启动 springcloud-consumer-dept-80 模块
不断访问 http://localhost/consumer/dept/msg,看结果
如果自己想写一个负载均衡配置策略,可以观摩一下RandomRule.clss类策略
2.2.4 拓展
Ribbon 的饿加载模式
在使用 Spring Cloud 的 Ribbon 或 Feign 来实现服务调用的时候,如果机器或网络环境等原因不是很好的话,有时候会发现这样一个问题:服务消费方调用服务提供方接口的时候,第一次请求经常会超时,而之后的调用就没有问题了
问题的原因
造成第一次服务调用出现失败的原因主要是Ribbon 进行客户端负载均衡的 Client 并不是在服务启动的时候就初始化的,而是在调用的时候才会去创建相应的 Client,所以第一次调用的耗时不仅仅包含发送 HTTP 请求的时间,还包含了创建 RibbonClient 的时间,这样一来如果创建时间速度较慢,同时设置的超时时间又比较短的话,很容易就会出现上面所描述的显现
解决的方法
ribbon:
eager-load:
# 开启饥饿加载
enabled: true
# 配置服务名为springcloud-provider-dept使用ribbon饥饿加载,多个服务可以使用","分隔
clients: springcloud-provider-dept
下一篇文章《微服务组件Feign&Nacos配置中心使用》