(九)EurekaServer-处理客户端变更状态、删除状态请求
作者:互联网
0. 前言
- springboot版本:2.1.9.RELEASE
- springcloud版本:Greenwich.SR4
1. 处理删除状态请求
服务端处理客户端变更状态和删除状态请求的方法都在 InstanceResource 类
// InstanceResource.class
public Response deleteStatusUpdate(
@HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication,
@QueryParam("value") String newStatusValue,
@QueryParam("lastDirtyTimestamp") String lastDirtyTimestamp) {
// isReplication:是否是集群节点同步复制
// newStatusValue:客户端发起删除状态时,这里为 null
// lastDirtyTimestamp:最新修改时间戳(脏)
try {
if (registry.getInstanceByAppAndId(app.getName(), id) == null) {
// 查询本地注册表中的服务实例信息,如果查询不到返回404
logger.warn("Instance not found: {}/{}", app.getName(), id);
return Response.status(Status.NOT_FOUND).build();
}
// 客户端发过来的 newStatusValue = null ,所以 newStatus = UNKNOWN
InstanceStatus newStatus = newStatusValue == null ? InstanceStatus.UNKNOWN : InstanceStatus.valueOf(newStatusValue);
// 2 处理删除状态
boolean isSuccess = registry.deleteStatusOverride(app.getName(), id,
newStatus, lastDirtyTimestamp, "true".equals(isReplication));
if (isSuccess) {
logger.info("Status override removed: {} - {}", app.getName(), id);
// 处理成功返回200
return Response.ok().build();
} else {
// 处理失败返回500
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);
// 处理异常返回500
return Response.serverError().build();
}
}
2. 处理删除状态
// PeerAwareInstanceRegistryImpl.class
public boolean deleteStatusOverride(String appName, String id,
InstanceStatus newStatus,
String lastDirtyTimestamp,
boolean isReplication) {
// 3 调用父类处理删除状态方法
if (super.deleteStatusOverride(appName, id, newStatus, lastDirtyTimestamp, isReplication)) {
// 4 处理成功后同步复制给集群节点
replicateToPeers(Action.DeleteStatusOverride, appName, id, null, null, isReplication);
return true;
}
return false;
}
3. 父类处理删除状态方法
// AbstractInstanceRegistry.class
public boolean deleteStatusOverride(String appName, String id,
InstanceStatus newStatus,
String lastDirtyTimestamp,
boolean isReplication) {
try {
// 打开读锁
read.lock();
STATUS_OVERRIDE_DELETE.increment(isReplication);
// 获取服务租约信息
Map<String, Lease<InstanceInfo>> gMap = registry.get(appName);
Lease<InstanceInfo> lease = null;
if (gMap != null) {
// 获取实例租约信息
lease = gMap.get(id);
}
if (lease == null) {
// 如果获取不到,返回 false
return false;
} else {
// 刷新续租过期时间
// 本地收到客户端删除状态请求,表明客户端还存活着,所以刷新续租过期时间
lease.renew();
InstanceInfo info = lease.getHolder();
// Lease is always created with its instance info object.
// This log statement is provided as a safeguard, in case this invariant is violated.
if (info == null) {
logger.error("Found Lease without a holder for instance id {}", id);
}
// 获取覆盖状态,并从 overriddenInstanceStatusMap 中删除
InstanceStatus currentOverride = overriddenInstanceStatusMap.remove(id);
if (currentOverride != null && info != null) {
// 设置实例信息的覆盖状态为 UNKNOWN
info.setOverriddenStatus(InstanceStatus.UNKNOWN);
// 设置实例信息的状态,但不标记 dirty
info.setStatusWithoutDirty(newStatus);
long replicaDirtyTimestamp = 0;
if (lastDirtyTimestamp != null) {
replicaDirtyTimestamp = Long.valueOf(lastDirtyTimestamp);
}
// If the replication's dirty timestamp is more than the existing one, just update
// it to the replica's.
if (replicaDirtyTimestamp > info.getLastDirtyTimestamp()) {
// 如果 客户端实例的最新修改时间戳(脏) 大于 本地注册表中相应实例信息的最新修改时间戳(脏)
// 则把本地的更新为客户端的
info.setLastDirtyTimestamp(replicaDirtyTimestamp);
}
// 设置行为类型为变更
info.setActionType(ActionType.MODIFIED);
// 实例变更租约信息放入最新变更队列
recentlyChangedQueue.add(new RecentlyChangedItem(lease));
// 设置本地相应实例信息的最新修改时间戳
info.setLastUpdatedTimestamp();
// 让相应缓存失效
invalidateCache(appName, info.getVIPAddress(), info.getSecureVipAddress());
}
return true;
}
} finally {
关闭读锁
read.unlock();
}
}
4. 同步复制给集群节点
《EurekaServer-处理客户端注册请求》中已讲过
5. 处理变更状态请求
// InstanceResource.class
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);
// 查询本地注册表中的实例信息,如果查询不到返回404
return Response.status(Status.NOT_FOUND).build();
}
// 6 处理变更状态
boolean isSuccess = registry.statusUpdate(app.getName(), id,
InstanceStatus.valueOf(newStatus), lastDirtyTimestamp,
"true".equals(isReplication));
if (isSuccess) {
logger.info("Status updated: {} - {} - {}", app.getName(), id, newStatus);
// 处理成功返回200
return Response.ok().build();
} else {
logger.warn("Unable to update status: {} - {} - {}", app.getName(), id, newStatus);
// 处理成功返回500
return Response.serverError().build();
}
} catch (Throwable e) {
logger.error("Error updating instance {} for status {}", id,
newStatus);
// 处理异常返回500
return Response.serverError().build();
}
}
6. 处理变更状态
// PeerAwareInstanceRegistryImpl.class
public boolean statusUpdate(final String appName, final String id,
final InstanceStatus newStatus, String lastDirtyTimestamp,
final boolean isReplication) {
// 7 调用父类处理变更状态方法
if (super.statusUpdate(appName, id, newStatus, lastDirtyTimestamp, isReplication)) {
// 4 处理成功后同步复制给集群节点
replicateToPeers(Action.StatusUpdate, appName, id, null, newStatus, isReplication);
return true;
}
return false;
}
7. 父类处理变更状态方法
// AbstractInstanceRegistry.class
public boolean statusUpdate(String appName, String id,
InstanceStatus newStatus, String lastDirtyTimestamp,
boolean isReplication) {
try {
// 打开读锁
read.lock();
STATUS_UPDATE.increment(isReplication);
// 获取服务租约信息
Map<String, Lease<InstanceInfo>> gMap = registry.get(appName);
Lease<InstanceInfo> lease = null;
if (gMap != null) {
// 获取实例租约信息
lease = gMap.get(id);
}
if (lease == null) {
return false;
} else {
// 刷新续租过期时间
// 本地收到客户端变更状态请求,表明客户端还存活着,所以刷新续租过期时间
lease.renew();
InstanceInfo info = lease.getHolder();
// Lease is always created with its instance info object.
// This log statement is provided as a safeguard, in case this invariant is violated.
if (info == null) {
logger.error("Found Lease without a holder for instance id {}", id);
}
if ((info != null) && !(info.getStatus().equals(newStatus))) {
// 当本地相关实例信息不为空,且状态和客户端请求变更的状态不一致
// Mark service as UP if needed
if (InstanceStatus.UP.equals(newStatus)) {
// 如果状态要变更为 UP ,且实例第一次启动,则记录启动时间
lease.serviceUp();
}
// This is NAC overriden status
// 保存变更的状态到 overriddenInstanceStatusMap
overriddenInstanceStatusMap.put(id, newStatus);
// Set it for transfer of overridden status to replica on
// replica start up
// 实例信息设置覆盖状态
info.setOverriddenStatus(newStatus);
long replicaDirtyTimestamp = 0;
// 设置实例信息的状态,但不记录脏时间戳
info.setStatusWithoutDirty(newStatus);
if (lastDirtyTimestamp != null) {
replicaDirtyTimestamp = Long.valueOf(lastDirtyTimestamp);
}
// If the replication's dirty timestamp is more than the existing one, just update
// it to the replica's.
if (replicaDirtyTimestamp > info.getLastDirtyTimestamp()) {
// 如果 客户端实例的最新修改时间戳(脏) 大于 本地注册表中相应实例信息的最新修改时间戳(脏)
// 则把本地的更新为客户端的
info.setLastDirtyTimestamp(replicaDirtyTimestamp);
}
// 设置行为类型为变更
info.setActionType(ActionType.MODIFIED);
// 放入最新变更队列
recentlyChangedQueue.add(new RecentlyChangedItem(lease));
// 设置本地相应实例信息的最新修改时间戳
info.setLastUpdatedTimestamp();
// 让相应缓存失效
invalidateCache(appName, info.getVIPAddress(), info.getSecureVipAddress());
}
return true;
}
} finally {
// 关闭读锁
read.unlock();
}
}
标签:info,状态,lastDirtyTimestamp,String,newStatus,EurekaServer,null,id,客户端 来源: https://blog.csdn.net/qq_42467713/article/details/117655124