目录
注:Ribbon拦截Eureka请求,找eureka-server拿对应服务信息,根据对应策略返回调用的ip和端口。
一、负载均衡实现逻辑
1、逻辑图
2、ClientHttpRequestInterceptor接口:客户端http请求拦截
3、LoadBalancerInterceptor类实现上面接口
//该方法拦截http请求
@Override
public ClientHttpResponse intercept(final HttpRequest request,final byte[] body,final ClientHttpRequestExecution execution){
//得到请求地址:http://user-service/user/1
final URI originalUri = request.getURI();
//得到服务名user-service
String serciceName=originalUri.getHost();
//RibbonLoadBalancerClient loadBalancer 进入负载均衡客户端
return this.loadBalancer.execute(serviceName,this.requestFactory.createRequest(request,body,execution));
}
4、RibbonLoadBalancerClient类
public <T> T execute(String serviceId,LoadBalancerRequest<T> request,Object hint) throws IOException{
//根据服务名拿到服务信息 DynamicServerListLoadBalancer 动态服务列表负载均衡器
ILoadBalancer loadBalancer=getLoadBalancer(serviceId);
//根据指定策略获取具体服务IP端口
Server server=getServer(loadBalancer,hint);
if(server==null){
throw new IllegalStateException("No instances available for"+serviceId);
}
RibbonServer ribbonServer=new RibbonServer(serviceId,server,isSecure(server,serviceId),serverIntrospector(serviceId).getMetadata(server));
return execute(serviceId,ribbonServer,request);
}
protected Server getServer(ILoadBalancer loadBalancer,Object hint){
if(loadBalancer==null){
return null;
}
return loadBalancer.chooseServer(hint!=null?hint:"default");
}
5、ZoneAwareLoadBalancer类
@Override
public Server chooseServer(Object key){
if(!ENABLED.get()||getLoadBalancerStats().getAvailableZones().size()<=1){
logger.debug("Zone aware logic disabled or there is only one zone");
return super.chooseServer(key);
}
Server server=null;
try{
LoadBalancerStats lbStats=getLoadBalancerStats();
}
}
6、BaseLoadBalancer类
public Server chooseServer(Object key){
if(counter==null){
counter=createCounter();
}
counter.increment();
if(rule==null){
return null;
}else{
try{
//调用IRule规则的实现类得到ip端口
return rule.choose(key);
}catch(Exception e){
logger.warn("LoadBalancer [{}]: Error choosing server for key {}",name,key,e);
return null;
}
}
}
二、负载均衡策略
Ribbon的负载均衡规则是一个叫做IRule的接口来定义的,每一个接口都是一种规则。
1、IRule层级(Eureka的实现类)
- AbstractLoadBalancerRule:策略抽象类
1. RetryRule:重试,重试机制的选择逻辑。
2. ClientConfigEnabledRoundRobinRule:
- BestAvailableRule:最低并发,忽略哪些短路的服务器,并选择并发数较低的服务器。
- PredicateBasedRule:
- AvailabilityFilteringRule:可用过滤,[[#AvailabilityFilteringRule作用]]
- ZoneAvoidanceRule:区域权重,[[#ZoneAvoidanceRule作用]]
3. RoundRobinRule:轮询,简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。
- WeightedResponseTimeRule:[[#WeightedResponseTimeRule作用]]
4. RandomRule:随机,随机选择一个可用的服务器。
2、AvailabilityFilteringRule作用
对以下两种服务器进行忽略:
在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为"短路"状态。短路状态将持续30秒,如果再次连接失败,短路的持续时间就会几何级地增加。
并发数过高的服务器。如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上限,可以由客户端的<clientName>.<clientConfigNameSpace>.ActiveConnectionsLimit属性进行配置。
3、ZoneAvoidanceRule作用
以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房,一个机架等。而后再对Zone内的多个服务做轮询。
4、WeightedResponseTimeRule作用
为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重值会影响服务器的选择。
三、修改负载均衡规则
1、引入依赖包
//eureka-ribbon 负载均衡
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-ribbon:2.2.10.RELEASE'
2、代码方式:在order-service中的OrderApplication类中,定义一个新的IRule
@Bean
public IRule randomRule() {
return new RandomRule();
}
3、 配置文件方式:在order-service的application.yml文件中,添加新的配置也可以修改规则
user-service:
ribbon:
# eureka负载均衡规则
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
# nacos负载均衡规则
# NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule
4、nacos的ribbon策略实现类
四、饥饿加载
Ribbon默认是采用懒加载,即第一次访问时才会去创建LoadBalanceClient,请求时间会很长。而饥饿加载则会在项目启动时创建,降低第一次访问的耗时。
开启饥饿加载
ribbon:
eager-load:
# 开启饥饿加载
enabled: true
clients:
# 指定饥饿加载的服务名称
- user-service