0


Ribbon LoadBalanced底层机制源码探秘

🍊 Java学习:社区快速通道

🍊 深入浅出RocketMQ设计思想:深入浅出RocketMQ设计思想

🍊 绝对不一样的职场干货:大厂最佳实践经验指南

📆 最近更新:2023年6月18日

🍊 点赞 👍 收藏 ⭐留言 📝 都是我最大的动力!


文章目录

通过本文你可以学习到:

  1. LoadBalanced作用原理
  2. 拦截器到Rule的调角链路
  3. IPing机制

负载均衡器LoadBalancer原理

一句话概括:

LoadBalanced

RestTemplate

上打标,Ribbon将带有负载均衡能力的拦截器注入标记好的

RestTemplate

中,以此实现负载均衡。

**从

@LoadBalanced

开始看起:**

它会将

RestTemplate

传送到

Ribbon

的自动装配类里进行改造。

在这里插入图片描述

  • @LoadBalanced:这个注解即修饰RestTemplate,还修饰LoadBalancerAutoConfiguration。它会将所有带有LoadBalanced注解的RestTemplate类,都传入到LoadBalancerAutoConfiguration中。这个注解的定义上还有一个@Qualifier注解,@Qualifier注解搭配@Autowired注解做自动装配,可以通过name属性,将指定的Bean装载到指定位置。

这里

LoadBalanced

也是借助

Qualifier

实现了一个给

RestTemplate

打标的功能,凡是被打标的

RestTemplate

都会被传送到

AutoConfig

中做进一步改造。

  • LBAutoConfig:从上一步中传送过来的RestTemplate,会经过LBAutoConfig的装配,将一系列的拦截器添加到RestTemplate中。Ribbon拦截器会拦截每个网络请求做一番处理,在这个过程中拦截器会找到对应的LoadBalancer对HTTP请求进行接管,接着LoadBalancer就会找到默认或指定的负载均衡策略来对HTTP请求进行转发。

拦截器是类似职责链设计模型的结构,常见的

ServletFilter

,权限控制器等都是类似的模式。

Ribbon LoadBalanced底层机制源码探秘

点进

LoadBalanced

注解,查到

LoadBalancerAutoConfiguration

使用了该注解

请添加图片描述
该注解可以把修饰的

restTemplate

传送到

LoadBalancerAutoConfiguration

这个

restTemplate

只在

loadBalancedRestTemplateInitializerDeprecated

方法里被用到

@BeanpublicSmartInitializingSingletonloadBalancedRestTemplateInitializerDeprecated(finalObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers){return()->{
        restTemplateCustomizers.ifAvailable((customizers)->{Iterator var2 =this.restTemplates.iterator();while(var2.hasNext()){RestTemplate restTemplate =(RestTemplate)var2.next();Iterator var4 = customizers.iterator();while(var4.hasNext()){RestTemplateCustomizer customizer =(RestTemplateCustomizer)var4.next();
                    customizer.customize(restTemplate);}}});};}

循环访问所有的

restTemplate

restTemplateCustomizers

是由外面初始化的bean注入进来的,使用

customizer

restTemplate

做手脚

@Bean@ConditionalOnMissingBeanpublicRestTemplateCustomizerrestTemplateCustomizer(finalLoadBalancerInterceptor loadBalancerInterceptor){return(restTemplate)->{List<ClientHttpRequestInterceptor> list =newArrayList(restTemplate.getInterceptors());
        list.add(loadBalancerInterceptor);
        restTemplate.setInterceptors(list);};}

先从

restTemplate

获取

getInterceptors()

,接下来list里添加一个

loadBalancerInterceptor

,它的注入:

@BeanpublicLoadBalancerInterceptorribbonInterceptor(LoadBalancerClient loadBalancerClient,LoadBalancerRequestFactory requestFactory){returnnewLoadBalancerInterceptor(loadBalancerClient, requestFactory);}
publicvoidsetInterceptors(List<ClientHttpRequestInterceptor> interceptors){if(this.interceptors != interceptors){this.interceptors.clear();this.interceptors.addAll(interceptors);AnnotationAwareOrderComparator.sort(this.interceptors);}}

这里把

interceptors

和本地保存的做一下比较,如果不一样则本地的

interceptors

全部清空,然后添加上新的,再

sort

一下


真正起作用的位置是在

LoadBalancerInterceptor

intercept

方法上

