Ribbon核心工作原理

Ribbon核心工作原理

1.Ribbon的核心接口

接口 描述 默认实现
IClientConfig 定义 Ribbon 中管理配置的接口 DefaultClientConfiglmpl
IRule 定义 Ribbon 中负载均衡策略的接口 ZoneAvoidanceRule
IPing 定义定期 ping 服务检查可用性的接口 DummyPing
ServerList 定义获取服务列表方法的接口 ConfigurationBasedServerList
ServerListFilter 定义特定期望获取服务列表方法的接口 ZonePreferenceServerListFilter
ILoadBalancer 定义负载均衡选择服务的核心方法的接口 ZoneAwareLoadBalancer
ServerListUpdater 为 DynamicServerListLoadBalancer 定义动态 更新
服务列表的接口
PollingServerListUpdater

2.LoadBalancerClient-负载均衡的基石

/**
 * Represents a client side load balancer
 * @author Spencer Gibb
 */
public interface LoadBalancerClient extends ServiceInstanceChooser {
	// 使用来自LoadBalancer的ServiceInstance对指定对象执行请求
	<T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;
	// 使用来自LoadBalancer的ServiceInstance对指定对象执行请求
	<T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException;
	// 使用真实的主机和端口创建适当的URI
	URI reconstructURI(ServiceInstance instance, URI original);
}
public interface ServiceInstanceChooser {

    /**从LoadBalancer中为指定服务选择一个ServiceInstance
     * Choose a ServiceInstance from the LoadBalancer for the specified service
     */
    ServiceInstance choose(String serviceId);
}

这两个类奠定了从负载均衡器中选取服务实例,用服务实例构建真实服务地址,以及发送请求的底层架构基础。

3.LoadBalancerAutoConfiguration-负载均衡配置的自动装配

@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
    /***
    *从类的注解就可以看出,它配置加载的时机一是当前工程环境必须有 RestTemplate 的实 例,
二是在工程环境中必须初始化了 LoadBalancerClient 的实现类
    **/
	@LoadBalanced
	@Autowired(required = false)
	private List<RestTemplate> restTemplates = Collections.emptyList();

	@Bean
	public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
			final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
		return () -> restTemplateCustomizers.ifAvailable(customizers -> {
            for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
                for (RestTemplateCustomizer customizer : customizers) {
                    customizer.customize(restTemplate);
                }
            }
        });
	}

	@Autowired(required = false)
	private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
	/**
	*LoadBalancerRequestFactory 用于创建 LoadBalancerRequest和LoadBalancerlnterceptor 使用,它在低版本中是没有的.LoadBalancerInterceptorConfig 中 则 维 护 了 Load- Balancerinterceptor 与RestTemplateCustomizer 的实例 , 它们的作用如下:
	□ LoadBalancerlnterceptor : 拦截每一次 HTTP 请求,将请求绑定进 Ribbon 负载均衡的 生命周期。
	□ RestTemplateCustomizer: 为每个 RestTemplate 绑定 LoadBalancerlnterceptor 拦截器。
	**/
	@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 restTemplate -> {
                List<ClientHttpRequestInterceptor> list = new ArrayList<>(
                        restTemplate.getInterceptors());
                list.add(loadBalancerInterceptor);
                restTemplate.setInterceptors(list);
            };
		}
	}
......
}

在这里就很明确了,通过 loadBalancerClient生成 LoadBalancerInterceptor并为每个 RestTemplate 绑定 LoadBalancerlnterceptor 拦截器。

4.LoadBalancerInterceptor-负载均衡拦截器

public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {

	private LoadBalancerClient loadBalancer;
	private LoadBalancerRequestFactory requestFactory;

.....
    // 执行拦截器
	@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));
	}
}

利用 ClientHttpRequestlnterceptor 来对每次 HTTP 请求进行拦截的,此类是 Spring 中维护的请求拦截器,实现它的 intercept 方法就可以使请求进入方法体,从而做一些处 理。可以看出这里把请求拦截下来之后使用了 LoadBalancerClientexecute 方法来处理请求,由于我 们在 RestTemplate 中使用的 URI 是形如 http://myservice/path/to/service 的,所以这里的 getHost() 方法实 际 取 到 的 就 是 服 务 名 myservice。LoadBalancerClient 接 口 只 有 一 个 实 现 类 , 即RibbonLoadBalancerClient

4.RibbonLoadBalancerClient-Ribbon的负载均衡实现

public class RibbonLoadBalancerClient implements LoadBalancerClient {
.....
    @Override
	public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
    	// 获取具体的服务实例 就是根基服务的实例名字获取服务的相关元数据信息
		ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
    	// Server 就是具体服务实例的封装 
    	// 就是发生负载均衡过程的地方
		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"); // default 就是默认的负载均衡算法的key
	}
    /********************************非本类的实现********************************/
     public Server chooseServer(Object key) {
        if (counter == null) {
            counter = createCounter();
        }
        counter.increment();
        if (rule == null) {
            return null;
        } else {
            try { 
                // 我们发现, rule.choose(key) 中的 rule 其实就是 IRule, 至此,拦截的HTTP 请求与负载均 衡策略得以关联起来
                return rule.choose(key);
            } catch (Exception e) {
                logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", name, key, e);
                return null;
            }
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章