點選上方“芋道原始碼”,選擇“置頂公眾號”
技術文章第一時間送達!
原始碼精品專欄
本文主要基於 Eureka 1.8.X 版本
-
1. 概述
-
2. 應用實體改寫狀態變更介面
-
2.1 更新應用實體改寫狀態
-
3. 應用實體改寫狀態刪除介面
-
3.1 刪除應用實體改寫狀態
-
4. 應用實體改寫狀態對映
-
4.1 應用實體狀態改寫規則
-
4.2 註冊場景
-
4.3 續租場景
-
4.4 下線場景
-
4.5 過期場景
-
5. 客戶端呼叫介面
-
666. 彩蛋
1. 概述
本文主要分享 應用實體的改寫狀態屬性。
這裡要註意下,不是應用實體的狀態( status
),而是改寫狀態( overridestatus
) 。程式碼如下:
public class InstanceInfo {
private volatile InstanceStatus overriddenstatus = InstanceStatus.UNKNOWN;
// ... 省略屬性和方法
}
呼叫 Eureka-Server HTTP Restful 介面 apps/${APP_NAME}/${INSTANCE_ID}/status
對應用實體改寫狀態的變更,從而達到主動的、強制的變更應用實體狀態。註意,實際不會真的修改 Eureka-Client 應用實體的狀態,而是修改在 Eureka-Server 註冊的應用實體的狀態。
透過這樣的方式,Eureka-Client 在獲取到註冊資訊時,並且配置 eureka.shouldFilterOnlyUpInstances = true
,過濾掉非 InstanceStatus.UP
的應用實體,從而避免調動該實體,以達到應用實體的暫停服務( InstanceStatus.OUT_OF_SERVICE
),而無需關閉應用實體。
因此,大多數情況下,呼叫該介面的目的,將應用實體狀態在 ( InstanceStatus.UP
) 和 ( InstanceStatus.OUT_OF_SERVICE
) 之間切換。取用官方程式碼上的註釋如下:
AbstractInstanceRegistry#statusUpdate
方法註釋
Updates the status of an instance.
Normally happens to put an instance between {@link InstanceStatus#OUT_OF_SERVICE} and {@link InstanceStatus#UP} to put the instance in and out of traffic.
推薦 Spring Cloud 書籍:
-
請支援正版。下載盜版,等於主動編寫低階 BUG 。
-
程式猿DD —— 《Spring Cloud微服務實戰》
-
周立 —— 《Spring Cloud與Docker微服務架構實戰》
-
兩書齊買,京東包郵。
推薦 Spring Cloud 影片:
-
Java 微服務實踐 – Spring Boot
-
Java 微服務實踐 – Spring Cloud
-
Java 微服務實踐 – Spring Boot / Spring Cloud
介面 apps/${APP_NAME}/${INSTANCE_ID}/status
實際是兩個:
-
PUT
apps/${APP_NAME}/${INSTANCE_ID}/status
-
DELETE
apps/${APP_NAME}/${INSTANCE_ID}/status
下麵,我們逐節分享這兩介面的程式碼實現。
2. 應用實體改寫狀態變更介面
應用實體改寫狀態變更介面,對映 InstanceResource#statusUpdate()
方法,實現程式碼如下:
@PUT
@Path("status")
public Response statusUpdate(
@QueryParam("value") String newStatus,
@HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication,
@QueryParam("lastDirtyTimestamp") String lastDirtyTimestamp) {
try {
// 應用實體不存在
if (registry.getInstanceByAppAndId(app.getName(), id) == null) {
logger.warn("Instance not found: {}/{}", app.getName(), id);
return Response.status(Status.NOT_FOUND).build();
}
// 改寫狀態更新
boolean isSuccess = registry.statusUpdate(app.getName(), id,
InstanceStatus.valueOf(newStatus), lastDirtyTimestamp,
"true".equals(isReplication));
// 傳回結果
if (isSuccess) {
logger.info("Status updated: " + app.getName() + " - " + id
+ " - " + newStatus);
return Response.ok().build();
} else {
logger.warn("Unable to update status: " + app.getName() + " - "
+ id + " - " + newStatus);
return Response.serverError().build();
}
} catch (Throwable e) {
logger.error("Error updating instance {} for status {}", id,
newStatus);
return Response.serverError().build();
}
}
-
呼叫
PeerAwareInstanceRegistryImpl#statusUpdate(...)
方法,更新應用實體改寫狀態。實現程式碼如下:@Override
public boolean statusUpdate(final String appName, final String id,
final InstanceStatus newStatus, String lastDirtyTimestamp,
final boolean isReplication) {
if (super.statusUpdate(appName, id, newStatus, lastDirtyTimestamp, isReplication)) {
// Eureka-Server 叢集同步
replicateToPeers(Action.StatusUpdate, appName, id, null, newStatus, isReplication);
return true;
}
return false;
} -
呼叫父類
AbstractInstanceRegistry#statusUpdate(…)
方法,更新應用實體改寫狀態。
2.1 更新應用實體改寫狀態
呼叫 AbstractInstanceRegistry#statusUpdate(...)
方法,更新應用實體改寫狀態,實現程式碼如下:
1: @Override
2: public boolean statusUpdate(String appName, String id,
3: InstanceStatus newStatus, String lastDirtyTimestamp,
4: boolean isReplication) {
5: try {
6: // 獲取讀鎖
7: read.lock();
8: // 新增 改寫狀態變更次數 到 監控
9: STATUS_UPDATE.increment(isReplication);
10: // 獲得 租約
11: Map> gMap = registry.get(appName);
12: Lease lease = null;
13: if (gMap != null) {
14: lease = gMap.get(id);
15: }
16: // 租約不存在
17: if (lease == null) {
18: return false;
19: } else {
20: // 設定 租約最後更新時間(續租)
21: lease.renew();
22:
23: // 應用實體資訊不存在( 防禦型程式設計 )
24: InstanceInfo info = lease.getHolder();
25: // Lease is always created with its instance info object.
26: // This log statement is provided as a safeguard, in case this invariant is violated.
27: if (info == null) {
28: logger.error("Found Lease without a holder for instance id {}", id);
29: }
30: //
31: if ((info != null) && !(info.getStatus().equals(newStatus))) {
32: // 設定 租約的開始服務的時間戳(只有第一次有效)
33: // Mark service as UP if needed
34: if (InstanceStatus.UP.equals(newStatus)) {
35: lease.serviceUp();
36: }
37: // 新增到 應用實體改寫狀態對映
38: // This is NAC overridden status
39: overriddenInstanceStatusMap.put(id, newStatus);
40: // 設定 應用實體改寫狀態
41: // Set it for transfer of overridden status to replica on
42: // replica start up
43: info.setOverriddenStatus(newStatus);
44: // 設定 應用實體資訊 資料不一致時間
45: long replicaDirtyTimestamp = 0;
46: // 設定 應用實體狀態
47: info.setStatusWithoutDirty(newStatus);
48: if (lastDirtyTimestamp != null) {
49: replicaDirtyTimestamp = Long.valueOf(lastDirtyTimestamp);
50: }
51: // If the replication's dirty timestamp is more than the existing one, just update
52: // it to the replica's.
53: if (replicaDirtyTimestamp > info.getLastDirtyTimestamp()) {
54: info.setLastDirtyTimestamp(replicaDirtyTimestamp);
55: }
56: // 新增到 最近租約變更記錄佇列
57: info.setActionType(ActionType.MODIFIED);
58: recentlyChangedQueue.add(new RecentlyChangedItem(lease));
59: // 設定 最後更新時間
60: info.setLastUpdatedTimestamp();
61: // 設定 響應快取 過期
62: invalidateCache(appName, info.getVIPAddress(), info.getSecureVipAddress());
63: }
64: return true;
65: }
66: } finally {
67: // 釋放鎖
68: read.unlock();
69: }
70: }
-
第 6 至 7 行 :獲取讀鎖。在 《Eureka原始碼解析 —— 應用實體註冊發現 (九)之歲月是把萌萌的讀寫鎖》詳細解析。
-
第 8 至 9 行 :新增改寫狀態變更次數到監控。配合 Netflix Servo 實現監控資訊採集。
-
第 10 至 15 行 :獲得租約。
-
第 16 至 18 行 :租約不存在,傳回更新失敗。
-
第 20 至 21 行 :設定租約最後更新時間( 續租 )。
-
第 23 至 29 行 :持有租約的應用實體不存在,理論來說不會出現,防禦性程式設計。
-
第 31 行 :應用實體當前狀態和覆該狀態不一致時才更新改寫狀態。
-
第 32 至 36 行 :當改寫狀態是
InstanceStatus.UP
,設定租約的開始服務的時間戳(只有第一次有效)。 -
第 37 至 39 行 :新增到應用實體改寫狀態對映(
overriddenInstanceStatusMap
)。此處英文"NAC"
可能是"Network Access Control"
的縮寫,感興趣的可以看看 《Network Access Control》 。overriddenInstanceStatusMap
屬性程式碼如下:/**
* 應用實體改寫狀態對映
* key:應用實體編號
*/
protected final ConcurrentMapoverriddenInstanceStatusMap = CacheBuilder
.newBuilder().initialCapacity(500)
.expireAfterAccess(1, TimeUnit.HOURS)
.build().asMap(); -
有效期 1 小時。每次訪問後會掃清有效期,在後文你會看到對其的訪問。
-
第 40 至 43 行 :設定應用實體的改寫狀態。用於 Eureka-Server 叢集同步。
-
第 46 至 47 行 :設定應用實體狀態。設定後,Eureka-Client 拉取註冊資訊,被更新改寫狀態的應用實體就是設定的狀態。
-
第 48 至 55 行 :設定應用實體的資料不一致時間。用於 Eureka-Server 叢集同步。
-
第 56 至 58 行 :新增應用實體到最近租約變更記錄佇列。
-
第 59 至 60 行 :設定應用實體的最後更新時間(
lastUpdatedTimestamp
)。lastUpdatedTimestamp
主要用於記錄最後更新時間,無實際業務用途。 -
第 61 至 62 行 :設定響應快取過期。
-
第 64 行 :傳回更新成功。
-
第 68 行 :釋放讀鎖。
3. 應用實體改寫狀態刪除介面
當我們不需要應用實體的改寫狀態時,排程介面介面進行刪除。關聯官方 issue#89
:Provide an API to remove all overridden status。
應用實體改寫狀態刪除介面,對映 InstanceResource#deleteStatusUpdate()
方法,實現程式碼如下:
@DELETE
@Path("status")
public Response deleteStatusUpdate(
@HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication,
@QueryParam("value") String newStatusValue,
@QueryParam("lastDirtyTimestamp") String lastDirtyTimestamp) {
try {
// 應用實體不存在
if (registry.getInstanceByAppAndId(app.getName(), id) == null) {
logger.warn("Instance not found: {}/{}", app.getName(), id);
return Response.status(Status.NOT_FOUND).build();
}
// 改寫狀態刪除
InstanceStatus newStatus = newStatusValue == null ? InstanceStatus.UNKNOWN : InstanceStatus.valueOf(newStatusValue);
boolean isSuccess = registry.deleteStatusOverride(app.getName(), id,
newStatus, lastDirtyTimestamp, "true".equals(isReplication));
// 傳回結果
if (isSuccess) {
logger.info("Status override removed: " + app.getName() + " - " + id);
return Response.ok().build();
} else {
logger.warn("Unable to remove status override: " + app.getName() + " - " + id);
return Response.serverError().build();
}
} catch (Throwable e) {
logger.error("Error removing instance's {} status override", id);
return Response.serverError().build();
}
}
-
請求引數
newStatusValue
,設定應用實體的狀態。大多數情況下,newStatusValue
要和應用實體實際的狀態一致,因為該應用實體的 Eureka-Client 不會從 Eureka-Server 拉取到該應用狀態newStatusValue
。另外一種方式,不傳遞該引數,相當於UNKNOWN
狀態,這樣,Eureka-Client 會主動向 Eureka-Server 再次發起註冊,具體原因在 [「4.3 續租場景」] 詳細解析,更加推薦的方式。 -
呼叫父類
AbstractInstanceRegistry#deleteStatusOverride(...)
方法,刪除應用實體改寫狀態。實現程式碼如下:@Override
public boolean deleteStatusOverride(String appName, String id,
InstanceStatus newStatus,
String lastDirtyTimestamp,
boolean isReplication) {
if (super.deleteStatusOverride(appName, id, newStatus, lastDirtyTimestamp, isReplication)) {
// Eureka-Server 叢集同步
replicateToPeers(Action.DeleteStatusOverride, appName, id, null, null, isReplication);
return true;
}
return false;
} -
呼叫父類
AbstractInstanceRegistry#deleteStatusOverride(…)
方法,刪除應用實體改寫狀態。
3.1 刪除應用實體改寫狀態
呼叫父類 AbstractInstanceRegistry#deleteStatusOverride(...)
方法,刪除應用實體改寫狀態。實現程式碼如下:
1: @Override
2: public boolean deleteStatusOverride(String appName, String id,
3: InstanceStatus newStatus,
4: String lastDirtyTimestamp,
5: boolean isReplication) {
6: try {
7: // 獲取讀鎖
8: read.lock();
9: // 新增 改寫狀態刪除次數 到 監控
10: STATUS_OVERRIDE_DELETE.increment(isReplication);
11: // 獲得 租約
12: Map> gMap = registry.get(appName);
13: Lease lease = null;
14: if (gMap != null) {
15: lease = gMap.get(id);
16: }
17: // 租約不存在
18: if (lease == null) {
19: return false;
20: } else {
21: // 設定 租約最後更新時間(續租)
22: lease.renew();
23:
24: // 應用實體資訊不存在( 防禦型程式設計 )
25: InstanceInfo info = lease.getHolder();
26: // Lease is always created with its instance info object.
27: // This log statement is provided as a safeguard, in case this invariant is violated.
28: if (info == null) {
29: logger.error("Found Lease without a holder for instance id {}", id);
30: }
31:
32: // 移除 應用實體改寫狀態
33: InstanceStatus currentOverride = overriddenInstanceStatusMap.remove(id);
34: if (currentOverride != null && info != null) {
35: // 設定 應用實體改寫狀態
36: info.setOverriddenStatus(InstanceStatus.UNKNOWN);
37: // 設定 應用實體狀態
38: info.setStatusWithoutDirty(newStatus);
39: // 設定 應用實體資訊 資料不一致時間
40: long replicaDirtyTimestamp = 0;
41: if (lastDirtyTimestamp != null) {
42: replicaDirtyTimestamp = Long.valueOf(lastDirtyTimestamp);
43: }
44: // If the replication's dirty timestamp is more than the existing one, just update
45: // it to the replica's.
46: if (replicaDirtyTimestamp > info.getLastDirtyTimestamp()) {
47: info.setLastDirtyTimestamp(replicaDirtyTimestamp);
48: }
49: // 新增到 最近租約變更記錄佇列
50: info.setActionType(ActionType.MODIFIED);
51: recentlyChangedQueue.add(new RecentlyChangedItem(lease));
52: // 設定 最後更新時間
53: info.setLastUpdatedTimestamp();
54: // 設定 響應快取 過期
55: invalidateCache(appName, info.getVIPAddress(), info.getSecureVipAddress());
56: }
57: return true;
58: }
59: } finally {
60: // 釋放鎖
61: read.unlock();
62: }
63: }
-
第 7 至 8 行 :獲取讀鎖。在 《Eureka原始碼解析 —— 應用實體註冊發現 (九)之歲月是把萌萌的讀寫鎖》詳細解析。
-
第 9 至 10 行 :新增改寫狀態刪除次數到監控。配合 Netflix Servo 實現監控資訊採集。
-
第 11 至 16 行 :獲得租約。
-
第 17 至 19 行 :租約不存在,傳回更新失敗。
-
第 21 至 22 行 :設定租約最後更新時間( 續租 )。
-
第 24 至 30 行 :持有租約的應用實體不存在,理論來說不會出現,防禦性程式設計。
-
第 32 至 33 行 :移除出應用實體改寫狀態對映(
overriddenInstanceStatusMap
)。 -
第 34 行 :應用實體的改寫狀態存在才設定狀態。
-
第 35 至 36 行 :設定應用實體的改寫狀態為 InstanceStatus.UNKNOWN。用於 Eureka-Server 叢集同步。
-
第 37 至 38 行 :設定應用實體的狀態為
newStatus
。設定後,Eureka-Client 拉取註冊資訊,被更新改寫狀態的應用實體就是設定的狀態。 -
第 39 至 48 行 :設定應用實體的資料不一致時間。用於 Eureka-Server 叢集同步。
-
第 49 至 51 行 :新增應用實體到最近租約變更記錄佇列。
-
第 52 至 53 行 :設定應用實體的最後更新時間(
lastUpdatedTimestamp
)。lastUpdatedTimestamp
主要用於記錄最後更新時間,無實際業務用途。 -
第 54 至 55 行 :設定響應快取過期。
-
第 57 行 :傳回更新成功。
-
第 61 行 :釋放讀鎖。
4. 應用實體改寫狀態對映
雖然我們在上面程式碼,使用改寫狀態( overridestatus
)設定到應用實體的狀態( status
),實際呼叫 AbstractInstanceRegistry#getOverriddenInstanceStatus(...)
方法,根據應用實體狀態改寫規則( InstanceStatusOverrideRule )進行計算最終應用實體的狀態。實現程式碼如下:
// AbstractInstanceRegistry.java
protected InstanceInfo.InstanceStatus getOverriddenInstanceStatus(InstanceInfo r,
Lease existingLease,
boolean isReplication) {
InstanceStatusOverrideRule rule = getInstanceInfoOverrideRule();
logger.debug("Processing override status using rule: {}", rule);
return rule.apply(r, existingLease, isReplication).status();
}
protected abstract InstanceStatusOverrideRule getInstanceInfoOverrideRule();
-
呼叫
#getInstanceInfoOverrideRule()
方法,獲取應用實體狀態改寫規則( InstanceStatusOverrideRule )。在 PeerAwareInstanceRegistryImpl 裡該方法實現程式碼如下:private final InstanceStatusOverrideRule instanceStatusOverrideRule;
public PeerAwareInstanceRegistryImpl(
EurekaServerConfig serverConfig,
EurekaClientConfig clientConfig,
ServerCodecs serverCodecs,
EurekaClient eurekaClient
) {
// ... 省略其它方法this.instanceStatusOverrideRule = new FirstMatchWinsCompositeRule(
new DownOrStartingRule(),
new OverrideExistsRule(overriddenInstanceStatusMap),
new LeaseExistsRule());}
@Override
protected InstanceStatusOverrideRule getInstanceInfoOverrideRule() {
return this.instanceStatusOverrideRule;
}
4.1 應用實體狀態改寫規則
com.netflix.eureka.registry.rule.InstanceStatusOverrideRule
,應用實體狀態改寫規則介面。介面程式碼如下:
// InstanceStatusOverrideRule.java
public interface InstanceStatusOverrideRule {
/**
* Match this rule.
*
* @param instanceInfo The instance info whose status we care about. 關註狀態的應用實體物件
* @param existingLease Does the instance have an existing lease already? If so let's consider that. 已存在的租約
* @param isReplication When overriding consider if we are under a replication mode from other servers. 是否是 Eureka-Server 發起的請求
* @return A result with whether we matched and what we propose the status to be overriden to.
*/
StatusOverrideResult apply(final InstanceInfo instanceInfo,
final Lease existingLease,
boolean isReplication) ;
}
// StatusOverrideResult.java
public class StatusOverrideResult {
public static StatusOverrideResult NO_MATCH = new StatusOverrideResult(false, null);
public static StatusOverrideResult matchingStatus(InstanceInfo.InstanceStatus status) {
return new StatusOverrideResult(true, status);
}
// Does the rule match?
private final boolean matches;
// The status computed by the rule.
private final InstanceInfo.InstanceStatus status;
private StatusOverrideResult(boolean matches, InstanceInfo.InstanceStatus status) {
this.matches = matches;
this.status = status;
}
public boolean matches() {
return matches;
}
public InstanceInfo.InstanceStatus status() {
return status;
}
}
-
#apply(…)
方法引數instanceInfo
代表的是關註狀態的應用實體,和方法引數existingLease
裡的應用實體不一定是同一個,在 「4.1.6 總結」 詳細解析。 -
com.netflix.eureka.registry.rule.StatusOverrideResult
,狀態改寫結果。當匹配成功,傳回matches = true
;否則,傳回matches = false
。
實現類關係如下:
-
AsgEnabledRule ,亞馬遜 AWS 專用,跳過。
4.1.1 FirstMatchWinsCompositeRule
com.netflix.eureka.registry.rule.FirstMatchWinsCompositeRule
,複合規則,以第一個匹配成功為準。實現程式碼如下:
// 超過微信限制 50000 字了
-
rules
屬性,複合規則集合。在 PeerAwareInstanceRegistryImpl 裡,我們可以看到該屬性為 [ DownOrStartingRule , OverrideExistsRule , LeaseExistsRule ] 。 -
defaultRule
屬性,預設規則,值為 AlwaysMatchInstanceStatusRule 。 -
#apply()
方法,優先使用複合規則(rules
),順序匹配,直到匹配成功 。當未匹配成功,使用預設規則(defaultRule
) 。
4.1.2 DownOrStartingRule
com.netflix.eureka.registry.rule.DownOrStartingRule
,匹配 InstanceInfo.InstanceStatus.DOWN
或者 InstanceInfo.InstanceStatus.STARTING
狀態。實現 #apply(...)
程式碼如下:
// 超過微信限制 50000 字了
-
註意,使用的是
instanceInfo
。
4.1.3 OverrideExistsRule
com.netflix.eureka.registry.rule.OverrideExistsRule
,匹配應用實體改寫狀態對映( statusOverrides
) 。實現 #apply(...)
程式碼如下:
// 超過微信限制 50000 字了
-
statusOverrides
屬性,應用實體改寫狀態對映。在 PeerAwareInstanceRegistryImpl 裡,使用AbstractInstanceRegistry.overriddenInstanceStatusMap
屬性賦值。 -
上文我們提到
AbstractInstanceRegistry.overriddenInstanceStatusMap
每次訪問掃清有效期,如果呼叫到 OverrideExistsRule ,則會不斷掃清。從 DownOrStartingRule 看到,instanceInfo
處於InstanceInfo.InstanceStatus.DOWN
或者InstanceInfo.InstanceStatus.STARTING
才不會繼續呼叫 OverrideExistsRule 匹配,AbstractInstanceRegistry.overriddenInstanceStatusMap
才有可能過期。
4.1.4 LeaseExistsRule
com.netflix.eureka.registry.rule.LeaseExistsRule
,匹配已存在租約的應用實體的 nstanceStatus.OUT_OF_SERVICE
或者 InstanceInfo.InstanceStatus.UP
狀態。實現 #apply(...)
程式碼如下:
// 超過微信限制 50000 字了
-
註意,使用的是
existingLease
,並且非 Eureka-Server 請求。
4.1.5 AlwaysMatchInstanceStatusRule
com.netflix.eureka.registry.rule.AlwaysMatchInstanceStatusRule
,總是匹配關註狀態的實體物件( instanceInfo
)的狀態。實現 #apply(...)
程式碼如下:
// 超過微信限制 50000 字了
-
註意,使用的是
instanceInfo
。
4.1.6 總結
我們將 PeerAwareInstanceRegistryImpl 的應用實體改寫狀態規則梳理如下:
-
應用實體狀態是最重要的屬性,沒有之一,因而在最終實體狀態的計算,以可信賴為主。
-
DownOrStartingRule ,
instanceInfo
處於STARTING
或者DOWN
狀態,應用實體可能不適合提供服務( 被請求 ),考慮可信賴,傳回instanceInfo
的狀態。 -
OverrideExistsRule ,當存在改寫狀態(
statusoverrides
) ,使用該狀態,比較好理解。 -
LeaseExistsRule ,來自 Eureka-Client 的請求( 非 Eureka-Server 叢集請求),當 Eureka-Server 的實體狀態存在,並且處於
UP
或則OUT_OF_SERVICE
,保留當前狀態。原因,禁止 Eureka-Client 主動在這兩個狀態之間切換。如果要切換,使用應用實體改寫狀態變更與刪除介面。 -
AlwaysMatchInstanceStatusRule ,使用
instanceInfo
的狀態傳回,以保證能匹配到狀態。 -
在下文中,你會看到,
#getOverriddenInstanceStatus()
方法會在註冊和續租使用到。結合上圖,我們在 「4.2 註冊場景」 和 「4.3 續租場景」 也會詳細解析。 -
在下文中,你會看到,
#getOverriddenInstanceStatus()
方法會在註冊和續租使用到,方法引數instanceInfo
情況如下: -
註冊時 :請求引數
instanceInfo
,和existingLease
的應用實體屬性不相等( 如果考慮 Eureka-Server 的LastDirtyTimestamp
更大的情況,則類似 續租時的情況 ) 。 -
續租時 :使用 Eureka-Server 的
existingLease
的應用實體,兩者相等。 -
總的來說,可以將 `instanceInfo` 理解成請求方的狀態。
-
DownOrStartingRule ,
4.2 註冊場景
// AbstractInstanceRegistry.java
// 超過微信限制 50000 字了
-
第 7 行 :獲得已存在的租約(
existingLease
) 。 -
第 15 行 :建立新的租約(
lease
)。 -
第 24 至 28 行 :設定應用實體的改寫狀態(
overridestatus
),避免註冊應用實體後,丟失改寫狀態。 -
第 30 至 32 行 :獲得應用實體最終狀態。註意下,不考慮第 9 行程式碼的情況,
registrant
和existingLease
的應用實體不是同一個物件。 -
第 33 只 34 行 :設定應用實體的狀態。
4.3 續租場景
// AbstractInstanceRegistry.java
// 超過微信限制 50000 字了
-
第 15 至 17 行 :獲得應用實體的最終狀態。
-
第 18 至 24 行 :應用實體的最終狀態為
UNKNOWN
,無法續約 。傳回false
後,請求方( Eureka-Client 或者 Eureka-Server 叢集其他節點 )會發起註冊,在 《Eureka 原始碼解析 —— 應用實體註冊發現(二)之續租》 有詳細解析。為什麼會是 `UNKNOWN` 呢?在 「3. 應用實體改寫狀態刪除介面」 傳遞應用實體狀態為UNKNOWN
。 -
第 25 至 36 行 :應用實體的狀態與最終狀態不相等,使用最終狀態改寫應用實體的狀態。為什麼會不相等呢?
#renew(…)
和#statusUpdate(…)
可以無鎖,並行執行,如果 -
`#renew(…)` 執行完第 16 行程式碼,獲取到 `overriddenInstanceStatus` 後,恰巧 `#statusUpdate(…)` 執行完更新應用實體狀態 `newStatus`,又恰好兩者不相等,使用 `overriddenInstanceStatus` 改寫掉應用實體的 `newStatus` 狀態。
-
那豈不是改寫狀態( `overriddenstatus` )反倒被改寫???不會,在下一次心跳,應用實體的狀態會被修正回來。當然,如果應用實體狀態如果為 `UP` 或者 `STARTING` 不會被修正,也不應該被修正。
4.4 下線場景
// AbstractInstanceRegistry.java
// 超過微信限制 50000 字了
4.5 過期場景
同 「4.4 下線場景」 相同。
5. 客戶端呼叫介面
對應用實體改寫狀態的變更和刪除介面呼叫,點選如下方法檢視,非常易懂,本文就不囉嗦了:
-
`AbstractJerseyEurekaHttpClient#statusUpdate(…)`
-
`AbstractJerseyEurekaHttpClient#deleteStatusOverride(…)`
666. 彩蛋
猜測改寫狀態的花費了較長時間,梳理應用實體改寫規則耗費大量腦細胞。
下一篇,讓我雞雞動動的,Eureka-Server 叢集同步走起!
胖友,分享我的公眾號( 芋道原始碼 ) 給你的胖友可好?
目前在知識星球(https://t.zsxq.com/2VbiaEu)更新瞭如下 Dubbo 原始碼解析如下:
01. 除錯環境搭建
02. 專案結構一覽
03. API 配置(一)之應用
04. API 配置(二)之服務提供者
05. API 配置(三)之服務消費者
06. 屬性配置
07. XML 配置
08. 核心流程一覽
09. 拓展機制 SPI
10. 執行緒池
11. 服務暴露(一)之遠端暴露(Injvm)
12. 服務暴露(二)之遠端暴露(Dubbo)
…
一共 60 篇++