本文主要基于 Eureka 1.8.X 版本
- 概述
- 2. 应用实例覆盖状态变更接口
2.1 更新应用实例覆盖状态
3.1 删除应用实例覆盖状态
4.1 应用实例状态覆盖规则
4.2 注册场景
4.3 续租场景
4.4 下线场景
4.5 过期场景
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();
}
}
@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: MapString, LeaseInstanceInfo gMap = registry.get(appName);
12: LeaseInstanceInfo 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: }
/**
* 应用实例覆盖状态映射
* key:应用实例编号
*/
protected final ConcurrentMapString, InstanceStatus overriddenInstanceStatusMap = CacheBuilder
.newBuilder().initialCapacity(500)
.expireAfterAccess(1, TimeUnit.HOURS)
.String, InstanceStatusbuild().asMap();
-
- 有效期 1 小时。每次访问后会刷新有效期,在后文你会看到对其的访问。
第 8 至 9 行 :添加覆盖状态变更次数到监控。配合 Netflix Servo 实现监控信息采集。
第 16 至 18 行 :租约不存在,返回更新失败。
第 23 至 29 行 :持有租约的应用实例不存在,理论来说不会出现,防御性编程。
第 32 至 36 行 :当覆盖状态是
InstanceStatus.UP
,设置租约的开始服务的时间戳(只有第一次有效)。
第 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();
}
}
@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(…)` 方法,删除应用实例覆盖状态。
调用父类
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: MapString, LeaseInstanceInfo gMap = registry.get(appName);
13: LeaseInstanceInfo 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,
LeaseInstanceInfo 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();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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; } |
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;
}
com.netflix.eureka.registry.rule.InstanceStatusOverrideRule</code> ,应用实例状态覆盖规则**接口**。接口代码如下:</p>
<pre style="margin-top: 0px; margin-bottom: 0px; padding: 0px; font-size: 15px; color: #3e3e3e; line-height: inherit; letter-spacing: 2px; word-spacing: 2px; background-color: #ffffff;"><code class="Java language-Java hljs" style="margin-right: 2px; margin-left: 2px; padding: 0.5em; font-size: 14px; color: #a9b7c6; line-height: 18px; border-radius: 0px; background: #282b2e; font-family: Consolas, Inconsolata, Courier, monospace; display: block; overflow-x: auto; word-spacing: 0px; letter-spacing: 0px; word-wrap: normal !important; overflow-y: auto !important;">// 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 LeaseInstanceInfo 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 的应用实例覆盖状态规则梳理如下:
-
- **注册时** :请求参数 `instanceInfo` ,和 `existingLease` 的应用实例属性不相等( 如果考虑 Eureka-Server 的 `LastDirtyTimestamp` 更大的情况,则类似 **续租时的情况** ) 。
- **续租时** :使用 Eureka-Server 的 `existingLease` 的应用实例,两者相等。
- **总的来说,可以将 `instanceInfo` 理解成请求方的状态**。
DownOrStartingRule ,
instanceInfo
处于
STARTING
或者
DOWN
状态,应用实例可能不适合提供服务( 被请求 ),考虑可信赖,返回
instanceInfo
的状态。
LeaseExistsRule ,来自 Eureka-Client 的请求( 非 Eureka-Server 集群请求),当 Eureka-Server 的实例状态存在,并且处于
UP
或则
OUT_OF_SERVICE
,保留当前状态。原因,禁止 Eureka-Client 主动在这两个状态之间切换。如果要切换,使用应用实例覆盖状态变更与删除接口。
在下文中,你会看到,
#getOverriddenInstanceStatus()
方法会在注册和续租使用到。结合上图,我们在 「4.2 注册场景」 和 「4.3 续租场景」 也会详细解析。
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. 拓展机制 SPI10. 线程池11. 服务暴露(一)之远程暴露(Injvm)12. 服务暴露(二)之远程暴露(Dubbo)…
一共 60 篇++