主要功能分析:

  Ribbon的负载均衡主要通过LoadBalancerClient来实现的,而LoadBalanceClient具体交给了ILoadBalancer来处理,ILoadBalancer通过配置IRule,IPing等,向EurekaClient获取注册列表的信息,默认每10秒向EurekaClient发送一次,进而检查是否需要更新服务的注册列表信息,最后,在得到服务注册列表后,ILoadBalancer根据IRule的策略进行负载均衡。

  而RestTemplate加上@LoadBalance注解后,在远程调用时能负载均衡,主要是维护了一个被@LoadBalance注解的RestTemplate列表,并给该列表中的RestTemplate对象添加了拦截器,在拦截器的方法中,将远程调度方法交给了Ribbon的负载器LoadBalanceClient去处理,从而实现。

LoadBalanceClient继承了ServiceInstanceChooser,具体实现类为RibbonLoadBalanceClient。

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);
}
public interface ServiceInstanceChooser {

    /**
* Chooses a ServiceInstance from the LoadBalancer for the specified service.
* @param serviceId The service ID to look up the LoadBalancer.
* @return A ServiceInstance that matches the serviceId.
*/
ServiceInstance choose(String serviceId);
}

reconstructURI用于重构URL,choose用于根据serviceID获取ServiceInstance,具体实现

    public ServiceInstance choose(String serviceId, Object hint) {
Server server = getServer(getLoadBalancer(serviceId), hint);
if (server == null) {
return null;
}
return new RibbonServer(serviceId, server, isSecure(server, serviceId),
serverIntrospector(serviceId).getMetadata(server));
}
    protected ILoadBalancer getLoadBalancer(String serviceId) {
return this.clientFactory.getLoadBalancer(serviceId);
}

在RibbonLoadBalancerClient的源码中,交给了ILoadBalancer类去执行,ILoadBalancer是一个接口

public interface ILoadBalancer {
void addServers(List<Server> var1); Server chooseServer(Object var1); void markServerDown(Server var1); /** @deprecated */
@Deprecated
List<Server> getServerList(boolean var1); List<Server> getReachableServers(); List<Server> getAllServers();
}

addServers方法用于添加一个Server集合

chooseServer方法用于根据key去获取Server

markServerDown方法用于标记服务下线

getReachableServer用于获取可用的Server集合

getAllServers用于获取所有server集合

接口继承关系:ILoadBalancer——AbstractLoadBalancer——BaseLoadBalancer——DynamicServerListLoadBalancer

    public DynamicServerListLoadBalancer(IClientConfig clientConfig, IRule rule, IPing ping,
ServerList<T> serverList, ServerListFilter<T> filter,
ServerListUpdater serverListUpdater) {
super(clientConfig, rule, ping);
this.serverListImpl = serverList;
this.filter = filter;
this.serverListUpdater = serverListUpdater;
if (filter instanceof AbstractServerListFilter) {
((AbstractServerListFilter) filter).setLoadBalancerStats(getLoadBalancerStats());
}
restOfInit(clientConfig);
}

DynamicServerListLoadBalancer类实例化的时候需要参数

IClientConfig:用于配置负载均衡的客户端,默认实现类DefaultClientConfigImpl
IRule:用于配置负载均衡的策略,默认是RoundRobinRule,提供了7种实现类

    BestAvailableRule:选择最小请求数

    ClientConfigEnableRoundRobinRule:轮询

    RandomRule:随机选择一个server

    RoundRobinRule:轮询选择server

    RetryRule:根据轮询的方式重试

    WeightedResponseTimeRule:根据响应时间分配权重,权重越低,被选择的可能性越低

    ZoneAvoidanceRule:根据server的zone区域和可用性来轮询选择

IPing:DummyPing
ServerList:ConfigurationBasedServerList
ServerListFilter:ZonePreferenceServerListFilter

DynamicServerListLoadBalancer初始化中有一个restOfInit方法

    void restOfInit(IClientConfig clientConfig) {
boolean primeConnection = this.isEnablePrimingConnections();
// turn this off to avoid duplicated asynchronous priming done in BaseLoadBalancer.setServerList()
this.setEnablePrimingConnections(false);
enableAndInitLearnNewServersFeature(); updateListOfServers();
if (primeConnection && this.getPrimeConnections() != null) {
this.getPrimeConnections()
.primeConnections(getReachableServers());
}
this.setEnablePrimingConnections(primeConnection);
LOGGER.info("DynamicServerListLoadBalancer for client {} initialized: {}", clientConfig.getClientName(), this.toString());
}

中间有一个updateListOfServers方法,该方法用来获取所有的serverList的

    @VisibleForTesting
