一、系统内置的策略有以下几种。
这个负载策略配置说白了就是让 Ribbon 这个客户端负载均衡器怎么进行访问服务提供者列表。是轮流访问?随机访问?权重?等。
Ribbon 的负载均衡策略
策略类 命名 说明
RandomRule 随机策略 随机选择 Server
RoundRobinRule 轮训策略 按顺序循环选择 Server
RetryRule 重试策略 在一个配置时问段内当选择 Server 不成功,则一直尝试选择一个可用的 Server
BestAvailableRule 最低并发策略 逐个考察 Server,如果 Server 断路器打开,则忽略,再选择其中并发连接最低的 Server
AvailabilityFilteringRule 可用过滤策略 过滤掉一直连接失败并被标记为 circuit tripped 的 Server,过滤掉那些高并发连接的 Server(active connections 超过配置的网值)
ResponseTimeWeightedRule 响应时间加权策略 根据 Server 的响应时间分配权重。响应时间越长,权重越低,被选择到的概率就越低;响应时间越短,权重越高,被选择到的概率就越高。这个策略很贴切,综合了各种因素,如:网络、磁盘、IO等,这些因素直接影响着响应时间
ZoneAvoidanceRule 区域权衡策略 综合判断 Server 所在区域的性能和 Server 的可用性轮询选择 Server,并且判定一个 AWS Zone 的运行性能是否可用,剔除不可用的 Zone 中的所有 Server
二、示例
1.只要在启动时创建一个IRule对象,注入容器,即可。因为系统内置的容器需要在真正 发起请求时才会创建,并且判断系统容器中没有IRule对象。
@SpringBootApplication
@Slf4j
@EnableDiscoveryClient
@RestController
public class ConsumeApplication {
@Autowired
RestTemplate restTemplate;
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
clientHttpRequestFactory.setConnectTimeout(5 * 1000);
clientHttpRequestFactory.setReadTimeout(5 * 1000);
return new RestTemplate(clientHttpRequestFactory);
}
@Bean
public IRule ribbonRule() {
return new RandomRule();
}
public static void main(String[] args) {
SpringApplication.run(ConsumeApplication.class, args);
}
@GetMapping("test")
public String getContent(){
log.info("发起请求");
String ret = restTemplate.getForObject("http://provider/provider",String.class);
return ret;
}
}
2.在创建ribbonLoadBalancer时就会使用最新的RULE
三、在发起调用时触发RULE的choose方法
1.源码 ,这个很简单,就是随机取一个实例。
package com.netflix.loadbalancer;
import java.util.List;
import java.util.Random;
import com.netflix.client.config.IClientConfig;
/**
* A loadbalacing strategy that randomly distributes traffic amongst existing
* servers.
*
* @author stonse
*
*/
public class RandomRule extends AbstractLoadBalancerRule {
Random rand;
public RandomRule() {
rand = new Random();
}
/**
* Randomly choose from all living servers
*/
@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
}
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) {
/*
* No servers. End regardless of pass, because subsequent passes
* only get more restrictive.
*/
return null;
}
int index = rand.nextInt(serverCount);
server = upList.get(index);
if (server == null) {
/*
* The only time this should happen is if the server list were
* somehow trimmed. This is a transient condition. Retry after
* yielding.
*/
Thread.yield();
continue;
}
if (server.isAlive()) {
return (server);
}
// Shouldn't actually happen.. but must be transient or a bug.
server = null;
Thread.yield();
}
return server;
}
四、可以针对单个服务自定义IRULE规则。
1.编写IRULE
package com.net.sample.consume;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.Server;
import java.util.List;
import java.util.Random;
public class FirstRule extends AbstractLoadBalancerRule {
public FirstRule() {
}
/**
* Randomly choose from all living servers
*/
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
}
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) {
/*
* No servers. End regardless of pass, because subsequent passes
* only get more restrictive.
*/
return null;
}
int index = 0;
server = upList.get(index);
if (server == null) {
/*
* The only time this should happen is if the server list were
* somehow trimmed. This is a transient condition. Retry after
* yielding.
*/
Thread.yield();
continue;
}
if (server.isAlive()) {
return (server);
}
// Shouldn't actually happen.. but must be transient or a bug.
server = null;
Thread.yield();
}
return server;
}
@Override
public Server choose(Object key) {
return choose(getLoadBalancer(), key);
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
// TODO Auto-generated method stub
}
}
2.编写CONFIGIGATION,这个配置类不在程序启动初始化时加载,而是在请求时,由RIBBON内部的SpringClientFactory的子applicationContext来创建和实例化。
package com.net.sample.consume;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.IRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
@Configuration
/** 用来标记使用的注解,方便排除或者引用 **/
@AvoidScan
public class RibbonFirstLoadBalancingConfiguration {
@Bean
public IRule ribbonRule() {
return new FirstRule();
}
}
3.启动类加上,启动时排除上面的配置的包。RibbonClient针对每个服务端进行单独的配置,就是configuation实例,由这个内部来创建IRULE,IRuleFilter,ServerList都可以自定义。
@SpringBootApplication
@Slf4j
@EnableDiscoveryClient
@RestController
@ComponentScan(excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,value = AvoidScan.class))
@RibbonClient(name = "provider",configuration = RibbonFirstLoadBalancingConfiguration.class)
public class ConsumeApplication {
4.这里看到进入了我们自定义的IRULE规则选择服务实例。