zoukankan      html  css  js  c++  java
  • Spring Cloud 负载均衡器 Ribbon实现原理(源码分析)

    Ribbon核心工作原理

    1、从前面Ribbon使用(应用间通信方式HTTP和RPC, 负载均衡器 Ribbion),只需要增加LoadBalanced就能实现负载均衡。进入LoadBalanced的源码

     通过注解的注释,我们知道注解标注了RestTemplate作为负载均衡客户端。负载均衡客户端接口为LoadBalancerClient

    2、进入LoadBalancerClient

    /**
     * Represents a client-side load balancer.
     *
     * @author Spencer Gibb
     */
    public interface LoadBalancerClient extends ServiceInstanceChooser {
    
    
    	<T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;
    
    
    	<T> T execute(String serviceId, ServiceInstance serviceInstance,
    			LoadBalancerRequest<T> request) throws IOException;
    
    
    	URI reconstructURI(ServiceInstance instance, URI original);
    
    }
    

      

    LoadBalancerClient继承了ServiceInstanceChooser 接口

    /**
     * Implemented by classes which use a load balancer to choose a server to send a request
     * to.
     */
    public interface ServiceInstanceChooser {
    
    
    	ServiceInstance choose(String serviceId);
    
    }
    

    1) ServiceInstance choose(String serviceId); 该方法主要是根据负载均衡器选择一个服务实例

    2)<T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;

    3)<T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException;

    2) 和 3) 主要是为负载均衡器选择的服务执行请求

    4)URI reconstructURI(ServiceInstance instance, URI original); 构建一个url,该方法主要使用具体逻辑服务名称作为host

    3、LoadBalancerClient接口的实现类为LoadBalancerAutoConfiguration的内部类中

    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnClass({RestTemplate.class}) //当前环境有RestTemplate.class
    @ConditionalOnBean({LoadBalancerClient.class}) //当前环境需要由LoadBalancerClient接口的实现类
    @EnableConfigurationProperties({LoadBalancerRetryProperties.class}) //初始化复制LoadBalancerRetryProperties
    public class LoadBalancerAutoConfiguration {
        @LoadBalanced
        @Autowired(required = false)
        //@AutoWired会自动装载集合类list,会将标注了@LoadBalanced(该注解被@Qualifier注解标注)的RestTemplate添加到restTemplates中
        //
        private List<RestTemplate> restTemplates = Collections.emptyList();
        @Autowired(
            required = false
        )
        private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
     
        public LoadBalancerAutoConfiguration() {
        }
     
        @Bean
        //SmartInitializingSingleton接口的实现类会在项目初始化之后被调用其afterSingletonsInstantiated方法
        public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(final ObjectProvider<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);
                        }
                    }
     
                });
            };
        }
     
        @Bean
        @ConditionalOnMissingBean
        //LoadBalancerRequestFactory被创建
        public LoadBalancerRequestFactory loadBalancerRequestFactory(LoadBalancerClient loadBalancerClient) {
            return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers);
        }
     
        @Configuration(
            proxyBeanMethods = false
        )
        @ConditionalOnClass({RetryTemplate.class})
        public static class RetryInterceptorAutoConfiguration {
            public RetryInterceptorAutoConfiguration() {
            }
     
            @Bean
            @ConditionalOnMissingBean
            public RetryLoadBalancerInterceptor ribbonInterceptor(LoadBalancerClient loadBalancerClient, LoadBalancerRetryProperties properties, LoadBalancerRequestFactory requestFactory, LoadBalancedRetryFactory loadBalancedRetryFactory) {
                return new RetryLoadBalancerInterceptor(loadBalancerClient, properties, requestFactory, loadBalancedRetryFactory);
            }
     
            @Bean
            @ConditionalOnMissingBean
            public RestTemplateCustomizer restTemplateCustomizer(final RetryLoadBalancerInterceptor loadBalancerInterceptor) {
                return (restTemplate) -> {
                    List<ClientHttpRequestInterceptor> list = new ArrayList(restTemplate.getInterceptors());
                    list.add(loadBalancerInterceptor);
                    restTemplate.setInterceptors(list);
                };
            }
        }
     
        @Configuration(
            proxyBeanMethods = false
        )
        @ConditionalOnClass({RetryTemplate.class})
        public static class RetryAutoConfiguration {
            public RetryAutoConfiguration() {
            }
     
            @Bean
            @ConditionalOnMissingBean
            public LoadBalancedRetryFactory loadBalancedRetryFactory() {
                return new LoadBalancedRetryFactory() {
                };
            }
        }
     
        @Configuration( proxyBeanMethods = false )
        @ConditionalOnMissingClass({"org.springframework.retry.support.RetryTemplate"})
        static class LoadBalancerInterceptorConfig {
            LoadBalancerInterceptorConfig() {
            }
     
            @Bean
    	//4、将loadBalancerClient接口的实现类和3方法中创建的LoadBalancerRequestFactory注入到该方法中
    	//同时成为LoadBalancerInterceptor的参数
            public LoadBalancerInterceptor ribbonInterceptor(LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory) {
                return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
            }
     
            @Bean
            @ConditionalOnMissingBean
    	//5、方法4中创建的LoadBalancerInterceptor会被作为参数注入进来
            public RestTemplateCustomizer restTemplateCustomizer(final LoadBalancerInterceptor loadBalancerInterceptor) {
    	    
                return (restTemplate) -> {
    		//5.1 这里会在afterSingletonsInstantiated()遍历调用
                    List<ClientHttpRequestInterceptor> list = new ArrayList(restTemplate.getInterceptors());
                    list.add(loadBalancerInterceptor);
                    restTemplate.setInterceptors(list);
                };
            }
        }
    }
     
    

      

    从注解中可以发现,当前类的加载时机必须存在restTemplate类,并且初始化了LoadBalancerClient的实现类。

    其中LoadBalancerRequestFactory用于创建LoadBalancerRequest供LoaderBalancerInterceptor使用

    LoadBalancerInterceptorConfig中维护了LoadBalancerInterceptor和RestTemplateCustomizer实例。
    LoadBalancerInterceptor拦截每一次HTTP请求,将请求绑定进Ribbon负载均衡生命周期。
    RestTemplateCustomizer为每个RestTemplate绑定LoadBalacerInterceptor

    4、LoadBalacerInterceptor的源码如下:
    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 compatibility
            this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
        }
     
        @Override
        public 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);
    	//真正的执行方法
    	//loadBalancer类型为LoadBalancerClient,LoadBalancerClient默认实现类为RibbonLoadBalancerClient
            return this.loadBalancer.execute(serviceName,
                    this.requestFactory.createRequest(request, body, execution));
        }
     
    }
    
    
    

     RibbonLoadBalancerClient的execute的源码如下

    public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
            return this.execute(serviceId, (LoadBalancerRequest)request, (Object)null);
        }
    
        public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException {
    	//1、根据请求的serviceId来获取具体的LoadBalanced
            ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId);
    	//获得具体server(包括哪台服务器和端口号)
            Server server = this.getServer(loadBalancer, hint);
            if (server == null) {
                throw new IllegalStateException("No instances available for " + serviceId);
            } else {
    	    //执行Http请求
                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);
            }
        }
    
        public <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException {
            Server server = null;
            if (serviceInstance instanceof RibbonLoadBalancerClient.RibbonServer) {
                server = ((RibbonLoadBalancerClient.RibbonServer)serviceInstance).getServer();
            }
    
            if (server == null) {
                throw new IllegalStateException("No instances available for " + serviceId);
            } else {
                RibbonLoadBalancerContext context = this.clientFactory.getLoadBalancerContext(serviceId);
                RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server);
    
                try {
                    T returnVal = request.apply(serviceInstance);
                    statsRecorder.recordStats(returnVal);
                    return returnVal;
                } catch (IOException var8) {
                    statsRecorder.recordStats(var8);
                    throw var8;
                } catch (Exception var9) {
                    statsRecorder.recordStats(var9);
                    ReflectionUtils.rethrowRuntimeException(var9);
                    return null;
                }
            }
        }
    

      

     

    1)首先得到一个ILoadBalancer 。ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId);

    2)然后用它得到一个Server。 Server server = this.getServer(loadBalancer, hint);

        protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
            return loadBalancer == null ? null : loadBalancer.chooseServer(hint != null ? hint : "default");
        }
    

      

    3) ZoneAwareLoadBalancer的chooseServer的代码如下

     public Server chooseServer(Object key) {
            if (this.counter == null) {
                this.counter = this.createCounter();
            }
    
            this.counter.increment();
            if (this.rule == null) {
                return null;
            } else {
                try {
                    return this.rule.choose(key);
                } catch (Exception var3) {
                    logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", new Object[]{this.name, key, var3});
                    return null;
                }
            }
        }
    

      这里的 this.rule.choose(key);其实就是我们定义的IRule



  • 相关阅读:
    shell 脚本判断linux 的发行版本
    notepad++ 正则学习记录
    360 加固分析
    Android的静默安装
    Linux下调整根目录的空间大小
    linux 隐藏权限
    i针对网段开放端口 (命令行设置)
    python 删除文件/夹
    字符串截取
    echo 不换行
  • 原文地址:https://www.cnblogs.com/linlf03/p/12532217.html
Copyright © 2011-2022 走看看