负载均衡,英文名称为Load Balance,其含义就是指将负载(工作任务)进行平衡、分摊到多个操作单元上进行运行,例如FTP服务器、Web服务器、企业核心应用服务器和其它主要任务服务器等,从而协同完成工作任务。
主流的负载均衡方案分为两种:一是集中式负载均衡,在消费者和提供者之间使用独立的代理方式进行负载,比如硬件的F5,或软件的Nginx;二是客户端根据自己的请求情况做负载均衡,比如Ribbon。
服务端负载均衡: 比如Nginx,先发送请求,然后通过负载均衡算法,在多个服务器之间进行访问,也就是所谓的在服务器端进行负载均衡算法分配。
客户端负载均衡: 比如Ribbon,spring cloud的客户端会有一个类似注册中心的服务器地址列表,在发送请求前通过负载均衡算法选择一个服务器,然后进行访问,也就是所谓的在客户端就进行负载均衡算法分配。
IRule是所有负载均衡策略的父接口,其中核心方法为choose,用来选择一个服务实例。
AbstractLoadBalancerRule抽象类,通过ILoadBalancer从现有服务器列表中通过均衡策略选择服务器。
在现有服务器之间随机分配流量的负载平衡策略。通过生成一个不大于服务实例总数的随机数选择服务实例。
基本负载均衡策略。通过遍历服务实例,先获取实例总数,如果为0,则会警告负载均衡器没有可用的服务器(No up servers available from load balancer:xxx
);如果实例数大于0,则会生成一个实例总数不断加1的数,取模后选取实例,如果连续十次都没取到实例,则会警告从负载均衡器尝试 10 次后没有可用的活动服务器(No available alive servers after 10 tries from load balancer:xxx
)。
也是轮询机制,只是当轮询到一个已失效或者null的实例后,会在失效时间内进行不断重试,超时后返回null。
会根据每个实例的运行情况计算出权重,默认情况下每30秒会计算一次,服务器的平均响应时间越短则权重越大,那么该实例被选中的概率也会越大。
此规则通常应与ServerListSubsetFilter一起使用,它对规则可见的服务器设置了限制。这确保了它只需要在少量服务器中找到最小的并发请求。此外,每个客户端将获得一个随机的服务器列表,避免了并发请求最低的服务器被大量客户端选择并立即不堪重负的问题。
默认的规则,根据区域和可用性过滤服务器的规则,比如北京和上海的服务器,当你在北京访问时会优先请求北京的服务器。
先过滤掉故障实例,再选择并发较小的实例。过滤规则:由于连续连接或读取失败而处于断路器跳闸状态,或
具有超过可配置限制的活动连接。
Nacos扩展了一个自己的配置,配置中通过spring.cloud.nacos.discovery.weight
设置权重大小。
引入了spring-cloud-starter-alibaba-nacos-discovery就不必再引入ribbon,因为其中依赖了ribbon,点入可看到如下依赖:
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-ribbonartifactId>
<version>2.2.6.RELEASEversion>
<scope>compilescope>
dependency>
用于标记要配置为使用 LoadBalancerClient 的 RestTemplate 或 WebClient bean 的注释。如下为标记RestTemplate,这样在使用restTemplate时会使用当前的负载均衡策略。
package com.xc.order.config;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* @author wyp
*/
@Configuration
public class RestTemplateConfig {
@LoadBalanced
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
}
(1)通过配置类
需要注意的是配置类不能放在@CompentScan能扫描到的地方,否则该配置会被所有服务共享,当定义多种规则的配置类时项目启动报错。所以要创建在扫描不到的地方,用谁取谁。其实也可以不加@Configuration注解,这样放哪儿也就无所谓了。
示例:
先定义两种规则:
①负载均衡策略-随机规则
package com.xc.ribbon;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 负载均衡策略-随机规则
* @author wyp
*/
@Configuration
public class RibbonRandomRuleConfig {
/**
* 方法名必须是iRule
* @return 随机
*/
@Bean
public IRule iRule() {
return new RandomRule();
}
}
②负载均衡策略-随机+权重
package com.xc.ribbon;
import com.alibaba.cloud.nacos.ribbon.NacosRule;
import com.netflix.loadbalancer.IRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 负载均衡策略-随机+权重
* @author wyp
*/
@Configuration
public class RibbonNacosRuleConfig {
/**
* 方法名必须是iRule
* @return nacos 随机+权重
*/
@Bean
public IRule iRule() {
return new NacosRule();
}
}
然后启动类上定义具体的服务使用的规则:
@RibbonClients(value = {
@RibbonClient(name = "A-SERVICE",configuration = RibbonNacosRuleConfig.class)
,@RibbonClient(name = "B-SERVICE",configuration = RibbonRandomRuleConfig.class)
})
意思是A-SERVICE服务下的实例采用RibbonNacosRuleConfig类下设置的规则,B-SERVICE服务下的实例采用RibbonRandomRuleConfig类下设置的规则。
(2)通过配置文件
配置语法为服务名.ribbon.NFLoadBalancerRuleClassName=负载均衡规则的全类名
。
在application.yml中进行以下配置:
# 被调用的微服务名
A-SERVICE:
ribbon:
# 指定负载均衡策略为nacos随机+权重
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule
# 被调用的微服务名
B-SERVICE:
ribbon:
# 指定负载均衡策略为随机
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
只需要继承AbstractLoadBalancerRule类,在choose方法中定义规则,然后通过以上配置类或者配置文件两种方式其中的一种进行配置即可。
示例:
public class MyLoadBalanceRule extends AbstractLoadBalancerRule {
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
public Server choose(Object key) {
ILoadBalancer loadBalancer = this.getLoadBalancer();
//获取当前请求的服务实例
List<Server> reachableServers = loadBalancer.getReachableServers();
//获取具体服务(这里只获取第一台)
Server server = reachableServers.get(0);
//若服务不可用则返回null
if (!server.isAlive()){
return null;
}
return server;
}
}
默认情况下,在第一次服务调用时才加载负载均衡器,如果网络情况不好,容易造成超时。
开启饥饿加载可在项目启动时加载负载均衡器,开启方式为在配置文件中加入如下:
ribbon:
eager-load:
# 开启ribbon饥饿加载
enabled: true
# 配置饥饿加载的服务,多个用逗号隔开
clients: A-SERVICE,B-SERVICE