簡要
在深入理解Eureka Server覆蓋狀態(tài)(九)這一篇文章中,我們介紹了Eureka Server的覆蓋狀態(tài),但是覆蓋狀態(tài)設(shè)置了之后
Eureka在使用的時(shí)候都會通過getOverriddenInstanceStatus()這個(gè)方法來計(jì)算實(shí)例的最終狀態(tài),那么他計(jì)算的規(guī)則是
什么呢,本篇文章主要講的就是這個(gè)。
代碼回顧
在注冊的時(shí)候,計(jì)算實(shí)例的最終狀態(tài)的代碼如下,
public void register(InstanceInfo registrant, int leaseDuration, boolean isReplication) {
try {
// .....省略N多代碼
// 判斷instance的的覆蓋狀態(tài)是否等于UNKONW (默認(rèn)狀態(tài)下就是等于UNKONW)
if (!InstanceStatus.UNKNOWN.equals(registrant.getOverriddenStatus())) {
// 如果不等于,則說明被修改過,放入overriddenInstanceStatusMap
logger.debug("Found overridden status {} for instance {}. Checking to see if needs to be add to the "
+ "overrides", registrant.getOverriddenStatus(), registrant.getId());
if (!overriddenInstanceStatusMap.containsKey(registrant.getId())) {
logger.info("Not found overridden id {} and hence adding it", registrant.getId());
overriddenInstanceStatusMap.put(registrant.getId(), registrant.getOverriddenStatus());
}
}
// overriddenInstanceStatusMap 里面是否存在這個(gè)instanceId的覆蓋狀態(tài)
InstanceStatus overriddenStatusFromMap = overriddenInstanceStatusMap.get(registrant.getId());
// 如果存在,則設(shè)置進(jìn)去
if (overriddenStatusFromMap != null) {
logger.info("Storing overridden status {} from map", overriddenStatusFromMap);
registrant.setOverriddenStatus(overriddenStatusFromMap);
}
//計(jì)算實(shí)例的最終狀態(tài)。
InstanceStatus overriddenInstanceStatus = getOverriddenInstanceStatus(registrant, existingLease, isReplication);
registrant.setStatusWithoutDirty(overriddenInstanceStatus);
// .....省略N多代碼
} finally {
read.unlock();
}
}
說明:
由上面的代碼可以很清晰的看出,在Eureka注冊時(shí)候,先對覆蓋狀態(tài)做了一系列判斷,對是否擁有覆蓋狀態(tài)做了初始化,
如果有,則設(shè)置覆蓋狀態(tài), 最終調(diào)用了getOverriddenInstanceStatus來計(jì)算實(shí)例的最終狀態(tài)
protected InstanceInfo.InstanceStatus getOverriddenInstanceStatus(InstanceInfo r,
Lease<InstanceInfo> existingLease,
boolean isReplication) {
// 獲取匹配規(guī)則
InstanceStatusOverrideRule rule = getInstanceInfoOverrideRule();
// 規(guī)則匹配
return rule.apply(r, existingLease, isReplication).status();
}
獲取匹配規(guī)則 : getInstanceInfoOverrideRule()的實(shí)現(xiàn)在AbstractInstanceRegistry的子類PeerAwareInstanceRegistryImpl里面。
@Inject
public PeerAwareInstanceRegistryImpl(
EurekaServerConfig serverConfig,
EurekaClientConfig clientConfig,
ServerCodecs serverCodecs,
EurekaClient eurekaClient
) {
super(serverConfig, clientConfig, serverCodecs);
this.eurekaClient = eurekaClient;
this.numberOfReplicationsLastMin = new MeasuredRate(1000 * 60 * 1);
// 設(shè)置狀態(tài)匹配規(guī)則。
this.instanceStatusOverrideRule = new FirstMatchWinsCompositeRule(new DownOrStartingRule(),
new OverrideExistsRule(overriddenInstanceStatusMap), new LeaseExistsRule());
}
@Override
protected InstanceStatusOverrideRule getInstanceInfoOverrideRule() {
return this.instanceStatusOverrideRule;
}
在PeerAwareInstanceRegistryImpl這個(gè)類加載的時(shí)候,設(shè)置了狀態(tài)的匹配規(guī)則(FirstMatchWinsCompositeRule ),同時(shí)
傳入了三個(gè)參數(shù),
DownOrStartingRule,
OverrideExistsRule, (傳入了覆蓋狀態(tài)的緩存MAP)
LeaseExistsRule
接下來直接看這個(gè)類的代碼即可。
FirstMatchWinsCompositeRule
public FirstMatchWinsCompositeRule(InstanceStatusOverrideRule... rules) {
// 將 傳入的規(guī)則實(shí)例匹配給rules
this.rules = rules;
// 設(shè)置默認(rèn)的匹配規(guī)則
this.defaultRule = new AlwaysMatchInstanceStatusRule();
// 循環(huán)得到匹配規(guī)則的名字
List<String> ruleNames = new ArrayList<>(rules.length+1);
for (int i = 0; i < rules.length; ++i) {
ruleNames.add(rules[i].toString());
}
ruleNames.add(defaultRule.toString());
compositeRuleName = ruleNames.toString();
}
// 具體匹配狀態(tài)的方法,主要是講這三個(gè)方法。
@Override
public StatusOverrideResult apply(InstanceInfo instanceInfo,
Lease<InstanceInfo> existingLease,
boolean isReplication) {
for (int i = 0; i < this.rules.length; ++i) {
// 調(diào)用具體規(guī)則匹配狀態(tài),其實(shí)就是構(gòu)造方法里面?zhèn)魅氲哪侨齻€(gè)規(guī)則
StatusOverrideResult result = this.rules[i].apply(instanceInfo, existingLease, isReplication);
// 匹配成功,則返回
if (result.matches()) {
return result;
}
}
// 如果以上都沒有匹配成功,則使用該規(guī)則進(jìn)行匹配
return defaultRule.apply(instanceInfo, existingLease, isReplication);
}
說明:
在apply方法里面,循環(huán)調(diào)用rules的apply方法,直到匹配成功 。 通過PeerAwareInstanceRegistryImpl類中創(chuàng)建FirstMatchWinsCompositeRule
對象的代碼,我們可以知道,具體的匹配規(guī)則有三個(gè),加上默認(rèn)的匹配規(guī)則,也就是有四個(gè),他們分別是:
按執(zhí)行順序排:
DownOrStartingRule,
OverrideExistsRule, (傳入了覆蓋狀態(tài)的緩存MAP)
LeaseExistsRule
AlwaysMatchInstanceStatusRule
DownOrStartingRule
public StatusOverrideResult apply(InstanceInfo instanceInfo,
Lease<InstanceInfo> existingLease,
boolean isReplication) {
// ReplicationInstance is DOWN or STARTING - believe that, but when the instance says UP, question that
// The client instance sends STARTING or DOWN (because of heartbeat failures), then we accept what
// the client says. The same is the case with replica as well.
// The OUT_OF_SERVICE from the client or replica needs to be confirmed as well since the service may be
// currently in SERVICE
if ((!InstanceInfo.InstanceStatus.UP.equals(instanceInfo.getStatus()))
&& (!InstanceInfo.InstanceStatus.OUT_OF_SERVICE.equals(instanceInfo.getStatus()))) {
logger.debug("Trusting the instance status {} from replica or instance for instance {}",
instanceInfo.getStatus(), instanceInfo.getId());
return StatusOverrideResult.matchingStatus(instanceInfo.getStatus());
}
return StatusOverrideResult.NO_MATCH;
}
從類名上理解,這個(gè)類就是負(fù)責(zé)處理 DOWN,STRATING這兩個(gè)狀態(tài)匹配的, 從上面的apply代碼上來看,如果instanceInfo的狀態(tài)不等于UP
同時(shí)也不等于OUT_OF_SERVICE , 那么就就匹配成功,其實(shí)說白了,不等于UP和OUT_OF_SERVICE , 其實(shí)也就是等于DOWN和STRATING。
如果匹配成功,則返回instance的狀態(tài),匹配成功。
PS: instanceInfo 為客戶端傳過來的,也就說客戶端說DOWN了或者正在啟動,那么服務(wù)端是直接會信任的。
OverrideExistsRule
public OverrideExistsRule(Map<String, InstanceInfo.InstanceStatus> statusOverrides) {
this.statusOverrides = statusOverrides;
}
@Override
public StatusOverrideResult apply(InstanceInfo instanceInfo, Lease<InstanceInfo> existingLease, boolean isReplication) {
// 根據(jù)實(shí)例ID從覆蓋狀態(tài)MAP里面獲取該實(shí)例的覆蓋狀態(tài)。
InstanceInfo.InstanceStatus overridden = statusOverrides.get(instanceInfo.getId());
// 覆蓋狀態(tài)不為空
if (overridden != null) {
logger.debug("The instance specific override for instance {} and the value is {}",
instanceInfo.getId(), overridden.name());
// 匹配成功,返回覆蓋狀態(tài)
return StatusOverrideResult.matchingStatus(overridden);
}
return StatusOverrideResult.NO_MATCH;
}
步驟說明:
1.根據(jù)實(shí)例ID從覆蓋狀態(tài)MAP里面獲取該實(shí)例的覆蓋狀態(tài)。
2.匹配成功,返回覆蓋狀態(tài)
PS: 也許有人會感覺到比較疑惑, 這里的statusOverrides只不過是在實(shí)例化OverrideExistsRule這個(gè)類的時(shí)候傳入了overriddenInstanceStatusMap,
后續(xù)為某個(gè)實(shí)例添加了覆蓋狀態(tài),statusOverrudes怎么能感知到呢? 因?yàn)閛verriddenInstanceStatusMap 本質(zhì)上是使用了gauva的緩存,所以statusOverrides指向的也是gauva的緩存,所以是能立馬感知到的,因?yàn)楸旧砭褪且粋€(gè)東西
LeaseExistsRule
@Override
public StatusOverrideResult apply(InstanceInfo instanceInfo,
Lease<InstanceInfo> existingLease,
boolean isReplication) {
// This is for backward compatibility until all applications have ASG
// names, otherwise while starting up
// the client status may override status replicated from other servers
// 判斷是否是Eureka Server發(fā)過來的復(fù)制請求
if (!isReplication) {
// 判斷本地的Instance是否為空,不為空這獲取existingStatus
InstanceInfo.InstanceStatus existingStatus = null;
if (existingLease != null) {
existingStatus = existingLease.getHolder().getStatus();
}
// Allow server to have its way when the status is UP or OUT_OF_SERVICE
// existingStatus 不為空,并且 existingStatus 等于UP或者OUT_OF_SERVICE
// 如果滿足上述條件,則匹配成功,返回existingStatus
if ((existingStatus != null)
&& (InstanceInfo.InstanceStatus.OUT_OF_SERVICE.equals(existingStatus)
|| InstanceInfo.InstanceStatus.UP.equals(existingStatus))) {
logger.debug("There is already an existing lease with status {} for instance {}",
existingLease.getHolder().getStatus().name(),
existingLease.getHolder().getId());
return StatusOverrideResult.matchingStatus(existingLease.getHolder().getStatus());
}
}
return StatusOverrideResult.NO_MATCH;
}
步驟說明:
1.判斷是否是Eureka Server發(fā)過來的復(fù)制請求 ,isReplication = true 表示是Eureka Server的復(fù)制請求
2.獲取Eureka Server本地已經(jīng)存在的instance信息,獲取其狀態(tài)
3.判斷狀態(tài)是否為空
4.判斷狀態(tài)是否等于UP 或者OUT_OF_SERVICE
5.匹配成功,則返回本地的instanceInfo的status
AlwaysMatchInstanceStatusRule
@Override
public StatusOverrideResult apply(InstanceInfo instanceInfo,
Lease<InstanceInfo> existingLease,
boolean isReplication) {
logger.debug("Returning the default instance status {} for instance {}", instanceInfo.getStatus(),
instanceInfo.getId());
return StatusOverrideResult.matchingStatus(instanceInfo.getStatus());
}
當(dāng)以上三個(gè)規(guī)則全部匹配不成功的時(shí)候,則直接使用這個(gè)規(guī)則匹配,這個(gè)規(guī)則會直接信任客戶端發(fā)過來的
instance的狀態(tài)
狀態(tài)匹配流程

1.使用DownOrStartingRule做匹配,匹配客戶端傳過來的instanceIInfo的status是否等于DOWN或STARTING , 如果是,則匹配成功
2.OverrideExistsRule規(guī)則, 判斷該實(shí)例是否存在覆蓋狀態(tài),如果存在,則直接返回覆蓋狀態(tài),以覆蓋狀態(tài)為準(zhǔn)
3.LeaseExistsRule , 判斷Eureka Server本地的實(shí)例狀態(tài)是否等于UP或OUT_OF_SERVICE ,如果等于,則返回本地實(shí)例的狀態(tài)
4.AlwaysMatchInstanceStatusRule直接信任客戶端傳過來的實(shí)例信息。