目录
一、关于负载均衡
负载均衡⼀般分为服务器端负载均衡和客户端负载均衡。区别就是,负载均衡在哪里执行。
1、服务器端负载均衡
⽐如Nginx、F5这些,请求到达服务器之后由这些负载均衡器根据⼀定的算法将请求路由到⽬标服务器处理。
2、客户端负载均衡
⽐如我们要说的Ribbon,服务消费者客户端会有⼀个服务器地址列表,调⽤⽅在请求前通过⼀定的负载均衡算法选择⼀个服务器进⾏访问,负载均衡算法的执⾏是在请求客户端进⾏。
3、Ribbon说明
Ribbon是Netflix发布的负载均衡器。Eureka⼀般配合Ribbon进⾏使⽤,Ribbon利⽤从Eureka中读取到服务信息,在调⽤服务提供者提供的服务时,会根据⼀定的算法进⾏负载。
二、Ribbon应用
(一)将服务提供者-简历微服务,进行集群配置
- 将原有的【lagou-service-resume-8080】项目复制一份,修改相关文件
- 修改application.yml
- 修改启动类名称为:LagouResumeApplication8081
接下来,可以进行负载均衡的配置了
(二)使用Ribbon进行负载均衡
1、配置
不需要引⼊额外的Jar坐标,因为在服务消费者中我们引⼊过eureka-client,它会引⼊Ribbon相关Jar。
如,下面的例子使用RestTemplate+Ribbon
①添加@LoadBalanced注解
在原有基础上,添加【@LoadBalanced】注解即可。
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
②web方法调整
原来的方法
调用使用的是从eureka获取实例,自己通过host和port拼接url,这种方式是我们自己做负载均衡
public Integer findResumeOpenState(@PathVariable Long userId) {
// TODO 从Eureka Server中获取我们关注的那个服务的实例信息以及接口信息
// 1、从 Eureka Server中获取lagou-service-resume服务的实例信息(使用客户端对象做这件事)
List<ServiceInstance> instances = discoveryClient.getInstances("lagou-service-resume");
// 2、如果有多个实例,选择一个使用(负载均衡的过程)
ServiceInstance serviceInstance = instances.get(0);
// 3、从元数据信息获取host port
String host = serviceInstance.getHost();
int port = serviceInstance.getPort();
String url = "http://" + host + ":" + port + "/resume/openstate/" + userId;
System.out.println("===============>>>从EurekaServer集群获取服务实例拼接的url:" + url);
// 调用远程服务—> 简历微服务接口
Integer forObject = restTemplate.getForObject(url, Integer.class);
System.out.println("================>>>调用简历微服务,获取到用户信息" + userId + ";获取到的信息是【" + forObject + "】");
return forObject;
}
改造后的方法
把host和port的拼接去掉,改为传入server实例的名称即可
/**
* 使用Ribbon负载均衡
*
* todo 配合启动类 AutoDeliverApplication 中的RestTemplate实例初始化,其方法上添加的(@LoadBalanced注解)
* @param userId
* @return
*/
@GetMapping("/checkState/{userId}")
public Integer findResumeOpenState(@PathVariable Long userId) {
String serviceName = "LAGOU-SERVICE-RESUME";
String url = "http://" + serviceName + "/resume/openstate/" + userId;
System.out.println("===============>>>从EurekaServer集群获取服务实例拼接的url:" + url);
// 调用远程服务—> 简历微服务接口
Integer forObject = restTemplate.getForObject(url, Integer.class);
System.out.println("================>>>调用简历微服务,获取到用户信息" + userId + ";获取到的信息是【" + forObject + "】");
return forObject;
}
2、测试
本地测试时可以在服务端将返回值改为端口号,便于观察负载均衡情况。
@Value("${server.port}")
private Integer port;
重启项目进行测试
可以看到,已经负载均衡成功。
三、Ribbon负载均衡策略
1、负载均衡策略说明
Ribbon内置了多种负载均衡策略,内部负责复杂均衡的顶级接⼝为com.netflix.loadbalancer.IRule ,类树如下
负载均衡策略 | 描述 |
---|---|
RoundRobinRule:轮询策略 | 默认超过10次获取到的server都不可⽤,会返回⼀个空的server |
RandomRule:随机策略 | 如果随机到的server为null或者不可⽤的话,会while不停的循环选取 |
RetryRule:重试策略 | ⼀定时限内循环重试。默认继承RoundRobinRule,也⽀持⾃定义注⼊,RetryRule会在每次选取之后,对选举的server进⾏判断,是否为null,是否alive,并且在500ms内会不停的选取判断。⽽RoundRobinRule失效的策略是超过10次,RandomRule是没有失效时间的概念,只要serverList没都挂。 |
BestAvailableRule:最⼩连接数策略 | 遍历serverList,选取出可⽤的且连接数最⼩的⼀个server。该算法⾥⾯有⼀个LoadBalancerStats的成员变量,会存储所有server的运⾏状况和连接数。如果选取到的server为null,那么会调⽤RoundRobinRule重新选取。1(1) 2(1)3(1) |
AvailabilityFilteringRule:可⽤过滤策略 | 扩展了轮询策略,会先通过默认的轮询选取⼀个server,再去判断该server是否超时可⽤,当前连接数是否超限,都成功再返回。 |
ZoneAvoidanceRule:区域权衡策略(默认策略) | 扩展了轮询策略,继承了2个过滤器:ZoneAvoidancePredicate和AvailabilityPredicate,除了过滤超时和链接数过多的server,还会过滤掉不符合要求的zone区域⾥⾯的所有节点,AWS --ZONE 在⼀个区域/机房内的服务实例中轮询 |
2、修改负载均衡策略
#针对的被调⽤⽅微服务名称,不加就是全局⽣效
lagou-service-resume:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #负载策略调整
以下是更详细的ribbon配置
#针对的被调用方微服务名称,不加就是全局生效
lagou-service-resume:
ribbon:
#请求连接超时时间
ConnectTimeout: 2000
#请求处理超时时间
##########################################Feign超时时长设置
ReadTimeout: 6000
#对所有操作都进行重试
OkToRetryOnAllOperations: true
####根据如上配置,当访问到故障请求的时候,它会再尝试访问一次当前实例(次数由MaxAutoRetries配置),
####如果不行,就换一个实例进行访问,如果还不行,再换一次实例访问(更换次数由MaxAutoRetriesNextServer配置),
####如果依然不行,返回失败信息。
MaxAutoRetries: 0 #对当前选中实例重试次数,不包括第一次调用
MaxAutoRetriesNextServer: 0 #切换实例的重试次数
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule #负载策略调整