待整理

一、深入探讨 Ribbon

1.1、入口1、RibbonClientConfiguration 看 Ribbon 全局

官方给出的提示

Spring Cloud creates a new ensemble as an ApplicationContext on demand for each named client using RibbonClientConfiguration. This contains (amongst other things) an ILoadBalancer, a RestClient, and a ServerListFilter.

根据 RibbonClientConfiguration 分离相关信息如下。

默认规则接口 (IRule

职责:选择服务器 -> 根据 负载均衡算法,获取的需要调用的服务器 默认实现:ZoneAvoidanceRule

  1. @Bean
  2. @ConditionalOnMissingBean
  3. public IRule ribbonRule(IClientConfig config) {
  4. if (this.propertiesFactory.isSet(IRule.class, name)) {
  5. return this.propertiesFactory.get(IRule.class, config, name);
  6. }
  7. ZoneAvoidanceRule rule = new ZoneAvoidanceRule();
  8. rule.initWithNiwsConfig(config);
  9. return rule;
  10. }

默认 PING 策略(IPing

职责:监测服务器是否存活。 -> 通过 ping 远程服务地址,有响应-存活,无响应-down 默认实现:DummyPing

  1. @Bean
  2. @ConditionalOnMissingBean
  3. public IPing ribbonPing(IClientConfig config) {
  4. if (this.propertiesFactory.isSet(IPing.class, name)) {
  5. return this.propertiesFactory.get(IPing.class, config, name);
  6. }
  7. return new DummyPing();
  8. }

默认 负载均衡器 ILoadBalancer

职责:(通过查看 基础接口:ILoadBalanceraddServers : 增加服务其 chooseServer : 根据关联 key 获取服务器 markServerDown : 标记服务器宕机 getServerList/getReachableServers/getAllServers : 获取服务列表 -> 通过 服务列表 能对 服务列表 进行 各种基础数据的增删改查。 默认实现:ZoneAvoidanceRule

  1. @Bean
  2. @ConditionalOnMissingBean
  3. public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
  4. ServerList<Server> serverList, ServerListFilter<Server> serverListFilter,
  5. IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
  6. if (this.propertiesFactory.isSet(ILoadBalancer.class, name)) {
  7. return this.propertiesFactory.get(ILoadBalancer.class, config, name);
  8. }
  9. return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList,
  10. serverListFilter, serverListUpdater);
  11. }

默认 负载均衡器上下文 LoadBalancerContext

职责: reconstructURIWithServer : 根据 服务信息转化 具体 主机+端口的形式 getServerFromLoadBalancer:获取服务实例(通过 ILoadBalancer 进行获取) 默认实现:RibbonLoadBalancerClient

  1. @Bean
  2. @ConditionalOnMissingBean
  3. public RibbonLoadBalancerContext ribbonLoadBalancerContext(ILoadBalancer loadBalancer,
  4. IClientConfig config, RetryHandler retryHandler) {
  5. return new RibbonLoadBalancerContext(loadBalancer, config, retryHandler);
  6. }

服务列表

职责:初始化,服务列表并获取 默认实现:ConfigurationBasedServerList

  1. @Bean
  2. @ConditionalOnMissingBean
  3. @SuppressWarnings("unchecked")
  4. public ServerList<Server> ribbonServerList(IClientConfig config) {
  5. if (this.propertiesFactory.isSet(ServerList.class, name)) {
  6. return this.propertiesFactory.get(ServerList.class, config, name);
  7. }
  8. ConfigurationBasedServerList serverList = new ConfigurationBasedServerList();
  9. serverList.initWithNiwsConfig(config);
  10. return serverList;
  11. }

小贴士:如果 服务列表 通过 Eureka 来进行 维护的时候,默认实现为:DiscoveryEnabledNIWSServerList

1.2、入口2、 RIbbon 自动 装配 RibbonAutoConfiguration

关注 LoadBalancerClient 负载均衡器客户端 ,代码如下:

  1. @Bean
  2. @ConditionalOnMissingBean(LoadBalancerClient.class)
  3. public LoadBalancerClient loadBalancerClient() {
  4. return new RibbonLoadBalancerClient(springClientFactory());
  5. }

其主要职责 与 Ribbon 的上下文 LoadBalancerContext 的功能职责相似,都是用来进行 服务名称—URL 的转化,以及 服务列表获取服务实例的获取

二、Ribbon 原理总结

通过上述,我们可以知道,Ribbon 其实就是通过维护一个 服务名称IP+端口 的映射列表。使得无需关注 对应 IP + 端口,只要一次配置,就能够在项目中直接通过 服务名称 进行 HTTP 远程服务访问。 Ribbon 还提供了 一些系列的负载均衡算法,进行客户端的负载均衡。 其相关配置信息也存在 其上下文 LoadBalancerContext 中,而通过查看,我们可以得知,其父容器为 ApplicationContext ,可以理解为 其内容仍然存在在 IOC 容器

Ribbon 通过 注解 @LoadBalanced 实现 RestTemplate 负载均衡原理

查看相关配置类 LoadBalancerAutoConfiguration,代码如下:

  1. @Configuration
  2. @ConditionalOnClass({RetryTemplate.class})
  3. public static class RetryInterceptorAutoConfiguration {
  4. public RetryInterceptorAutoConfiguration() {
  5. }
  6. @Bean
  7. @ConditionalOnMissingBean
  8. public RetryLoadBalancerInterceptor ribbonInterceptor(LoadBalancerClient loadBalancerClient, LoadBalancerRetryProperties properties, LoadBalancedRetryPolicyFactory lbRetryPolicyFactory, LoadBalancerRequestFactory requestFactory, LoadBalancedBackOffPolicyFactory backOffPolicyFactory, LoadBalancedRetryListenerFactory retryListenerFactory) {
  9. return new RetryLoadBalancerInterceptor(loadBalancerClient, properties, lbRetryPolicyFactory, requestFactory, backOffPolicyFactory, retryListenerFactory);
  10. }
  11. @Bean
  12. @ConditionalOnMissingBean
  13. public RestTemplateCustomizer restTemplateCustomizer(final RetryLoadBalancerInterceptor loadBalancerInterceptor) {
  14. return new RestTemplateCustomizer() {
  15. public void customize(RestTemplate restTemplate) {
  16. List<ClientHttpRequestInterceptor> list = new ArrayList(restTemplate.getInterceptors());
  17. list.add(loadBalancerInterceptor);
  18. restTemplate.setInterceptors(list);
  19. }
  20. };
  21. }
  22. }

查看 LoadBalancerInterceptor

  1. public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
  2. private LoadBalancerClient loadBalancer;
  3. private LoadBalancerRequestFactory requestFactory;
  4. public LoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerRequestFactory requestFactory) {
  5. this.loadBalancer = loadBalancer;
  6. this.requestFactory = requestFactory;
  7. }
  8. public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
  9. // for backwards compatibility
  10. this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
  11. }
  12. @Override
  13. public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
  14. final ClientHttpRequestExecution execution) throws IOException {
  15. final URI originalUri = request.getURI();
  16. String serviceName = originalUri.getHost();
  17. Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
  18. return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));
  19. }
  20. }

结论

通过查看源码,我们可以很直观的看出来,RibbonRestTemplate 负载均衡的实现,其实是通过 拦截器的方式来做的,也就是在 RestTemplate 触发 请求进入到拦截器中,通过拦截器 中的 loadBalancer ,进行 ServerName -URL 的转化。