Spring Cloud Ribbon 부하 이퀄 라이저 처리 방법
세 부분 으로 나 누 어 훑 기:
설정
서 비 스 를 받다
선택 서비스
이전'Spring Cloud Ribbon 의 원 리 를 훑어보다'의 설정 부분 에서 볼 수 있 듯 이 기본 부하 균형 기 는 Zone AwareLoadBalancer 입 니 다.
설정 클래스 를 보 세 요.
위치:
spring-cloud-netflix-core-1.3.5.RELEASE.jar
org.springframework.cloud.netflix.ribbon
RibbonClientConfiguration.class
@SuppressWarnings("deprecation")
@Configuration
@EnableConfigurationProperties
//Order is important here, last should be the default, first should be optional
// see https://github.com/spring-cloud/spring-cloud-netflix/issues/2086#issuecomment-316281653
@Import({OkHttpRibbonConfiguration.class, RestClientRibbonConfiguration.class, HttpClientRibbonConfiguration.class})
public class RibbonClientConfiguration {
//  
 @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);
 }
//  
}config:인 스 턴 스 설정.
rule:부하 균형 정책 인 스 턴 스.
ping:ping 인 스 턴 스.
server List:서비스의 인 스 턴 스 를 가 져 오고 업데이트 합 니 다.
server ListFilter:서비스 필터 실례.
server ListUpdater:서비스 목록 정보 업데이트 인 스 턴 스.
@SuppressWarnings("deprecation")
@Configuration
@EnableConfigurationProperties
//Order is important here, last should be the default, first should be optional
// see https://github.com/spring-cloud/spring-cloud-netflix/issues/2086#issuecomment-316281653
@Import({OkHttpRibbonConfiguration.class, RestClientRibbonConfiguration.class, HttpClientRibbonConfiguration.class})
public class RibbonClientConfiguration {
 //  
 @Bean
 @ConditionalOnMissingBean
 public IClientConfig ribbonClientConfig() {
 DefaultClientConfigImpl config = new DefaultClientConfigImpl();
 config.loadProperties(this.name);
 return config;
 }
 @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;
 }
 @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();
 }
 @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;
 }
 @Bean
 @ConditionalOnMissingBean
 public ServerListUpdater ribbonServerListUpdater(IClientConfig config) {
 return new PollingServerListUpdater(config);
 }
 @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);
 }
 @Bean
 @ConditionalOnMissingBean
 @SuppressWarnings("unchecked")
 public ServerListFilter<Server> ribbonServerListFilter(IClientConfig config) {
 if (this.propertiesFactory.isSet(ServerListFilter.class, name)) {
 return this.propertiesFactory.get(ServerListFilter.class, config, name);
 }
 ZonePreferenceServerListFilter filter = new ZonePreferenceServerListFilter();
 filter.initWithNiwsConfig(config);
 return filter;
 }
 @Bean
 @ConditionalOnMissingBean
 public RibbonLoadBalancerContext ribbonLoadBalancerContext(
 ILoadBalancer loadBalancer, IClientConfig config, RetryHandler retryHandler) {
 return new RibbonLoadBalancerContext(loadBalancer, config, retryHandler);
 }
 //  
}config:DefaultClientConfigImpl。
rule:ZoneAvoidanceRule。
ping:DummyPing。
server List:ConfigurationBasedServerList,설정 한 서비스 목록 인 스 턴 스 를 기반 으로 합 니 다.
serverListFilter:ZonePreferenceServerListFilter。
serverListUpdater:PollingServerListUpdater。
주의해 야 할 것 은 여기 서 server List 의 인 스 턴 스 는 ConfigurationBased ServerList 입 니 다.이것 은 Eureka 를 사용 하지 않 았 을 때 서비스 정 보 를 가 져 오 는 인 스 턴 스 입 니 다.설정 파일 에서 가 져 옵 니 다.
그렇다면 유레카 와 함께 사용 할 때 유레카 서버 에서 서비스 정 보 를 얻 으 려 면 어떤 인 스 턴 스 로 이 일 을 해 야 할 까?
Eureka 서 비 스 를 사용 하면 Eureka RibbonClient Configuration 설정 클래스 를 먼저 사용 합 니 다.
위치:
spring-cloud-netflix-eureka-client-1.3.5.RELEASE.jar
org.springframework.cloud.netflix.ribbon.eureka
EurekaRibbonClientConfiguration.class
@Configuration
@CommonsLog
public class EurekaRibbonClientConfiguration {
 //  
 @Bean
 @ConditionalOnMissingBean
 public IPing ribbonPing(IClientConfig config) {
 if (this.propertiesFactory.isSet(IPing.class, serviceId)) {
 return this.propertiesFactory.get(IPing.class, config, serviceId);
 }
 NIWSDiscoveryPing ping = new NIWSDiscoveryPing();
 ping.initWithNiwsConfig(config);
 return ping;
 }
 @Bean
 @ConditionalOnMissingBean
 public ServerList<?> ribbonServerList(IClientConfig config, Provider<EurekaClient> eurekaClientProvider) {
 if (this.propertiesFactory.isSet(ServerList.class, serviceId)) {
 return this.propertiesFactory.get(ServerList.class, config, serviceId);
 }
 DiscoveryEnabledNIWSServerList discoveryServerList = new DiscoveryEnabledNIWSServerList(
 config, eurekaClientProvider);
 DomainExtractingServerList serverList = new DomainExtractingServerList(
 discoveryServerList, config, this.approximateZoneFromHostname);
 return serverList;
 }
 //  
}config:DefaultClientConfigImpl。
rule:ZoneAvoidanceRule。
ping:NIWSDiscoveryPing。
server List:DomainExtracting ServerList,내 부 는 Discovery EnabledNIWSServerList 로 실제 서비스 발견 을 통 해 서비스 정보 목록 을 얻 습 니 다.
serverListFilter:ZonePreferenceServerListFilter。
serverListUpdater:PollingServerListUpdater。
서비스 가 져 오기
서비스 정 보 를 얻 는 입 구 를 찾기 전에 부하 이퀄 라이저 의 클래스 계승 관 계 를 살 펴 보 세 요.
 
 Zone AwareLoadBalancer 의 구조 에서 부모 클래스 DynamicServerListLoadBalancer 구 조 를 호출 하 였 습 니 다.
