待整理
一、深入探讨 Ribbon
1.1、入口1、RibbonClientConfiguration 看 Ribbon 全局
Spring Cloud creates a new ensemble as an
ApplicationContext
on demand for each named client usingRibbonClientConfiguration
. This contains (amongst other things) anILoadBalancer
, aRestClient
, and aServerListFilter
.
根据 RibbonClientConfiguration
分离相关信息如下。
默认规则接口 (IRule)
职责:选择服务器 -> 根据 负载均衡算法,获取的需要调用的服务器 默认实现:ZoneAvoidanceRule
@Bean
@ConditionalOnMissingBean
public IRule ribbonRule(IClientConfig config) {
if (this.propertiesFactory.isSet(IRule.class, name)) {
return this.propertiesFactory.get(IRule.class, config, name);
}
ZoneAvoidanceRule rule = new ZoneAvoidanceRule();
rule.initWithNiwsConfig(config);
return rule;
}
默认 PING 策略(IPing)
职责:监测服务器是否存活。 -> 通过 ping 远程服务地址,有响应-存活,无响应-down 默认实现:DummyPing
@Bean
@ConditionalOnMissingBean
public IPing ribbonPing(IClientConfig config) {
if (this.propertiesFactory.isSet(IPing.class, name)) {
return this.propertiesFactory.get(IPing.class, config, name);
}
return new DummyPing();
}
默认 负载均衡器 ILoadBalancer
职责:(通过查看 基础接口:ILoadBalancer) addServers : 增加服务其 chooseServer : 根据关联 key 获取服务器 markServerDown : 标记服务器宕机 getServerList/getReachableServers/getAllServers : 获取服务列表 -> 通过 服务列表 能对 服务列表 进行 各种基础数据的增删改查。 默认实现:ZoneAvoidanceRule
@Bean
@ConditionalOnMissingBean
public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
ServerList<Server> serverList, ServerListFilter<Server> serverListFilter,
IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
if (this.propertiesFactory.isSet(ILoadBalancer.class, name)) {
return this.propertiesFactory.get(ILoadBalancer.class, config, name);
}
return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList,
serverListFilter, serverListUpdater);
}
默认 负载均衡器上下文 LoadBalancerContext
职责: reconstructURIWithServer : 根据 服务信息转化 具体 主机+端口的形式 getServerFromLoadBalancer:获取服务实例(通过 ILoadBalancer 进行获取) 默认实现:RibbonLoadBalancerClient
@Bean
@ConditionalOnMissingBean
public RibbonLoadBalancerContext ribbonLoadBalancerContext(ILoadBalancer loadBalancer,
IClientConfig config, RetryHandler retryHandler) {
return new RibbonLoadBalancerContext(loadBalancer, config, retryHandler);
}
服务列表
职责:初始化,服务列表并获取 默认实现:ConfigurationBasedServerList
@Bean
@ConditionalOnMissingBean
@SuppressWarnings("unchecked")
public ServerList<Server> ribbonServerList(IClientConfig config) {
if (this.propertiesFactory.isSet(ServerList.class, name)) {
return this.propertiesFactory.get(ServerList.class, config, name);
}
ConfigurationBasedServerList serverList = new ConfigurationBasedServerList();
serverList.initWithNiwsConfig(config);
return serverList;
}
小贴士:如果 服务列表 通过 Eureka 来进行 维护的时候,默认实现为:DiscoveryEnabledNIWSServerList
1.2、入口2、 RIbbon 自动 装配 RibbonAutoConfiguration
关注 LoadBalancerClient 负载均衡器客户端 ,代码如下:
@Bean
@ConditionalOnMissingBean(LoadBalancerClient.class)
public LoadBalancerClient loadBalancerClient() {
return new RibbonLoadBalancerClient(springClientFactory());
}
其主要职责 与 Ribbon 的上下文 LoadBalancerContext 的功能职责相似,都是用来进行 服务名称—URL 的转化,以及 服务列表获取,服务实例的获取
二、Ribbon 原理总结
通过上述,我们可以知道,Ribbon 其实就是通过维护一个 服务名称 和 IP+端口 的映射列表。使得无需关注 对应 IP + 端口,只要一次配置,就能够在项目中直接通过 服务名称 进行 HTTP 远程服务访问。 Ribbon 还提供了 一些系列的负载均衡算法,进行客户端的负载均衡。 其相关配置信息也存在 其上下文 LoadBalancerContext 中,而通过查看,我们可以得知,其父容器为 ApplicationContext ,可以理解为 其内容仍然存在在 IOC 容器中
Ribbon 通过 注解 @LoadBalanced 实现 RestTemplate 负载均衡原理
查看相关配置类 LoadBalancerAutoConfiguration,代码如下:
@Configuration
@ConditionalOnClass({RetryTemplate.class})
public static class RetryInterceptorAutoConfiguration {
public RetryInterceptorAutoConfiguration() {
}
@Bean
@ConditionalOnMissingBean
public RetryLoadBalancerInterceptor ribbonInterceptor(LoadBalancerClient loadBalancerClient, LoadBalancerRetryProperties properties, LoadBalancedRetryPolicyFactory lbRetryPolicyFactory, LoadBalancerRequestFactory requestFactory, LoadBalancedBackOffPolicyFactory backOffPolicyFactory, LoadBalancedRetryListenerFactory retryListenerFactory) {
return new RetryLoadBalancerInterceptor(loadBalancerClient, properties, lbRetryPolicyFactory, requestFactory, backOffPolicyFactory, retryListenerFactory);
}
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(final RetryLoadBalancerInterceptor loadBalancerInterceptor) {
return new RestTemplateCustomizer() {
public void customize(RestTemplate restTemplate) {
List<ClientHttpRequestInterceptor> list = new ArrayList(restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
}
};
}
}
查看 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));
}
}
结论:
通过查看源码,我们可以很直观的看出来,Ribbon 对 RestTemplate 负载均衡的实现,其实是通过 拦截器的方式来做的,也就是在 RestTemplate 触发 请求进入到拦截器中,通过拦截器 中的 loadBalancer ,进行 ServerName -URL 的转化。