Spring Cloud :2 . Netflix Ribbon
负载均衡
负载均衡分为软件负载均衡和硬件负载均衡:
- 软件负载均衡:nginx,lvs
- 硬件负载均衡:F5
同时软件负载均衡又分为两种:
服务端负载均衡 和 客户端负载均衡。
什么是客户端负载均衡呢?
所谓客户端负载均衡,就是把所有需要被负载的服务IP地址、端口号、服务存放在客户端,客户端在调用的时候,直接定义算法(轮询、随机、权重 …)来对其中一台服务发起调用。
什么是服务端负载均衡呢?
所谓服务端负载均衡,其实就是服务端来维护 服务列表 ,比如Nginx,客户端请求Nginx,由Nginx来做负载均衡 路由到后台服务,但是站在Nginx的角度,Nginx也是客户端。
Ribbon负载均衡
Ribbon是客户端的负载均衡,也是只负责负载均衡的功能(轮询,随机,权重 …),并不提供从Eureka Server中拉取服务列表。服务消费端访问服务 需要三个组件,分别是Eureka Client、Ribbon、RestTemplate(可以使用Feign代替)。 步骤如下:
- 由Eureka Client从Eureka Server中获取服务列表。
- Ribbon从已经获取的服务列表中,根据特定的算法选出一个可用的服务信息。
- RestTemplate根据选出的可用服务信息调用远程服务。
不懂Eureka的优先看:https://blog.youkuaiyun.com/xi_rurensheng/article/details/107143035
简单的调用远程服务
previder端:
@RestController
public class MainController {
@Value("${server.port}")
String port;
@GetMapping("/getport")
public String getPort(){
return port;
}
}
两个previder的端口分别为8080和8081.
consumer端:
注入RestTemplate类:
@Configuration
public class MyConfiguration {
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
Controller :
@RestController
public class MainController {
@Autowired
private LoadBalancerClient lb;
@Autowired
private RestTemplate restTemplate;
@GetMapping("/ribbon")
public Object ribbon(){
//ribbon自动做负载均衡获取到一个实例对象
ServiceInstance choose = lb.choose("eureka-provider");
String host = choose.getHost();
int port = choose.getPort();
String url="http://"+host+":"+port+"/getport";
System.out.println(url);
//远程调用,获得返回结果
String result = restTemplate.getForObject(url, String.class);
return result;
}
}
访问http://localhost:80/ribbon,连续访问,会得到8080和8081的结果。
LoadBalancerClient.choose的源码流程图
轮询策略
根据上面的流程图,可以发现接收负载均衡策略的为 IRule 接口,我们来看一下这个接口的实现实现类有哪些?
默认实现:
- ZoneAvoidanceRule(区域权衡策略):复合判断Server所在区域的性能和Server的可用性,轮询选择服务器。
其他规则:
-
BestAvailableRule(最低并发策略):会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务。逐个找服务,如果断路器打开,则忽略。
-
RoundRobinRule(轮询策略):以简单轮询选择一个服务器。按顺序循环选择一个server。
-
RandomRule(随机策略):随机选择一个服务器。
-
AvailabilityFilteringRule(可用过滤策略):会先过滤掉多次访问故障而处于断路器跳闸状态的服务和过滤并发的连接数量超过阀值得服务,然后对剩余的服务列表安装轮询策略进行访问。
-
WeightedResponseTimeRule(响应时间加权策略):据平均响应时间计算所有的服务的权重,响应时间越快服务权重越大,容易被选中的概率就越高。刚启动时,如果统计信息不中,则使用RoundRobinRule(轮询)策略,等统计的信息足够了会自动的切换到WeightedResponseTimeRule。响应时间长,权重低,被选择的概率低。反之,同样道理。此策略综合了各种因素(网络,磁盘,IO等),这些因素直接影响响应时间。
-
RetryRule(重试策略):先按照RoundRobinRule(轮询)的策略获取服务,如果获取的服务失败则在指定的时间会进行重试,进行获取可用的服务。如多次获取某个服务失败,就不会再次获取该服务。主要是在一个时间段内,如果选择一个服务不成功,就继续找可用的服务,直到超时。
更改轮询策略
注解方式
@Configuration
public class MyConfiguration {
@Bean
public IRule myRule() {
//return new RoundRobinRule();
//return new RandomRule();
//return new RetryRule();
return new RandomRule();
}
}
配置文件方式
针对服务定ribbon策略:
#最前面的eureka-provider表示服务的ID,不固定。
eureka-provider.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
给所有服务定ribbon策略:
ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
改进 简单调用远程服
之前的远程调用,代码内的url是我们自己拼接处来的,比较麻烦,我们可以使用注解的方式,让开发变得更简单。
第一步:
@Bean
@LoadBalanced //添加这个注解,可以使RestTemplate能够解析URL中的服务ID
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
在RestTemplate上添加注解@LoadBalanced。
第二步:
@GetMapping("/ribbon2")
public Object ribbon2(){
//ribbon自动做负载均衡获取到一个实例对象
// ServiceInstance choose = lb.choose("eureka-provider");
// String host = choose.getHost();
// int port = choose.getPort();
// String url="http://"+host+":"+port+"/getport";
String url="http://eureka-provider/getport";
//远程调用,获得返回结果
String result = restTemplate.getForObject(url, String.class);
return result;
}
把之前的URL中的 host 和 port 替换成 服务ID (eureka-provider),然后重启服务,进行访问 http://localhost:80/ribbon2
这篇文章是本人的个人理解,不保证准确性,如果有错误的地方希望大家留言指正,一起学习共同进步!
如果转载请标明出处。谢谢