위치:
ribbon-loadbalancer-2.2.2.jar
com.netflix.loadbalancer
ZoneAwareLoadBalancer.class
DynamicServerListLoadBalancer 의 구조 에서 restOfInit 함 수 를 호출 하 였 습 니 다.
ribbon-loadbalancer-2.2.2.jar
com.netflix.loadbalancer
DynamicServerListLoadBalancer.class
 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());
 }먼저 enableAndInitLearn NewServers Feature 방법 을 살 펴 보 세 요.실제로 서비스 목록 정보 업데이트 인 스 턴 스 를 호출 한 start 방법 으로 정시 업데이트 기능 을 시작 합 니 다.
 /**
 * Feature that lets us add new instances (from AMIs) to the list of
 * existing servers that the LB will use Call this method if you want this
 * feature enabled
 */
 public void enableAndInitLearnNewServersFeature() {
 LOGGER.info("Using serverListUpdater {}", serverListUpdater.getClass().getSimpleName());
 serverListUpdater.start(updateAction);
 }
public class PollingServerListUpdater implements ServerListUpdater {
 //  
 private static long LISTOFSERVERS_CACHE_UPDATE_DELAY = 1000; // msecs;
 private static int LISTOFSERVERS_CACHE_REPEAT_INTERVAL = 30 * 1000; // msecs; 
 //  
 private final AtomicBoolean isActive = new AtomicBoolean(false);
 private volatile long lastUpdated = System.currentTimeMillis();
 private final long initialDelayMs;
 private final long refreshIntervalMs;
 //  
 public PollingServerListUpdater(IClientConfig clientConfig) {
 this(LISTOFSERVERS_CACHE_UPDATE_DELAY, getRefreshIntervalMs(clientConfig));
 }
 public PollingServerListUpdater(final long initialDelayMs, final long refreshIntervalMs) {
 this.initialDelayMs = initialDelayMs;
 this.refreshIntervalMs = refreshIntervalMs;
 }
 @Override
 public synchronized void start(final UpdateAction updateAction) {
 if (isActive.compareAndSet(false, true)) {
 final Runnable wrapperRunnable = new Runnable() {
 @Override
 public void run() {
  if (!isActive.get()) {
  if (scheduledFuture != null) {
  scheduledFuture.cancel(true);
  }
  return;
  }
  try {
  updateAction.doUpdate();
  lastUpdated = System.currentTimeMillis();
  } catch (Exception e) {
  logger.warn("Failed one update cycle", e);
  }
 }
 };
 scheduledFuture = getRefreshExecutor().scheduleWithFixedDelay(
  wrapperRunnable,
  initialDelayMs,
  refreshIntervalMs,
  TimeUnit.MILLISECONDS
 );
 } else {
 logger.info("Already active, no-op");
 }
 }
 //  
}start 방법 으로 볼 때 정기 적 으로 실행 되 는 schedule 을 열 고 정기 적 으로 updateAction.do Update()를 실행 합 니 다.
start 방법 호출 자 DynamicServerListLoadBalancer 클래스 로 돌아 가서 UpdateAction 실례 의 정 의 를 보십시오.
protected final ServerListUpdater.UpdateAction updateAction = new ServerListUpdater.UpdateAction() {
 @Override
 public void doUpdate() {
 updateListOfServers();
 }
 };updateListof Servers 방법 을 계속 보 세 요.
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);
 }2.ServerList Filter 인 스 턴 스 를 통 해 얻 은 서비스 정보 목록 을 필터 합 니 다.