publicClientHttpResponseintercept(finalHttpRequest request,finalbyte[] body,finalClientHttpRequestExecution execution)throwsIOException{URI originalUri = request.getURI();String serviceName = originalUri.getHost();Assert.state(serviceName !=null,"Request URI does not contain a valid hostname: "+ originalUri);return(ClientHttpResponse)this.loadBalancer.execute(serviceName,this.requestFactory.createRequest(request, body, execution));}

先从

url

中得到

uri

,再从

uri

里得到

serviceName

(要去访问的

serviceName

),然后执行

execute

方法

public<T>Texecute(String serviceId,LoadBalancerRequest<T> request,Object hint)throwsIOException{ILoadBalancer loadBalancer =this.getLoadBalancer(serviceId);Server server =this.getServer(loadBalancer, hint);if(server ==null){thrownewIllegalStateException("No instances available for "+ serviceId);}else{RibbonLoadBalancerClient.RibbonServer ribbonServer =newRibbonLoadBalancerClient.RibbonServer(serviceId, server,this.isSecure(server, serviceId),this.serverIntrospector(serviceId).getMetadata(server));returnthis.execute(serviceId,(ServiceInstance)ribbonServer,(LoadBalancerRequest)request);}}

这里到了真正执行任务的时候了,先根据

serviceId

获取一个

LoadBalancer

,拿到负载均衡策略之后用

getServer

获取到真正的

server
protectedServergetServer(ILoadBalancer loadBalancer,Object hint){return loadBalancer ==null?null: loadBalancer.chooseServer(hint !=null? hint :"default");}
@OverridepublicServerchooseServer(Object key){if(!ENABLED.get()||getLoadBalancerStats().getAvailableZones().size()<=1){
        logger.debug("Zone aware logic disabled or there is only one zone");returnsuper.chooseServer(key);}Server server =null;try{LoadBalancerStats lbStats =getLoadBalancerStats();Map<String,ZoneSnapshot> zoneSnapshot =ZoneAvoidanceRule.createSnapshot(lbStats);
        logger.debug("Zone snapshots: {}", zoneSnapshot);if(triggeringLoad ==null){
            triggeringLoad =DynamicPropertyFactory.getInstance().getDoubleProperty("ZoneAwareNIWSDiscoveryLoadBalancer."+this.getName()+".triggeringLoadPerServerThreshold",0.2d);}if(triggeringBlackoutPercentage ==null){
            triggeringBlackoutPercentage =DynamicPropertyFactory.getInstance().getDoubleProperty("ZoneAwareNIWSDiscoveryLoadBalancer."+this.getName()+".avoidZoneWithBlackoutPercetage",0.99999d);}Set<String> availableZones =ZoneAvoidanceRule.getAvailableZones(zoneSnapshot, triggeringLoad.get(), triggeringBlackoutPercentage.get());
        logger.debug("Available zones: {}", availableZones);if(availableZones !=null&&  availableZones.size()< zoneSnapshot.keySet().size()){String zone =ZoneAvoidanceRule.randomChooseZone(zoneSnapshot, availableZones);
            logger.debug("Zone chosen: {}", zone);if(zone !=null){BaseLoadBalancer zoneLoadBalancer =getLoadBalancer(zone);
                server = zoneLoadBalancer.chooseServer(key);}}}catch(Exception e){
        logger.error("Error choosing server using zone aware logic for load balancer={}", name, e);}if(server !=null){return server;}else{
        logger.debug("Zone avoidance logic is not invoked.");returnsuper.chooseServer(key);}}

如果只定义了一个

defaultZone

,则会调用父类的

chooseServer

方法

publicServerchooseServer(Object key){if(counter ==null){
        counter =createCounter();}
    counter.increment();if(rule ==null){returnnull;}else{try{return rule.choose(key);}catch(Exception e){
            logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", name, key, e);returnnull;}}}

这里使用默认的负载均衡策略

RandomRule

回到

RibbonLoadBalancerClient

execute

方法,获取到的服务器不为空则:

RibbonLoadBalancerClient.RibbonServer ribbonServer =newRibbonLoadBalancerClient.RibbonServer(serviceId, server,this.isSecure(server, serviceId),this.serverIntrospector(serviceId).getMetadata(server));returnthis.execute(serviceId,(ServiceInstance)ribbonServer,(LoadBalancerRequest)request);

构建一个

RibbonServer

,最后

execute

就是真正发起请求了

标签: ribbon java spring

本文转载自: https://blog.csdn.net/HNU_Csee_wjw/article/details/124386738
版权归原作者 小王曾是少年 所有, 如有侵权,请联系我们删除。

“Ribbon LoadBalanced底层机制源码探秘”的评论:

还没有评论