目前主流的负载方案分为两种,一种是集中式负载均衡,在消费者和服务提供方中间使用独立的代理方式进行负载,有硬件的,比如F5,也有软件的,比如Nginx。
另一种则是客户端自己做负载均衡,根据自己的请求情况做负载,Ribbon就是属于客户端自己做负载的。
一句话介绍那就是Ribbon是Netflix开源的一款用于客户端负载均衡的工具软件。GitHub地址:https://github.com/Netflix/ribbon。
Ribbon默认的策略是轮询,我们可以自定义负载策略来覆盖默认的,当然也可以通过配置指定使用哪些策略。
Ribbon架构图
Ribbon作为后端负载均衡器,比Nginx更注重的是承担并发而不是请求分发,可以直接感知后台动态变化来指定分发策略。它一共提供了7种负载均衡策略:
以随机访问策略:
1、ribbon配置文件添加:
service-B.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
其中service-B是我注册到Eureka的serviceID,一共起了3个示例。
2、main类注册:
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public IRule ribbonRule() {
return new RandomRule();//这里配置策略,和配置文件对应
}
一定记得加第二个注册,里面配具体的策略。
3、Controller:
@RestController
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private LoadBalancerClient loadBalancerClient;
@RequestMapping(value = "/add", method = RequestMethod.GET)
public String add(@RequestParam Integer a,@RequestParam Integer b) {
this.loadBalancerClient.choose("service-B");//随机访问策略
return restTemplate.getForEntity("http://service-B/add?a="+a+"&b="+b, String.class).getBody();
}
}
客户端负载均衡Spring Cloud Ribbon
Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,基于Netflix Ribbon实现。
目录
客户端负载均衡
源码分析
负载均衡器
负载均衡策略(本文重点)
配置详解
自动化配置
负载均衡器
负载均衡器相关内容见上一篇文章
负载均衡策略
AbstractLoadBalancerRule
负载均衡策略的抽象类,在该抽象类中定义了负载均衡器ILoadBalancer对象,该对象能够在具体实现选择服务策略时,获取到一些负载均衡器中维护的信息作为分配依据,并以此设计一些算法来实现针对特定场景的高效策略。
package com.netflix.loadbalancer;
import com.netflix.client.IClientConfigAware;
public abstract class AbstractLoadBalancerRule implements IRule, IClientConfigAware {
private ILoadBalancer lb;
@Override
public void setLoadBalancer(ILoadBalancer lb){
this.lb = lb;
}
@Override
public ILoadBalancer getLoadBalancer(){
return lb;
}
}
RandomRule
该策略实现了从服务实例清单中随机选择一个服务实例的功能。下面先看一下源码:
package com.netflix.loadbalancer;
import java.util.List;
import java.util.Random;
import com.netflix.client.config.IClientConfig;
public class RandomRule extends AbstractLoadBalancerRule {
Random rand;
public RandomRule() {
rand = new Random();
}
@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 upList = lb.getReachableServers();
List 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;
}