3.걸 러 낸 서비스 정보 목록 을 LoadBalancer Stats 에 저장 하여 상태 로 유지 합 니 다.
다음 에 따로 보 자.
1.ServerList 인 스 턴 스 를 통 해 서비스 정보 목록 을 가 져 옵 니 다.
ServerList 인 스 턴 스 는 설정 단계 에서 생 성 된 DomainExtracting ServerList 입 니 다.서비스 정 보 를 얻 는 것 은 모두 Discovery EnabledNIWSServerList 에 의뢰 합 니 다.
public class DiscoveryEnabledNIWSServerList extends AbstractServerList<DiscoveryEnabledServer>{
 //  
 @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;
 }
 //  
}2.ServerList Filter 인 스 턴 스 를 통 해 얻 은 서비스 정보 목록 을 필터 합 니 다.
server ListFilte 인 스 턴 스 는 설정 단계 에서 생 성 된 Zone Preference ServerListFilter 입 니 다.이 인 스 턴 스 의 getFiltered ListOfServers 방법 을 호출 하여 걸 러 냅 니 다.
@Data
@EqualsAndHashCode(callSuper = false)
public class ZonePreferenceServerListFilter extends ZoneAffinityServerListFilter<Server> {
 private String zone;
 @Override
 public void initWithNiwsConfig(IClientConfig niwsClientConfig) {
 super.initWithNiwsConfig(niwsClientConfig);
 if (ConfigurationManager.getDeploymentContext() != null) {
 this.zone = ConfigurationManager.getDeploymentContext().getValue(
  ContextKey.zone);
 }
 }
 @Override
 public List<Server> getFilteredListOfServers(List<Server> servers) {
 List<Server> output = super.getFilteredListOfServers(servers);
 if (this.zone != null && output.size() == servers.size()) {
 List<Server> local = new ArrayList<Server>();
 for (Server server : output) {
 if (this.zone.equalsIgnoreCase(server.getZone())) {
  local.add(server);
 }
 }
 if (!local.isEmpty()) {
 return local;
 }
 }
 return output;
 }
}그러나 Zone Preference ServerList Filter.getFiltered List of Servers 에 서 는 부모 클래스 가 필 터 를 하지 않 았 더 라 도 같은 zone 의 서 비 스 를 거 르 고 사용 해 야 합 니 다.누가 이 클래스 를 Zone Preference 라 고 부 릅 니까?
이것 은 비교적 기괴 한 부분 으로 부계 의 지능 판정 은 아무런 작용 이 없다 고 느낀다.
Zone Affinity ServerList Filter.getFiltered List of Servers 가 하 는 힘 든 일 을 보 세 요.
public class ZoneAffinityServerListFilter<T extends Server> extends
 AbstractServerListFilter<T> implements IClientConfigAware {
 //  
 private boolean shouldEnableZoneAffinity(List<T> filtered) { 
 if (!zoneAffinity && !zoneExclusive) {
 return false;
 }
 if (zoneExclusive) {
 return true;
 }
 LoadBalancerStats stats = getLoadBalancerStats();
 if (stats == null) {
 return zoneAffinity;
 } else {
 logger.debug("Determining if zone affinity should be enabled with given server list: {}", filtered);
 ZoneSnapshot snapshot = stats.getZoneSnapshot(filtered);
 double loadPerServer = snapshot.getLoadPerServer();
 int instanceCount = snapshot.getInstanceCount(); 
 int circuitBreakerTrippedCount = snapshot.getCircuitTrippedCount();
 if (((double) circuitBreakerTrippedCount) / instanceCount >= blackOutServerPercentageThreshold.get() 
  || loadPerServer >= activeReqeustsPerServerThreshold.get()
  || (instanceCount - circuitBreakerTrippedCount) < availableServersThreshold.get()) {
 logger.debug("zoneAffinity is overriden. blackOutServerPercentage: {}, activeReqeustsPerServer: {}, availableServers: {}", 
  new Object[] {(double) circuitBreakerTrippedCount / instanceCount, loadPerServer, instanceCount - circuitBreakerTrippedCount});
 return false;
 } else {
 return true;
 }
 }
 }
 @Override
 public List<T> getFilteredListOfServers(List<T> servers) {
 if (zone != null && (zoneAffinity || zoneExclusive) && servers !=null && servers.size() > 0){
 List<T> filteredServers = Lists.newArrayList(Iterables.filter(
  servers, this.zoneAffinityPredicate.getServerOnlyPredicate()));
 if (shouldEnableZoneAffinity(filteredServers)) {
 return filteredServers;
 } else if (zoneAffinity) {
 overrideCounter.increment();
 }
 }
 return servers;
 }
 //  
}shouldEnableZone Affinity 방법 에서 같은 zone 의 서비스 에 대해 snapshot 을 한 번 하여 이러한 서비스의 인 스 턴 스 수량,평균 부하,차단 의 인 스 턴 스 수 를 계산 하여 판정 합 니 다.
initWithNiws Config 방법의 관건 적 인 지표의 값 을 볼 수 있 습 니 다.
판정 조건:
차단 실례 백분율>=0.8(차단 실례 수/서비스의 실례 수량)
평균 부하>=0.6
사용 가능 한 인 스 턴 스 수<2(인 스 턴 스 수-차단 인 스 턴 스 수)
판정 조건 에 도달 하면 모든 서 비 스 를 이용 해 가용성 을 확보한다.
그러나 위 에서 도 말 했 듯 이 Zone Preference ServerList Filter 자체 가 항상 소비 단 zone 과 일치 하 는 서 비 스 를 선택 하기 때문에 Zone Affinity ServerList Filter.getFiltered Listof Servers 에서 하 는 스마트 조작 은 소 용이 없다.
단,물론 사용자 정의 설정 을 통 해 Zone Affinity ServerList Filter 인 스 턴 스 를 사용 할 수 있 습 니 다.
3.걸 러 낸 서비스 정보 목록 을 LoadBalancer Stats 에 저장 하여 상태 로 유지 합 니 다.
4.567914.따라 가면 한 걸음 한 걸음 깊이 들 어가 면 실제 적 으로 4.567914 에 저 장 된 것 을 발견 할 수 있 습 니 다.그리고 이때 서 비 스 는 zone 에 따라 조 를 나 누 어 4.567914.구조 로 저 장 된 것 이 고 key 는 zone 입 니 다.
서비스 선택
ILoadBalancer 인터페이스의 부하 균형 기 를 실현 하 였 으 며,chooseServer 방법 을 실현 하여 서 비 스 를 선택 하 였 으 며,선택 한 서 비 스 를 목표 로 서 비 스 를 요청 하 였 습 니 다.
Zone AwareLoadBalancer.choose 서버 방법 을 보 세 요.
@Override
 public Server chooseServer(Object key) {
 if (!ENABLED.get() || getLoadBalancerStats().getAvailableZones().size() <= 1) {
 logger.debug("Zone aware logic disabled or there is only one zone");
 return super.chooseServer(key);
 }
 Server server = null;
 try {
 LoadBalancerStats lbStats = getLoadBalancerStats();
 Map<String, ZoneSnapshot> zoneSnapshot = ZoneAvoidanceRule.createSnapshot(lbStats);
 logger.debug("Zone snapshots: {}", zoneSnapshot);
 if (triggeringLoad == null) {
 triggeringLoad = DynamicPropertyFactory.getInstance().getDoubleProperty(
  "ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".triggeringLoadPerServerThreshold", 0.2d);
 }
 if (triggeringBlackoutPercentage == null) {
 triggeringBlackoutPercentage = DynamicPropertyFactory.getInstance().getDoubleProperty(
  "ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".avoidZoneWithBlackoutPercetage", 0.99999d);
 }
 Set<String> availableZones = ZoneAvoidanceRule.getAvailableZones(zoneSnapshot, triggeringLoad.get(), triggeringBlackoutPercentage.get());
 logger.debug("Available zones: {}", availableZones);
 if (availableZones != null && availableZones.size() < zoneSnapshot.keySet().size()) {
 String zone = ZoneAvoidanceRule.randomChooseZone(zoneSnapshot, availableZones);
 logger.debug("Zone chosen: {}", zone);
 if (zone != null) {
  BaseLoadBalancer zoneLoadBalancer = getLoadBalancer(zone);
  server = zoneLoadBalancer.chooseServer(key);
 }
 }
 } catch (Exception e) {
 logger.error("Error choosing server using zone aware logic for load balancer={}", name, e);
 }
 if (server != null) {
 return server;
 } else {
 logger.debug("Zone avoidance logic is not invoked.");
 return super.chooseServer(key);
 }
 }1.Zone AwareniWSDiscovery LoadBalancer.enabled=false 닫 기 영역 을 설정 하여 부하 균형 을 감지 하거나 zone 의 개수<=1 개 를 감지 합 니 다.
2.구역 감지 또는 zone 의 개수>1 을 사용 합 니 다.
한 명 씩 볼 게 요.
1.Zone AwareniWSDiscovery LoadBalancer.enabled=false 닫 기 영역 을 설정 하여 부하 균형 을 감지 하거나 zone 의 개수<=1 개 를 감지 합 니 다.
이 경우 부모 클래스 BaseLoadBalancer.choose Server 방법 을 호출 했 습 니 다.
public Server chooseServer(Object key) {
 if (counter == null) {
 counter = createCounter();
 }
 counter.increment();
 if (rule == null) {
 return null;
 } else {
 try {
 return rule.choose(key);
 } catch (Exception e) {
 logger.warn("LoadBalancer [{}]: Error choosing server for key {}", name, key, e);
 return null;
 }
 }
 }
public void setRule(IRule rule) {
 if (rule != null) {
 this.rule = rule;
 } else {
 /* default rule */
 this.rule = new RoundRobinRule();
 }
 if (this.rule.getLoadBalancer() != this) {
 this.rule.setLoadBalancer(this);
 }
 }2.구역 감지 또는 zone 의 개수>1 을 사용 합 니 다.
public Server chooseServer(Object key) {
 if (!ENABLED.get() || getLoadBalancerStats().getAvailableZones().size() <= 1) {
 logger.debug("Zone aware logic disabled or there is only one zone");
 return super.chooseServer(key);
 }
 Server server = null;
 try {
 LoadBalancerStats lbStats = getLoadBalancerStats();
 Map<String, ZoneSnapshot> zoneSnapshot = ZoneAvoidanceRule.createSnapshot(lbStats);
 logger.debug("Zone snapshots: {}", zoneSnapshot);
 if (triggeringLoad == null) {
 triggeringLoad = DynamicPropertyFactory.getInstance().getDoubleProperty(
  "ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".triggeringLoadPerServerThreshold", 0.2d);
 }
 if (triggeringBlackoutPercentage == null) {
 triggeringBlackoutPercentage = DynamicPropertyFactory.getInstance().getDoubleProperty(
  "ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".avoidZoneWithBlackoutPercetage", 0.99999d);
 }
 Set<String> availableZones = ZoneAvoidanceRule.getAvailableZones(zoneSnapshot, triggeringLoad.get(), triggeringBlackoutPercentage.get());
 logger.debug("Available zones: {}", availableZones);
 if (availableZones != null && availableZones.size() < zoneSnapshot.keySet().size()) {
 String zone = ZoneAvoidanceRule.randomChooseZone(zoneSnapshot, availableZones);
 logger.debug("Zone chosen: {}", zone);
 if (zone != null) {
  BaseLoadBalancer zoneLoadBalancer = getLoadBalancer(zone);
  server = zoneLoadBalancer.chooseServer(key);
 }
 }
 } catch (Exception e) {
 logger.error("Error choosing server using zone aware logic for load balancer={}", name, e);
 }
 if (server != null) {
 return server;
 } else {
 logger.debug("Zone avoidance logic is not invoked.");
 return super.chooseServer(key);
 }
 }zone 의 snapshot 정 보 를 가 져 옵 니 다.
사용 가능 한 zone 을 가 져 옵 니 다.ZoneAvoidance Rule.getAvailableZones 정 의 를 관찰 한 결과 사용 가능 한 zone 이 아 닌 조건 은:
소속 실례 수==04.567917.고장 률>0.99999 또는 평균 부하<04.567917.위의 두 가지 상황 이 아니라면 부하 가 가장 높 은 하 나 를 선택 하여 사용 할 수 없 는 zone 을 제거 합 니 다.
zone 을 모두 가 져 온 후 무 작위 로 하 나 를 선택 하 십시오.
또한 이 zone 에서 Zone AwareLoadBalancer 의 부모 클래스 BaseLoadBalancer.choose Server 를 통 해 서 비 스 를 선택 합 니 다.위 에서 정 리 했 습 니 다.BaseLoadBalancer 에 rule 이 들 어 오지 않 았 다 면 기본적으로 RoundRobinRule 정책 바퀴 를 사용 하여 서 비 스 를 찾 습 니 다.
사실은 위 에서 서비스 에서 Zone Preference ServerList Filter 필 터 를 가 져 오 는 문제 입 니 다.실제로 걸 러 낸 것 은 소비 자 와 같은 zone 의 서비스 만 있 기 때문에 2.부분의 사용 가능 한 zone 에서 서 비 스 를 선택 하 는 기능 은 가지 못 하고 가 려 면 필 터 를 바 꿔 야 합 니 다.
요약:
설정 한 부하 이퀄 라이저 는 schedule 을 시작 하여 서비스 정 보 를 가 져 옵 니 다.Eureka 클 라 이언 트 를 사용 할 때 Eureka 서비스 에서 모든 서비스 인 스 턴 스 정 보 를 가 져 옵 니 다.필 터 를 통 해 사용 할 수 있 는 서 비 스 를 걸 러 냅 니 다.필 터 는 기본적으로 소비 자 와 같은 zone 의 서비스 만 걸 러 냅 니 다.Zone Affinity ServerList Filter 필 터 를 높 게 설정 하려 면필터 후의 서비스 목록 은 IRule 인터페이스의 부하 균형 전략 을 실현 하여 해당 하 는 서 비 스 를 선택 합 니 다.zone 감지 전략 을 사용 하면 부하 상황 이 좋 은 zone 에서 적당 한 서 비 스 를 선택 할 수 있 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
thymeleaf로 HTML 페이지를 동적으로 만듭니다 (spring + gradle)지난번에는 에서 화면에 HTML을 표시했습니다. 이번에는 화면을 동적으로 움직여보고 싶기 때문에 입력한 문자를 화면에 표시시키고 싶습니다. 초보자의 비망록이므로 이상한 점 등 있으면 지적 받을 수 있으면 기쁩니다! ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.