Spring cloud的Ribbon负载均衡的实现原理

先从Ribbon的自动配置看,LoadBalancerAutoConfiguration。

@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {

    @LoadBalanced
    @Autowired(required = false)
    private List restTemplates = Collections.emptyList();

    @Bean
    public SmartInitializingSingleton loadBalancedRestTemplateInitializer(
            final List customizers) {
        return new SmartInitializingSingleton() {
            @Override
            public void afterSingletonsInstantiated() {
                for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
                    for (RestTemplateCustomizer customizer : customizers) {
                        customizer.customize(restTemplate);
                    }
                }
            }
        };
    }

    @Autowired(required = false)
    private List transformers = Collections.emptyList();

    @Bean
    @ConditionalOnMissingBean
    public LoadBalancerRequestFactory loadBalancerRequestFactory(
            LoadBalancerClient loadBalancerClient) {
        return new LoadBalancerRequestFactory(loadBalancerClient, transformers);
    }

    @Configuration
    @ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
    static class LoadBalancerInterceptorConfig {
        @Bean
        public LoadBalancerInterceptor ribbonInterceptor(
                LoadBalancerClient loadBalancerClient,
                LoadBalancerRequestFactory requestFactory) {
            return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
        }

        @Bean
        @ConditionalOnMissingBean
        public RestTemplateCustomizer restTemplateCustomizer(
                final LoadBalancerInterceptor loadBalancerInterceptor) {
            return new RestTemplateCustomizer() {
                @Override
                public void customize(RestTemplate restTemplate) {
                    List list = new ArrayList<>(
                            restTemplate.getInterceptors());
                    list.add(loadBalancerInterceptor);
                    restTemplate.setInterceptors(list);
                }
            };
        }
    }

    @Configuration
    @ConditionalOnClass(RetryTemplate.class)
    public static class RetryAutoConfiguration {
        @Bean
        public RetryTemplate retryTemplate() {
            RetryTemplate template =  new RetryTemplate();
            template.setThrowLastExceptionOnExhausted(true);
            return template;
        }

        @Bean
        @ConditionalOnMissingBean
        public LoadBalancedRetryPolicyFactory loadBalancedRetryPolicyFactory() {
            return new LoadBalancedRetryPolicyFactory.NeverRetryFactory();
        }
    }

    @Configuration
    @ConditionalOnClass(RetryTemplate.class)
    public static class RetryInterceptorAutoConfiguration {
        @Bean
        @ConditionalOnMissingBean
        public RetryLoadBalancerInterceptor ribbonInterceptor(
                LoadBalancerClient loadBalancerClient, LoadBalancerRetryProperties properties,
                LoadBalancedRetryPolicyFactory lbRetryPolicyFactory,
                LoadBalancerRequestFactory requestFactory) {
            return new RetryLoadBalancerInterceptor(loadBalancerClient, properties,
                    lbRetryPolicyFactory, requestFactory);
        }

        @Bean
        @ConditionalOnMissingBean
        public RestTemplateCustomizer restTemplateCustomizer(
                final RetryLoadBalancerInterceptor loadBalancerInterceptor) {
            return new RestTemplateCustomizer() {
                @Override
                public void customize(RestTemplate restTemplate) {
                    List list = new ArrayList<>(
                            restTemplate.getInterceptors());
                    list.add(loadBalancerInterceptor);
                    restTemplate.setInterceptors(list);
                }
            };
        }
    }
}

ribbonInterceptor方法返回了一个拦截器叫做LoadBalancerInterceptor,这个拦截器的作用主要是在客户端发起请求时进行拦截,进而实现客户端负载均衡功能。restTemplateCustomizer方法返回了一个RestTemplateCustomizer,这个方法主要用来给RestTemplate添加LoadBalancerInterceptor拦截器。restTemplates是一个被@LoadBalanced注解修饰的RestTemplate对象列表,在loadBalancedRestTemplateInitializer方法中通过调用RestTemplateCustomizer中的customizef方法来给RestTemplate添加上LoadBalancerInterceptor拦截器。

可以猜到,拦截器是实现ribbon负载均衡的方式。

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);
        //在这里执行
        return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));
    }
}

跟踪execute方法,进入RibbonLoadBalancerClient类,这个类里有多个execute方法,我们根据参数列表找到对应的方法。

@Override
    public  T execute(String serviceId, LoadBalancerRequest request) throws IOException {
        ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
        //顾名思义,获得服务,继续跟踪这个getServer(loadBalancer)方法
        Server server = getServer(loadBalancer);
        if (server == null) {
            throw new IllegalStateException("No instances available for " + serviceId);
        }
        RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,
                serviceId), serverIntrospector(serviceId).getMetadata(server));

        return execute(serviceId, ribbonServer, request);
    }


protected Server getServer(ILoadBalancer loadBalancer){
        if(loadBalancer == null){
                return null;
        }
        return loadBalancer.chooseServer("default");
}

之后进入BaseLoadBalancer里的chooseServer方法

public Server chooseServer(Object key){
        省略...
        try{
                //根据这个类中对rule变量的定义,rule的默认初始化对象是RoundRobinRule()
                return rule.choose(key);
        }
        省略...
}

可以知道ribbon负载均衡默认采用的是轮询的方式,那轮询的实现方式又是什么呢?

跟踪到PredicateBasedRule类中的choose方法

public Server choose(Object key){
        ...
        Optional server = getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(),key);
        ...
}

跟踪chooseRoundRobinAfterFiltering方法

public Optional chooseRoundRobinAfterFiltering(List servers,Object loadBalancerKey){
        ...
        //nextIndex为访问次数,用访问次数对服务的总数做取余操作完成轮询
        return Optionadl.of(eligible.get(nextIndex.getAndIncrement() % eligible.size()));
}

你可能感兴趣的:(Spring cloud的Ribbon负载均衡的实现原理)