一、简介
目前主流的负载均衡的方案分为两种:一种是集中式的负载均衡,在消费者和服务提供方中间使用独立的大力方式进行负载,另一种则是客户端自己做负载均衡,根据自己的请求情况做负载。Ribbon就是客户端自己做负载。
二、Ribbon模块
ribbon-loadbalancer:负载均衡模块,可独立使用,也可以和别的模块一起使用。Ribbon的内置负载均衡算法都实现在其中
ribbon-eureka:基于Eureka封装的模块,能够快速的方便的集成Eureka。
ribbon-transport:就要Netty 实现多协议的支持,比如Http、TCP、Udp等
ribbon-httpclient:基于Apache HttpClient 封装的Rest的客户端,集成了负载均衡模块,可以一直接在项目中使用来调用接口。
ribbon-example:Ribbon使用代码示例
ribbon-core:一些比较和音的具有通用性的代码,客户端API的一些配置和其他API的定义。
三、Ribbon的使用
准备工作:需要启动两个服务,下面的示例中这两个服务的端口分别为8081和8082他们都有/user/hello的接口
1. 引入依赖
<dependency>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon</artifactId>
<version> 2.3.0</version>
</dependency>
<dependency>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon-loadbalancer</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon-core</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>io.reactivex</groupId>
<artifactId>rxjava</artifactId>
<version>1.3.8</version>
</dependency>
2. 编写客户端调用接口
public String testRibbon(){
List<Server> serverList = new ArrayList<>();
serverList.add(new Server("localhost",8081));
serverList.add(new Server("localhost",8082));
ILoadBalancer loadBalancer = LoadBalancerBuilder.newBuilder().buildFixedServerListLoadBalancer(serverList);
for (int i=0;i<5;i++){
String result = LoadBalancerCommand.<String>builder().withLoadBalancer(loadBalancer)
.build().submit(new ServerOperation<String>() {
@Override
public Observable<String> call(Server server) {
try{
String addr = "http://"+server.getHost()+":"+server.getPort()+"/user/hello";
System.out.println("调用地址:"+addr);
URL url = new URL(addr);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestMethod("GET");
httpURLConnection.connect();
InputStream inputStream = httpURLConnection.getInputStream();
byte[] data = new byte[inputStream.available()];
inputStream.read();
return Observable.just(new String(data));
}catch (Exception e){
return Observable.error(e);
}
}
}).toBlocking().first();
System.out.println("调用结果:"+result);
}
return "finish";
}
运行后的结果如下:
调用地址:http://localhost:8082/user/hello
调用结果:hello everyone
调用地址:http://localhost:8081/user/hello
调用结果:hello everyone
调用地址:http://localhost:8082/user/hello
调用结果:hello everyone
调用地址:http://localhost:8081/user/hello
调用结果:hello everyone
调用地址:http://localhost:8082/user/hello
调用结果:hello everyone
根据上面的输入可以看出负载起了作用。
四、RestTemplate 结合Ribbon的使用
1. 引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version> 2.2.2.RELEASE</version>
</dependency>
2. 在RestTemplate的配置上加LoadBalance注解
@Configuration
public class BeanConfiguration {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
3. 接口的调用
@RestController
public class ArticleController {
private final RestTemplate restTemplate;
@Autowired
public ArticleController(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@GetMapping("/article/callhello2")
public String callHello2(){
return restTemplate.getForObject("http://eureka-client-user-service/user/hello",String.class);
}
}
@LoadBalanced作用:给RestTemplate增加拦截器,在请求之前对请求的地址进行替换,或者根据具体的负载均衡的策略选择服务地址,然后再去调用。
五、负载均衡策略
1. BestAvailabl:选择一个最小的并发请求的 Server ,逐个考察 Server ,如果Server标记为错误责跳过,然后再选择ActiveRequestCount中最小的 Server 。
2. AvailabilityFilteringRule:过滤掉那些一直连接失败并且被标记为 circuit tripped的后端 Server ,并过滤掉那些高并发的后端 Server 或者使用一个 AvailabilityPredicate 来包含过滤 Availability 的窥觊,其实就是检查 Status 里记录的各个 Server 的运行状态。
3. ZoneAvoiddanceRule:使用 ZoneAvoiddancePredicate 和AvailabilityPredicate 来判断是否选择某个Server ,前一个判断判定一个Zone的运行性能是否可用,删除不可用的Zone的所有Server,后一个用于过滤连接数过多的Server。
4. RadomRule:随机选择一个Server。
5. RoundRobinRule:轮询选择,轮询index,选择index对应位置的Server
6.RetryRule:对选定的负载均衡策略机上重试机制,也就是说当选定了某个策略进行请求负载时在一个配置时间段内若选择Server不成功,责一直尝试使用 subRule的方式选择一个可用的Server.
7. ResponseTimeWeightedRule:作用同 WeightedResponseTimeRule ,ResponseTimeWeightedRule后来改名为WeightedResponseTimeRule。
8. WeightedResponseTimeRule:根绝相应时间分配一个Weight,相应时间越长 Weight越小,被选中的可能性越低。
六、自定义负载均衡策略
public class MyRule implements IRule {
private ILoadBalancer loadBalancer;
@Override
public Server choose(Object o) {
//主要选择的逻辑都在这个方法里面
List<Server> allServers = loadBalancer.getAllServers();
for (Server server: allServers) {
System.out.println(server.getHost());
}
return allServers.get(0);
}
@Override
public void setLoadBalancer(ILoadBalancer iLoadBalancer) {
this.loadBalancer = loadBalancer;
}
@Override
public ILoadBalancer getLoadBalancer() {
return loadBalancer;
}
}