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);
}
//
}
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 에서 적당 한 서 비 스 를 선택 할 수 있 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
thymeleaf로 HTML 페이지를 동적으로 만듭니다 (spring + gradle)지난번에는 에서 화면에 HTML을 표시했습니다. 이번에는 화면을 동적으로 움직여보고 싶기 때문에 입력한 문자를 화면에 표시시키고 싶습니다. 초보자의 비망록이므로 이상한 점 등 있으면 지적 받을 수 있으면 기쁩니다! ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.