负载均衡器之DynamicServerListLoadBalancer(一)

912 阅读2分钟

小知识,大挑战!本文正在参与「程序员必备小知识」创作活动

10负载均衡器之DynamicServerListLoadBalancer

DynamicServerListLoadBalancer继承BaseLoadBalancer

  • 实现了服务实例清单在运行期的动态更新能力
  • 对服务实例清单的过滤功能

从Eureka Server中获取服务实例清单

ServerList是个接口,具体实现类是DomainExtractingServerList实例,

EurekaRibbonClientConfiguration

@Bean
@ConditionalOnMissingBean
public ServerList<?> ribbonServerList(IClientConfig config) {
   DiscoveryEnabledNIWSServerList discoveryServerList = new DiscoveryEnabledNIWSServerList(
         config);
   DomainExtractingServerList serverList = new DomainExtractingServerList(
         discoveryServerList, config, this.approximateZoneFromHostname);
   return serverList;
}

这里创建了DomainExtractingServerList,构造方法传入DiscoveryEnabledNIWSServerList,那么DiscoveryEnabledNIWSServerList是如何实现服务实例的获取的?是通过obtainServersViaDiscovery方法:

DiscoveryEnabledNIWSServerList的obtainServersViaDiscovery方法:

@Override
public List<DiscoveryEnabledServer> getInitialListOfServers(){
    return obtainServersViaDiscovery();
}

@Override
public List<DiscoveryEnabledServer> getUpdatedListOfServers(){
    return obtainServersViaDiscovery();
}

private List<DiscoveryEnabledServer> obtainServersViaDiscovery() {
    List<DiscoveryEnabledServer> serverList = new ArrayList<DiscoveryEnabledServer>();

    if (eurekaClientProvider == null || eurekaClientProvider.get() == null) {
        logger.warn("EurekaClient has not been initialized yet, returning an empty list");
        return new ArrayList<DiscoveryEnabledServer>();
    }

    EurekaClient eurekaClient = eurekaClientProvider.get();
    if (vipAddresses!=null){
        for (String vipAddress : vipAddresses.split(",")) {
            // if targetRegion is null, it will be interpreted as the same region of client
            List<InstanceInfo> listOfInstanceInfo = eurekaClient.getInstancesByVipAddress(vipAddress, isSecure, targetRegion);
            for (InstanceInfo ii : listOfInstanceInfo) {
                if (ii.getStatus().equals(InstanceStatus.UP)) {

                    if(shouldUseOverridePort){
                        if(logger.isDebugEnabled()){
                            logger.debug("Overriding port on client name: " + clientName + " to " + overridePort);
                        }

                        // copy is necessary since the InstanceInfo builder just uses the original reference,
                        // and we don't want to corrupt the global eureka copy of the object which may be
                        // used by other clients in our system
                        InstanceInfo copy = new InstanceInfo(ii);

                        if(isSecure){
                            ii = new InstanceInfo.Builder(copy).setSecurePort(overridePort).build();
                        }else{
                            ii = new InstanceInfo.Builder(copy).setPort(overridePort).build();
                        }
                    }

                    DiscoveryEnabledServer des = new DiscoveryEnabledServer(ii, isSecure, shouldUseIpAddr);
                    des.setZone(DiscoveryClient.getZone(ii));
                    serverList.add(des);
                }
            }
            if (serverList.size()>0 && prioritizeVipAddressBasedServers){
                break; // if the current vipAddress has servers, we dont use subsequent vipAddress based servers
            }
        }
    }
    return serverList;
}

这里主要依靠EurekaClient从服务注册中心中获取到具体的服务实例InstanceInfo列表,vipAddress为逻辑上的服务名,对这些服务实例进行遍历,将状态为UP的实例转换成DiscoveryEnabledServer对象,最后将这些实例组织成列表返回。

DiscoveryEnabledNIWSServerList通过EurekaClient从服务注册中心获取到最新的服务实例清单后,返回的List到了DomainExtractingServerList,将继续通过setZones方法处理:

private List<DiscoveryEnabledServer> setZones(List<DiscoveryEnabledServer> servers) {
   List<DiscoveryEnabledServer> result = new ArrayList<>();
   boolean isSecure = this.clientConfig.getPropertyAsBoolean(
         CommonClientConfigKey.IsSecure, Boolean.TRUE);
   boolean shouldUseIpAddr = this.clientConfig.getPropertyAsBoolean(
         CommonClientConfigKey.UseIPAddrForServer, Boolean.FALSE);
   for (DiscoveryEnabledServer server : servers) {
      result.add(new DomainExtractingServer(server, isSecure, shouldUseIpAddr,
            this.approximateZoneFromHostname));
   }
   return result;
}

将DiscoveryEnabledNIWSServerList返回的list列表的元素转换成内部定义的DomainExtractingServer