public void updateListOfServers() {
List<T> servers = new ArrayList<T>();
if (serverListImpl != null) {
servers = serverListImpl.getUpdatedListOfServers();
LOGGER.debug("List of Servers for {} obtained from Discovery client: {}",
getIdentifier(), servers); if (filter != null) {
servers = filter.getFilteredListOfServers(servers);
LOGGER.debug("Filtered List of Servers for {} obtained from Discovery client: {}",
getIdentifier(), servers);
}
}
updateAllServerList(servers);
}

由serverListImpl的实现类DiscoveryEnabledNIWSServerList的getUpdatedListOfServers

    public List<DiscoveryEnabledServer> getUpdatedListOfServers() {
return this.obtainServersViaDiscovery();
} private List<DiscoveryEnabledServer> obtainServersViaDiscovery() {
List<DiscoveryEnabledServer> serverList = new ArrayList();
if (this.eurekaClientProvider != null && this.eurekaClientProvider.get() != null) {
EurekaClient eurekaClient = (EurekaClient)this.eurekaClientProvider.get();
if (this.vipAddresses != null) {
String[] var3 = this.vipAddresses.split(",");
int var4 = var3.length; for(int var5 = 0; var5 < var4; ++var5) {
String vipAddress = var3[var5];
List<InstanceInfo> listOfInstanceInfo = eurekaClient.getInstancesByVipAddress(vipAddress, this.isSecure, this.targetRegion);
Iterator var8 = listOfInstanceInfo.iterator(); while(var8.hasNext()) {
InstanceInfo ii = (InstanceInfo)var8.next();
if (ii.getStatus().equals(InstanceStatus.UP)) {
if (this.shouldUseOverridePort) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding port on client name: " + this.clientName + " to " + this.overridePort);
} InstanceInfo copy = new InstanceInfo(ii);
if (this.isSecure) {
ii = (new Builder(copy)).setSecurePort(this.overridePort).build();
} else {
ii = (new Builder(copy)).setPort(this.overridePort).build();
}
} DiscoveryEnabledServer des = this.createServer(ii, this.isSecure, this.shouldUseIpAddr);
serverList.add(des);
}
} if (serverList.size() > 0 && this.prioritizeVipAddressBasedServers) {
break;
}
}
} return serverList;
} else {
logger.warn("EurekaClient has not been initialized yet, returning an empty list");
return new ArrayList();
}
}

obtainServersViaDiscovery()方法是根据EurekaClientProvider.get来获取EurekaClient,再根据EurekaClient来获取注册列表信息

Ribbon就是从EurekaClient获取服务列表信息的,并根据IRule的策略去路由,根据Iping去判断服务可用性

@LoadBalanced注解

  LoadBalancerAutoConfiguration类

@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration { @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(); @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);
};
}
}

首先维护了一个被@LoadBalanced修饰的RestTemplate对象的list,在初始化的过程中,通过调用customizer.customize(restTemplate)方法来给RestTemplate增加拦截器LoadBalancerInterceptor。

    @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));
}

最新文章

  1. 【python】实践中的总结——列表『持续更新中』
  2. SQL Server 2012 配置数据库邮件
  3. PAT1025. PAT Ranking
  4. action属性
  5. iOS-APP中添加启动界面
  6. POJ 1330 Nearest Common Ancestors(求最近的公共祖先)
  7. Spring MVC 解读——@Autowired(转)
  8. 微信小程序环境搭建
  9. EF连接MySQL数据Web.Config配置
  10. weblogic-部署web应用
  11. codeforces960G. Bandit Blues
  12. Linux三剑客-SED
  13. cordova最小化app插件的使用: cordova-plugin-appminimize
  14. LCA转换成RMQ
  15. rownum和分析函数 over
  16. 一篇文章让你读懂iOS和Android的历史起源
  17. Servlet会话管理二(Cookie)
  18. vagrant特性——基于docker开发环境(docker和vagrant的结合)-3-boxes和配置
  19. 51Nod 1287 加农炮 (线段树)
  20. IIS7配置伪静态把后缀名映射为html方案

热门文章

  1. 6.navicat for mysql 定时计划 定时导出EXCEL文件 并 附件发送邮件到固定邮箱
  2. 51电子-STC89C51开发板:程序烧录(刷写) 到 IC 设置
  3. ES6-Class类上
  4. [vsCode]Visual Studio Code左侧导航栏图标丢失
  5. springcloud(五) - 网关gateway
  6. mysql 导入问题排查
  7. yolov5查看训练日志图片和直方图(包括稀疏训练bn直方图)
  8. cookie、session入门
  9. Django Cannot assign &quot;A1&quot;: &quot;B1&quot; must be a &quot;C1&quot; instance.
  10. Access to the path &#39;C:\Windows\TEMP\XXX.tmp&#39; is denied.