簡(jiǎn)要
在深入理解Eureka Server覆蓋狀態(tài)(九)這一篇文章中疗认,我們介紹了Eureka Server的覆蓋狀態(tài)嘉汰,但是覆蓋狀態(tài)設(shè)置了之后
Eureka在使用的時(shí)候都會(huì)通過(guò)getOverriddenInstanceStatus()這個(gè)方法來(lái)計(jì)算實(shí)例的最終狀態(tài)醋寝,那么他計(jì)算的規(guī)則是
什么呢挣跋,本篇文章主要講的就是這個(gè)苛骨。
代碼回顧
在注冊(cè)的時(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())) {
// 如果不等于博肋,則說(shuō)明被修改過(guò)低斋,放入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();
}
}
說(shuō)明:
由上面的代碼可以很清晰的看出膊畴,在Eureka注冊(cè)時(shí)候,先對(duì)覆蓋狀態(tài)做了一系列判斷病游,對(duì)是否擁有覆蓋狀態(tài)做了初始化唇跨,
如果有,則設(shè)置覆蓋狀態(tài), 最終調(diào)用了getOverriddenInstanceStatus來(lái)計(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
接下來(lái)直接看這個(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;
}
}
// 如果以上都沒(méi)有匹配成功薛窥,則使用該規(guī)則進(jìn)行匹配
return defaultRule.apply(instanceInfo, existingLease, isReplication);
}
說(shuō)明:
在apply方法里面,循環(huán)調(diào)用rules的apply方法眼姐,直到匹配成功 诅迷。 通過(guò)PeerAwareInstanceRegistryImpl類中創(chuàng)建FirstMatchWinsCompositeRule
對(duì)象的代碼,我們可以知道众旗,具體的匹配規(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代碼上來(lái)看绍弟,如果instanceInfo的狀態(tài)不等于UP
同時(shí)也不等于OUT_OF_SERVICE , 那么就就匹配成功技即,其實(shí)說(shuō)白了,不等于UP和OUT_OF_SERVICE , 其實(shí)也就是等于DOWN和STRATING樟遣。
如果匹配成功而叼,則返回instance的狀態(tài),匹配成功豹悬。
PS: instanceInfo 為客戶端傳過(guò)來(lái)的葵陵,也就說(shuō)客戶端說(shuō)DOWN了或者正在啟動(dòng),那么服務(wù)端是直接會(huì)信任的屿衅。
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;
}
步驟說(shuō)明:
1.根據(jù)實(shí)例ID從覆蓋狀態(tài)MAP里面獲取該實(shí)例的覆蓋狀態(tài)。
2.匹配成功涡尘,返回覆蓋狀態(tài)
PS: 也許有人會(huì)感覺(jué)到比較疑惑忍弛, 這里的statusOverrides只不過(guò)是在實(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ā)過(guò)來(lái)的復(fù)制請(qǐng)求
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;
}
步驟說(shuō)明:
1.判斷是否是Eureka Server發(fā)過(guò)來(lái)的復(fù)制請(qǐng)求 丢早,isReplication = true 表示是Eureka Server的復(fù)制請(qǐng)求
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ī)則會(huì)直接信任客戶端發(fā)過(guò)來(lái)的
instance的狀態(tài)
狀態(tài)匹配流程
1.使用DownOrStartingRule做匹配,匹配客戶端傳過(guò)來(lái)的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直接信任客戶端傳過(guò)來(lái)的實(shí)例信息。