Ribbon LoadBalanced底层机制源码探秘
🍊 Java学习:社区快速通道
🍊 深入浅出RocketMQ设计思想:深入浅出RocketMQ设计思想
🍊 绝对不一样的职场干货:大厂最佳实践经验指南
📆 最近更新:2023年6月18日
🍊 点赞 👍 收藏 ⭐留言 📝 都是我最大的动力!
文章目录
- 负载均衡器LoadBalancer原理
- Ribbon LoadBalanced底层机制源码探秘
通过本文你可以学习到:
- LoadBalanced作用原理
- 拦截器到Rule的调角链路
- 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方法里被用到
@Bean public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(final ObjectProvider 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 @ConditionalOnMissingBean public RestTemplateCustomizer restTemplateCustomizer(final LoadBalancerInterceptor loadBalancerInterceptor) { return (restTemplate) -> { List list = new ArrayList(restTemplate.getInterceptors()); list.add(loadBalancerInterceptor); restTemplate.setInterceptors(list); }; }
先从restTemplate获取getInterceptors(),接下来list里添加一个loadBalancerInterceptor,它的注入:
@Bean public LoadBalancerInterceptor ribbonInterceptor(LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory) { return new LoadBalancerInterceptor(loadBalancerClient, requestFactory); }
public void setInterceptors(List interceptors) { if (this.interceptors != interceptors) { this.interceptors.clear(); this.interceptors.addAll(interceptors); AnnotationAwareOrderComparator.sort(this.interceptors); } }
这里把 interceptors 和本地保存的做一下比较,如果不一样则本地的interceptors全部清空,然后添加上新的,再sort一下
真正起作用的位置是在LoadBalancerInterceptor的intercept方法上
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException { 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 execute(String serviceId, LoadBalancerRequest request, Object hint) throws IOException { ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId); Server server = this.getServer(loadBalancer, hint); if (server == null) { throw new IllegalStateException("No instances available for " + serviceId); } else { RibbonLoadBalancerClient.RibbonServer ribbonServer = new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server)); return this.execute(serviceId, (ServiceInstance)ribbonServer, (LoadBalancerRequest)request); } }
这里到了真正执行任务的时候了,先根据serviceId获取一个LoadBalancer,拿到负载均衡策略之后用getServer获取到真正的server
protected Server getServer(ILoadBalancer loadBalancer, Object hint) { return loadBalancer == null ? null : loadBalancer.chooseServer(hint != null ? hint : "default"); }
@Override public Server chooseServer(Object key) { if (!ENABLED.get() || getLoadBalancerStats().getAvailableZones().size() logger.debug("Zone aware logic disabled or there is only one zone"); return super.chooseServer(key); } Server server = null; try { LoadBalancerStats lbStats = getLoadBalancerStats(); Map 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 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."); return super.chooseServer(key); } } if (counter == null) { counter = createCounter(); } counter.increment(); if (rule == null) { return null; } else { try { return rule.choose(key); } catch (Exception e) { logger.warn("LoadBalancer [{}]: Error choosing server for key {}", name, key, e); return null; } } }
- LBAutoConfig:从上一步中传送过来的RestTemplate,会经过LBAutoConfig的装配,将一系列的拦截器添加到RestTemplate中。Ribbon拦截器会拦截每个网络请求做一番处理,在这个过程中拦截器会找到对应的LoadBalancer对HTTP请求进行接管,接着LoadBalancer就会找到默认或指定的负载均衡策略来对HTTP请求进行转发。
还没有评论,来说两句吧...