原创不易,转载请注明出处
系列文章目录
- 《SpringCloud Eureka Server源码解析(启动流程)》
- 《Eureka Server源码解析(服务注册流程)》
- 《Eureka Server源码解析(服务续约流程)》
- 《深度解析Eureka的自我保护机制》
前言
本文主要是解析下Eureka Server 处理客户端服务主动下线流程代码,服务主动下线其实很简单,就是客户端服务发送服务主动下线请求给Eureka Server ,Eureka Server 收到请求后将对应的实例信息从注册表中删除,删除本地多级缓存中关于该实例信息的数据,这样子服务发现的时候就不会被拉取到该实例的信息,最后就是将服务下线请求同步给Eureka Server 集群其他节点,接下来我们就看看Eureka Server 是怎样处理服务主动下线请求的。
1.源码解析
客户端服务delete请求/apps/{appName}/{instanceId} 路径到Eureka Server进行服务主动下线。
然后在Eureka Server 中InstanceResource 的cancelLease 方法接收服务下线请求并处理,我们看下
@DELETE
public Response cancelLease(
@HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication) {
boolean isSuccess = registry.cancel(app.getName(), id,
"true".equals(isReplication));
// 此处省略代码若干
return Response.ok().build();
}
可以看到就是调用的注册表cancel进行服务主动下线,参数1:appName,参数2:instanceId 实例id, 参数3:是否是集群其他节点同步过来的。接下来我们就看下注册表PeerAwareInstanceRegistry 的cancel方法
PeerAwareInstanceRegistry #cancel
@Override
public boolean cancel(final String appName, final String id,
final boolean isReplication) {
if (super.cancel(appName, id, isReplication)) {
replicateToPeers(Action.Cancel, appName, id, null, null, isReplication);
return true;
}
return false;
}
套路都是一样的,先是调用父类AbstractInstanceRegistry 的cancel 方法进行本地注册表变更,服务下线就是删除对应的服务实例信息。变更完本地服务注册表后,将服务主动下线请求同步给Eureka Server 集群的其他节点。
接下来我们看下本地注册表服务下线的流程。
@Override
public boolean cancel(String appName, String id, boolean isReplication) {
return internalCancel(appName, id, isReplication);
}
这个internalCancel 方法内容比较多,我们分为几部分看看。
先是获取读写锁的读锁,其实在服务注册处理的那段代码也是获取读锁的。
// 获取appName 对应的所有实例集合
Map<String, Lease<InstanceInfo>> gMap = registry.get(appName);
Lease<InstanceInfo> leaseToCancel = null;
if (gMap != null) {
// 根据实例id 移除对应的实例租约信息
leaseToCancel = gMap.remove(id);
}
先是根据appName 从注册表中获取到对应的所有实例集合,也就是个map,然后根据实例id (instanceId) 从实例集合中移除对应实例的租约信息(服务信息)。
// 将变更信息 扔到最近删除队列中
recentCanceledQueue.add(new Pair<Long, String>(System.currentTimeMillis(), appName + "(" + id + ")"));
InstanceStatus instanceStatus = overriddenInstanceStatusMap.remove(id);
将要删除的appName+实例id 信息放入最近删除队列中,从实例状态map中移除该实例的状态信息。
// 变更实例剔除时间
leaseToCancel.cancel();
InstanceInfo instanceInfo = leaseToCancel.getHolder();
String vip = null;
String svip = null;
if (instanceInfo != null) {
instanceInfo.setActionType(ActionType.DELETED);
// 放入最近变更队列中
recentlyChangedQueue.add(new RecentlyChangedItem(leaseToCancel));
instanceInfo.setLastUpdatedTimestamp();
vip = instanceInfo.getVIPAddress();
svip = instanceInfo.getSecureVipAddress();
}
// 删除实例对应的缓存数据
invalidateCache(appName, vip, svip);
更新实例剔除时间, 删除该实例对应本地缓存数据。
// 更新 需要发送心跳的客户端数量
synchronized (lock) {
if (this.expectedNumberOfClientsSendingRenews > 0) {
// Since the client wants to cancel it, reduce the number of clients to send renews.
this.expectedNumberOfClientsSendingRenews = this.expectedNumberOfClientsSendingRenews - 1;
updateRenewsPerMinThreshold();
}
}
更新需要发送续约信息客户端数量,毕竟是服务下线,就少了一个需要发送续约信息的客户端,更新自我保护机制触发阈值,这块涉及到Eureka Server 自我保护机制实现原理,感兴趣的小伙伴可以看下《深度解析Eureka的自我保护机制》 一文。
好了,到这服务主动下线的源码就解析完了。
2.流程图
高清大图:链接
总结
Eureka Server 处理服务主动下线主要是干了2件事,1是删除本地注册表中关于该实例的租约信息,删除本地多级缓存中关于该实例的信息;2是将服务下线请求同步给集群中的其他节点。