待整理
一、深入探讨 Ribbon
1.1、入口1、RibbonClientConfiguration 看 Ribbon 全局
Spring Cloud creates a new ensemble as an
ApplicationContexton demand for each named client usingRibbonClientConfiguration. This contains (amongst other things) anILoadBalancer, aRestClient, and aServerListFilter.
根据 RibbonClientConfiguration 分离相关信息如下。
默认规则接口 (IRule)
职责:选择服务器 -> 根据 负载均衡算法,获取的需要调用的服务器 默认实现:ZoneAvoidanceRule
@Bean@ConditionalOnMissingBeanpublic IRule ribbonRule(IClientConfig config) {if (this.propertiesFactory.isSet(IRule.class, name)) {return this.propertiesFactory.get(IRule.class, config, name);}ZoneAvoidanceRule rule = new ZoneAvoidanceRule();rule.initWithNiwsConfig(config);return rule;}
默认 PING 策略(IPing)
职责:监测服务器是否存活。 -> 通过 ping 远程服务地址,有响应-存活,无响应-down 默认实现:DummyPing
@Bean@ConditionalOnMissingBeanpublic IPing ribbonPing(IClientConfig config) {if (this.propertiesFactory.isSet(IPing.class, name)) {return this.propertiesFactory.get(IPing.class, config, name);}return new DummyPing();}
默认 负载均衡器 ILoadBalancer
职责:(通过查看 基础接口:ILoadBalancer) addServers : 增加服务其 chooseServer : 根据关联 key 获取服务器 markServerDown : 标记服务器宕机 getServerList/getReachableServers/getAllServers : 获取服务列表 -> 通过 服务列表 能对 服务列表 进行 各种基础数据的增删改查。 默认实现:ZoneAvoidanceRule
@Bean@ConditionalOnMissingBeanpublic ILoadBalancer ribbonLoadBalancer(IClientConfig config,ServerList<Server> serverList, ServerListFilter<Server> serverListFilter,IRule rule, IPing ping, ServerListUpdater serverListUpdater) {if (this.propertiesFactory.isSet(ILoadBalancer.class, name)) {return this.propertiesFactory.get(ILoadBalancer.class, config, name);}return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList,serverListFilter, serverListUpdater);}
默认 负载均衡器上下文 LoadBalancerContext
职责: reconstructURIWithServer : 根据 服务信息转化 具体 主机+端口的形式 getServerFromLoadBalancer:获取服务实例(通过 ILoadBalancer 进行获取) 默认实现:RibbonLoadBalancerClient
@Bean@ConditionalOnMissingBeanpublic RibbonLoadBalancerContext ribbonLoadBalancerContext(ILoadBalancer loadBalancer,IClientConfig config, RetryHandler retryHandler) {return new RibbonLoadBalancerContext(loadBalancer, config, retryHandler);}
服务列表
职责:初始化,服务列表并获取 默认实现:ConfigurationBasedServerList
@Bean@ConditionalOnMissingBean@SuppressWarnings("unchecked")public ServerList<Server> ribbonServerList(IClientConfig config) {if (this.propertiesFactory.isSet(ServerList.class, name)) {return this.propertiesFactory.get(ServerList.class, config, name);}ConfigurationBasedServerList serverList = new ConfigurationBasedServerList();serverList.initWithNiwsConfig(config);return serverList;}
小贴士:如果 服务列表 通过 Eureka 来进行 维护的时候,默认实现为:DiscoveryEnabledNIWSServerList
1.2、入口2、 RIbbon 自动 装配 RibbonAutoConfiguration
关注 LoadBalancerClient 负载均衡器客户端 ,代码如下:
@Bean@ConditionalOnMissingBean(LoadBalancerClient.class)public LoadBalancerClient loadBalancerClient() {return new RibbonLoadBalancerClient(springClientFactory());}
其主要职责 与 Ribbon 的上下文 LoadBalancerContext 的功能职责相似,都是用来进行 服务名称—URL 的转化,以及 服务列表获取,服务实例的获取
二、Ribbon 原理总结
通过上述,我们可以知道,Ribbon 其实就是通过维护一个 服务名称 和 IP+端口 的映射列表。使得无需关注 对应 IP + 端口,只要一次配置,就能够在项目中直接通过 服务名称 进行 HTTP 远程服务访问。 Ribbon 还提供了 一些系列的负载均衡算法,进行客户端的负载均衡。 其相关配置信息也存在 其上下文 LoadBalancerContext 中,而通过查看,我们可以得知,其父容器为 ApplicationContext ,可以理解为 其内容仍然存在在 IOC 容器中
Ribbon 通过 注解 @LoadBalanced 实现 RestTemplate 负载均衡原理
查看相关配置类 LoadBalancerAutoConfiguration,代码如下:
@Configuration@ConditionalOnClass({RetryTemplate.class})public static class RetryInterceptorAutoConfiguration {public RetryInterceptorAutoConfiguration() {}@Bean@ConditionalOnMissingBeanpublic RetryLoadBalancerInterceptor ribbonInterceptor(LoadBalancerClient loadBalancerClient, LoadBalancerRetryProperties properties, LoadBalancedRetryPolicyFactory lbRetryPolicyFactory, LoadBalancerRequestFactory requestFactory, LoadBalancedBackOffPolicyFactory backOffPolicyFactory, LoadBalancedRetryListenerFactory retryListenerFactory) {return new RetryLoadBalancerInterceptor(loadBalancerClient, properties, lbRetryPolicyFactory, requestFactory, backOffPolicyFactory, retryListenerFactory);}@Bean@ConditionalOnMissingBeanpublic RestTemplateCustomizer restTemplateCustomizer(final RetryLoadBalancerInterceptor loadBalancerInterceptor) {return new RestTemplateCustomizer() {public void customize(RestTemplate restTemplate) {List<ClientHttpRequestInterceptor> list = new ArrayList(restTemplate.getInterceptors());list.add(loadBalancerInterceptor);restTemplate.setInterceptors(list);}};}}
查看 LoadBalancerInterceptor
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {private LoadBalancerClient loadBalancer;private LoadBalancerRequestFactory requestFactory;public LoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerRequestFactory requestFactory) {this.loadBalancer = loadBalancer;this.requestFactory = requestFactory;}public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {// for backwards compatibilitythis(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));}@Overridepublic ClientHttpResponse intercept(final HttpRequest request, final byte[] body,final ClientHttpRequestExecution execution) throws IOException {final URI originalUri = request.getURI();String serviceName = originalUri.getHost();Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));}}
结论:
通过查看源码,我们可以很直观的看出来,Ribbon 对 RestTemplate 负载均衡的实现,其实是通过 拦截器的方式来做的,也就是在 RestTemplate 触发 请求进入到拦截器中,通过拦截器 中的 loadBalancer ,进行 ServerName -URL 的转化。
