Spring Cloud Ribbon 부하 이퀄 라이저 처리 방법

27517 단어 springcloudribbon
다음은 부하 이퀄 라이저 의 내 부 를 살 펴 보고 서비스 인 스 턴 스 를 어떻게 얻 었 는 지,얻 은 후에 어떤 처 리 를 했 는 지,처리 한 후에 서비스 인 스 턴 스 를 어떻게 선택 하 는 지 살 펴 보 자.
세 부분 으로 나 누 어 훑 기:
설정
서 비 스 를 받다
선택 서비스

  • 배치 하 다.
    이전'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);
     }
    //  
    }
    Zone AwareLoadBalancer 를 실례 화 할 때,config,rule,ping,server List,server List Filter,server List Updater 인 스 턴 스 를 주입 합 니 다.
    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;
     }
     //  
    }
    먼저 Eureka Ribbon Client Configuration 설정 을 사용 한 후 실제 각 인 스 턴 스 가 바 뀌 었 습 니 다.
    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());
     }
    먼저 enableAndInitLearnNewServers Feature 방법 을 호출 하여 정시 업데이트 서비스 목록 을 시작 한 다음,즉시 updateListofServers 함 수 를 호출 하여 서비스 목록 정 보 를 즉시 가 져 오고 업데이트 합 니 다.
    먼저 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);
     }
    이 서비스 목록 의 정보 업데이트 인 스 턴 스 는 설정 단계 에서 설정 한 PollingServerListUpdater 인 스 턴 스 입 니 다.이러한 구조 와 start 방법 을 보 세 요.
    
    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");
     }
     }
     //  
    }
    구조 와 상수 정 의 를 통 해 알 수 있 듯 이 1 초 지연 되 고 기본 값 은 30 초 마다 업 데 이 트 를 실행 하 며 설정 수정 간격 으로 업데이트 할 수 있 습 니 다.
    start 방법 으로 볼 때 정기 적 으로 실행 되 는 schedule 을 열 고 정기 적 으로 updateAction.do Update()를 실행 합 니 다.
    start 방법 호출 자 DynamicServerListLoadBalancer 클래스 로 돌아 가서 UpdateAction 실례 의 정 의 를 보십시오.
    
    protected final ServerListUpdater.UpdateAction updateAction = new ServerListUpdater.UpdateAction() {
     @Override
     public void doUpdate() {
     updateListOfServers();
     }
     };
    실제로 DynamicServerListLoadBalancer 류 의 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);
     }
    1.ServerList 인 스 턴 스 를 통 해 서비스 정보 목록 을 가 져 옵 니 다.
    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;
     }
     //  
    }
    이 를 통 해 알 수 있 듯 이 Eureka 클 라 이언 트 를 통 해 Eureka 서버 에서 모든 서비스 인 스 턴 스 정 보 를 얻 고 온라인 을 Discovery Enabled Server 인 스 턴 스 로 포장 하 며 zone 정 보 를 가지 고 서비스 목록 에 있 습 니 다.
    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;
     }
    }
    getFiltered ListofServers 방법 에서 첫째 는 부모 클래스 를 호출 하 는 동명 의 방법 으로 먼저 필터 링 을 한다.사실 부모 클래스 도 소비 단 과 같은 구역 의 서 비 스 를 필터 링 하여 사용한다.뿐만 아니 라 스마트 한 판정 을 추가 하여 고장/부하 가 비교적 높 거나 실례 가 적 을 때 같은 구역 의 필 터 를 하지 않도록 한다.
    그러나 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;
     }
     //  
    }
    우선 소비 자 와 같은 zone 의 서 비 스 를 걸 러 낸 다음 shouldEnableZone Affinity(filered Servers)를 통 해 같은 zone 의 서 비 스 를 받 아들 일 수 있 는 지,아니면 모든 서 비 스 를 사용 할 수 있 는 지 판단 합 니 다.
    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;
     }
     }
     }
    여기 서 사용 하 는 부하 균형 정책 rule 은 실제 적 으로 Zone AwareLoadBalancer 를 구성 할 때 들 어 오 는 것 으로 설정 단계 에서 생 성 된 Zone Avoidance Rule 정책 인 스 턴 스 입 니 다.   
    
    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);
     }
     }
    설정 이 없 으 면 기본적으로 RoundRobinRule 정책 인 스 턴 스 를 사용 합 니 다.
    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 Avoidance Rule 부하 균형 정책 을 기본적으로 사용 합 니 다.
    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 에서 적당 한 서 비 스 를 선택 할 수 있 습 니 다.

    좋은 웹페이지 즐겨찾기