Ribbon

Spring Cloud Ribbon 是一个基于HTTP 和 TCP 的客户端负载均衡工具, 它基于 Netflix Ribbon实现. 通过 Spring Cloud 的封装,可以让我们轻松地将面向服务的 REST 模板请求自动转换成客户端负载均衡的服务调用.

1.Rest Template

import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class WebConfig {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(RestTemplateBuilder builder){
        return builder.build();
    }
}

2. 源码分析

2.1 LoadBalanced

/**
 * Annotation to mark a RestTemplate bean to be configured to use a LoadBalancerClient
 * @author Spencer Gibb
 */
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}

负载均衡客户端(LoadBalanceClient)

public interface LoadBalancerClient extends ServiceInstanceChooser {

    /**
     * Copy From org.springframework.cloud.client.loadbalancer.ServiceInstanceChooser
     * Choose a ServiceInstance from the LoadBalancer for the specified service
     */
    ServiceInstance choose(String serviceId);

    /**
     * execute request using a ServiceInstance from the LoadBalancer for the specified service
     * 使用从负载君合器中挑选出的服务实例来执行请求内容
     */
    <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;

    /**
     * execute request using a ServiceInstance from the LoadBalancer for the specified service
     * 使用指定的服务器实例执行请求内容
     */
    <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException;

    /**
     * Create a proper URI with a real host and port for systems to utilize.
     * Some systems use a URI with the logical serivce name as the host,
     * such as http://myservice/path/to/service.  This will replace the
     * service name with the host:port from the ServiceInstance.
     * 为系统构建一个合适的 host:port 形式的 URI
     */
    URI reconstructURI(ServiceInstance instance, URI original);
}

LoadBalancer

被@LoadBalanced 注解修饰的RestTemplate 队列列表,在LoadBalancerAutoConfiguration#loadBalancedRestTemplateInitializerDeprecated初始化, 给客户端负载均衡RestTemplate增加 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 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));
    }

    /**
     * 执行 org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient中的execute方法
     */
    @Override
    public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
        // 通过serviceId获取具体的服务实例
        ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
        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));

        // 执行rest请求
        return execute(serviceId, ribbonServer, request);
    }
}

2.3 负均衡策略

IRule

自动化配置

results matching ""

    No results matching ""