Ribbon
是一个客户端负载均衡工具,主要功能是将面向服务的Rest模板(RestTemplate)请求转换成客户端负载均衡的服务调用。通过Ribbon,开发人员可以在客户端实现请求的负载均衡,而无需单独部署负载均衡器。Ribbon支持多种负载均衡算法,如轮询、随机
、加权等,只需要在配置文件类中添加@LoadBalanced
。
Ribbon配置在消费者模块中
之前写过消费者的模块 =>SpringCloud之消费者
本文章的目的是:利用Ribbon实现负载均衡
1、导入依赖
<!-- ribbon & eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
2、创建配置文件类
只需要在RestTemplate上添加
@LoadBalanced
注解
@Configuration
public class ConfigBean {
/**
* http请求
* @return
*/
@Bean
@LoadBalanced // 使用Ribbon
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
@Bean
public IRule getRule(){
return new RandomRule(); // 随机
// return new MyRule(); 自定义
}
}
3、定义负载均衡的规则
实现了IRule的实现类如下:
具体实现类作用如下:
RandomRule:随机规则。使用Random对象从服务列表中随机选择一个服务实例。这种规则在每次请求时都会随机选择一个服务实例,有助于实现请求的均匀分布。
RoundRobinRule:轮询规则。这是Ribbon的默认规则,也是更高级规则的回退策略。它按照顺序依次选择服务实例进行调用,实现了一种简单的负载均衡。
RetryRule:重试规则。这种规则首先使用RoundRobinRule进行服务实例选择,如果选择服务实例失败或在指定时间内没有响应,则会在一定时间内不断进行重试,直到找到可用的服务实例或超时。
WeightedResponseTimeRule:加权响应时间规则。这种规则会根据每个服务实例的平均响应时间计算权重,响应时间越快的服务实例权重越高,被选中的概率也越高。这种规则能够优先将请求分发给性能更好的服务实例。
BestAvailableRule:最佳可用规则。它会选择并发量最小的服务实例进行调用,有助于平衡各个服务实例的负载。
ZoneAvoidanceRule:区域感知规则。在非AWS环境下,可以将其理解为根据机房或Eureka集群来选择服务实例。它会优先选择同区域的服务实例,当同区域的服务实例不可用时,才会选择其他区域的服务实例。
4、自定义负载均衡的规则
自定义负载均衡需要注意的是自己创建的MyRule类不能和项目启动器类放在同一个文件夹内,即不能被Spring Boot扫描到。所以需要放置在启动类所在的包之外的独立包中。
/**
* 注意 这个类不能被主启动类扫描 所以需要放在com.jyl下的目录
*/
@Configuration
public class MyRule extends AbstractLoadBalancerRule {
/**
* 实现一个每个服务只能访问5次,访问五次后换下一个服务
* @param lb
* @param key
* @return
*/
private int total = 0 ;// 被调用的次数
private int currentIndex = 0 ; // 当前被调用的服务
public MyRule(){
}
// @SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"})
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
} else {
Server server = null;
while(server == null) {
if (Thread.interrupted()) {
return null;
}
// 获得活着的服务
List<Server> upList = lb.getReachableServers();
// 获得全部的服务
List<Server> allList = lb.getAllServers();
int serverCount = allList.size();
if (serverCount == 0) {
return null;
}
// // 生成区间随机数
// int index = this.chooseRandomInt(serverCount);
// // 随机获取一个
// server = (Server)upList.get(index);
if(total < 5){
server = upList.get(currentIndex);
total++;
}else {
total = 0 ;
currentIndex++ ; // 5 + 1
if (currentIndex > upList.size()){
currentIndex = 0 ;
}
// 从活着的服务中, 获取指定的服务来进行操作
server = upList.get(currentIndex);
}
if (server == null) {
Thread.yield();
} else {
if (server.isAlive()) {
return server;
}
server = null;
Thread.yield();
}
}
return server;
}
}
protected int chooseRandomInt(int serverCount) {
return ThreadLocalRandom.current().nextInt(serverCount);
}
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
5、启动器类
需要添加@RibbonClient注解
需要的参数是name
=“Eureka界面中的Application提供者的名称” 和configuration
=自定义类
@SpringBootApplication
@EnableEurekaClient
//再微服务启动的时候就可以加载自定义ribbon类
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = MyRule.class)
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class,args);
}
}
6、创建数据库&提供者模块
到这里还没有结束
,需要体验到负载均衡的效果,需要使用三个提供者,三个提供者要使用不同的数据库
之前有写过提供者的案例=>这里!!!
创建数据库名db01、db02、db03,创建相同的dept表如下:
CREATE TABLE `dept` (
`deptno` bigint(20) NOT NULL AUTO_INCREMENT,
`dname` varchar(50) DEFAULT NULL,
`db_source` varchar(50) DEFAULT NULL,
PRIMARY KEY (`deptno`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
只需要修改配置文件中的数据库名提供者依次连接数据库,如:提供者1连接db01
# spring 的配置
spring:
application:
name: springcloud-provider-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://localhost:3306/数据库名?useUnicode=true&useSSL=false&characterEncoding=utf-8
username: root
password: root
7、启动eureka&提供者
启动3个eureka服务、3个提供者和一个消费者
随机访问一个eureka服务界面
比如访问:http://localhost:7001/
说明3个提供者已经注册到了eureka集群中了
8、测试负载均衡
默认的负载均衡策略是轮询
如果需要修改负载均衡策略可以再配置文件类中设置
@Configuration
public class ConfigBean {
@Bean
public IRule getRule(){
return new RandomRule(); // 随机
// return new MyRule(); 自定义
}
}
【每日自勉+1】“业精于勤,荒于嬉;行成于思,毁于随。”——韩愈。