- 1、SpringCloud Ribbon 是一个客户端的负载均衡组件,主要提供负载均衡算法。
- 2、Ribbon中负载均衡算法实现:
AbstractLoadBalancerRule:负载均衡策略的抽象类,在该抽象类中定义了负载均衡器ILoadBalancer对象,该对象能够在具体实现选择服务策略时,获取到一些负载均衡器中维护的信息来作为分配依据,并以此设计一些算法来实现针对特定场景的高效策略。
RandomRule:随机策略,从服务实例清单中随机选择一个服务实例。获得可用实例列表upList和所有实例列表allList,并通过rand.nextInt(serverCount)函数来获取一个随机数,并将该随机数作为upList的索引值来返回具体实例。
RoundRobinRule:轮询策略,按照线性轮询的方式依次选择每个服务实例。通过AtomicInteger nextServerCyclicCounter对象实现,每次进行实例选择时通过调用incrementAndGetModulo函数实现递增。
RetryRule:重试策略,具备重试机制的实例选择。内部定义了RoundRobinRule,并实现了对RoundRobinRule进行反复尝试的策略,若期间能够选择到具体的服务实例就返回,若选择不到就根据设置的尝试结束时间为阈值,当超过该阈值后就返回null。
WeightedResponseTimeRule:权重策略,根据实例的运行情况来计算权重,并根据权重来挑选实例,以达到更优的分配效果。通过定时任务为每个服务进行权重计算,平均响应时间小的权重区间(总平均响应时间-实例平均响应时间)就大,实力选择根据权重范围随机选择,落在哪个区间则选择哪个实例。
BestAvailableRule:最佳策略,通过遍历负载均衡器中维护的所有服务实例,会过滤掉故障的实例,并找出并发请求数最小的一个,选出最空闲的实例。
AvailabilityFilteringRule:可用过滤策略:先过滤出故障的或并发请求大于阈值一部分服务实例,然后再以线性轮询的方式从过滤后的实例清单中选出一个。
ZoneAvoidanceRule:区域感知策略:使用主过滤条件(区域负载器,选择最优区域)对所有实例过滤并返回过滤后的实例清单,依次使用次过滤条件列表中的过滤条件对主过滤条件的结果进行过滤,判断最小过滤数(默认1)和最小过滤百分比(默认0),满足条件则使用RoundRobinRule选择实例。
- 3、Ribbon使用
//导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
//开启负载均衡
@Configuration
public class ConfigBean {
//实现负载均衡
@Bean
@LoadBalanced //这个注解开启ribbon负载均衡
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
//服务消费着通过RestTemplate与服务之间进行通信
@RestController
public class DeptConsumerController {
@Autowired
private RestTemplate restTemplate;
//通过注册中心的服务名称获取服务的通信地址
private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
@RequestMapping(value = "/consumer/dept/add",method = RequestMethod.POST)
public boolean addDept(Dept dept){
//通过接口地址向服务发送请求,并就收返回信息
return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add/",dept,boolean.class);
}
@RequestMapping("/consumer/dept/get/{id}")
public Dept getDept(@PathVariable("id") Long id){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class);
}
@RequestMapping("/consumer/dept/queryAll")
public List<Dept> queryAll(){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/all/",List.class);
}
}
自定义负载均衡策略
//自定义负载均衡需要实现AbstractLoadBalancerRule类
package com.zhang.rule;
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class Rule extends AbstractLoadBalancerRule {
public Rule() {
}
//设置每个服务访问5次
//total = 0 默认0,如果等于5,指向下一个服务节点
//index = 0 默认0,如果total>5,index+1
private int total = 0; //服务被调用的次数
private int currentIndex = 0; //当前是谁在提供服务
//@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++;
if(currentIndex>upList.size()-1){
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) {
}
}
//将自定义规则交给spring管理
package com.zhang.rule;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Myrule {
@Bean
public IRule myRule(){
return new Rule();
}
}
//在启动类加载自定义负载均衡策略
package com.zhang.springcloud;
import com.zhang.rule.Myrule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
@SpringBootApplication
@EnableEurekaClient
//在微服务启动的时候就能够自动加载自定义的Ribbon负载均衡策略
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = Myrule.class)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}