之前的文章中我们简单介绍了一下微服务系统架构中引入Ribbon负载均衡的集成
接下来我们会系统的介绍一下Ribbon的实现及自定义策略负载均衡
1)项目的基础结构:
在一个微服务中我们存在一个共有api
一个统一的客户端(服务消费者)80
服务注册中心的集群 eureka
服务的提供者(多个)
Ribbon应用的思维导图:
Ribbon是一个客户端实现负载均衡的方案,集成在我们的编码阶段,区别于nginx的不同是不需要搭建服务器来实现
其核心主要为:
- 获取注册中心的服务
- 通过用户定义的负载均衡的策略选择服务的提供者(默认采用轮询策略)
Ribbon的核心策略类为IRule:其中包含的策略有
后面我们会具体介绍这几种策略
2)实现Ribbon负载均衡
根据官方描述:
可以使用@RibbonClient
实现Ribbon的负载均衡,但是实现类必须是@Configuration
且不能与主启动类存在与同一级下,所以我们的客户端项目结构为
3)修改负载均衡的策略
@Configuration
public class MyRule {
@Bean
public IRule myIRule(){
return new RandomRule(); //随机
}
}
4)配置主启动类使用我们的负载均衡配置
@SpringBootApplication
@EnableEurekaClient
//在启动时加载我们自定义的负载均衡组件,自定义组件必须是@Configuration,他会替换已有的组件,从而使用我们自定义的负载均衡组件
@RibbonClient(name = "peo_user",configuration = MyRule.class)
public class ConApplication {
public static void main(String[] args) {
SpringApplication.run(ConApplication.class,args);
}
}
至此我们就完成了Ribbon的负载均衡的实现,当然,在实际开发中,IRule提供的负载均衡的策略不一定满足我们服务器的配置需求,这时候就需要我们实现自定义的负载均衡的算法策略,下面我们就介绍一下Ribbon提供的负载均衡的策略及如何实在自定义的负载均衡策略
上面我们介绍到Ribbon的核心组件是IRule,是所有负载均衡算法的父接口,其下有
- RoundRobinRule :轮询策略,即依次使用存活的服务
- RandomRule : 随机策略,每次请求会产生一个随机的服务提供访问
- AvailabilityFilteringRule :过滤轮询策略,他会先过滤掉跳闸、故障、超过并发阈值的服务,对剩余服务使用轮询策略
- WeightedResponseTimeRule : 权重策略,根据平均响应时间计算所有服务的权重,响应时间越快服务权重越大被选中的概率越高。刚启动时,如果统计信息不足,则使用轮询策略,等信息足够,切换到 WeightedResponseTimeRule
- RetryRule : 重试,先按照轮询策略获取服务,如果获取失败则在指定时间内重试,获取可用服务
- BestAvailableRule :选过滤掉多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
- ZoneAvoidanceRule : 符合判断server所在区域的性能和server的可用性选择服务
以上的几种策略都继承AbstractLoadBalancerRule
下面简单介绍一下随机策略的实现源码,其余实现大家可自行阅读源码
public class RandomRule extends AbstractLoadBalancerRule {
public RandomRule() {
}
@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 (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) {
}
}
通过注解我们可以看出,其实就是实现了一个简单的算法,通过一个范围随机数来指定此次访问的服务为哪一个。
重点来了-------
重点来了-------
重点来了-------
既然我们已经了解了Ribbon负载均衡的算法实现及原理,那么我们就可以实现我们自己的负载均衡策略
- 集成
AbstractLoadBalancerRule
- 添加实现方法
- 编写自己的算法策略
- 依据上面的配置修改为我们自己的策略
描述:每个服务提供五次访问,满五次以后切换到下一个服务,当所有服务都使用完毕后从第一个服务继续开始,编码如下
public class MyBalancerRule extends AbstractLoadBalancerRule {
private int total = 0; //服务被调用次数
private int currentIndex = 0; //当前提供服务的服务下标
public MyBalancerRule(){
}
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
/**
* 自定义策略,访问五次更换服务
*/
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;
}
if(total < 5){ //服务未被调用五次,可以继续使用当前服务
server = upList.get(currentIndex); //获取当前服务
total++; //增加服务调用次数
}else{ //服务已被调用五次,需要更换服务
total = 0; //归零服务被调用次数
currentIndex++; //下移当前被调用服务下标
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;
}
}
}
@Configuration
public class MyRule {
@Bean
public IRule myIRule(){
return new MyBalancerRule(); //自定义负载均衡策略
}
}
我们也可以使用配置文件来配置:
eureka.client.service-url.defaultZone=http://localhost:7001/eureka/,http://localhost:7002/eureka/
server.port=80
spring.application.name=pro_user
springboot-eureka-clent.ribbon.NFLoadBalancerRuleClassName=com.balance.config.MyBalancerRule
补充知识
在非eureka环境下使用Ribbon
#取消Ribbon使用Eureka
ribbon.eureka.enabled=false
#配置Ribbon能访问 的微服务节点,多个节点用逗号隔开
microservice-provider-user.ribbon.listOfServers=localhost:7001,localhost:7002
源码地址:下载地址