【源码】eureka srver 响应服务下线过程解析

1.源码定位

方法:com.netflix.eureka.resources.InstanceResource#cancelLease

源码版本:v1.7.x

源码地址:https://github.com/Netflix/eureka/tree/v1.7.x



2. 源码解析

protected boolean internalCancel(String appName, String id, boolean isReplication) {
        try {
            read.lock();

            CANCEL.increment(isReplication);
						// 根据服务名称从注册表中获取服务实例列表信息
            Map<String, Lease<InstanceInfo>> gMap = registry.get(appName);
            Lease<InstanceInfo> leaseToCancel = null;
            if (gMap != null) {
								//移除服务实例
                leaseToCancel = gMap.remove(id);
            }
            synchronized (recentCanceledQueue) {
                // 添加到统计队列,最近下线记录队列中
                recentCanceledQueue.add(new Pair<Long, String>(System.currentTimeMillis(), appName + "(" + id + ")"));
            }
            // 服务实例状态表也移除该服务实例信息
            InstanceStatus instanceStatus = overriddenInstanceStatusMap.remove(id);
            if (instanceStatus != null) {
                logger.debug("Removed instance id {} from the overridden map which has value {}", id, instanceStatus.name());
            }
            if (leaseToCancel == null) {
                CANCEL_NOT_FOUND.increment(isReplication);
                logger.warn("DS: Registry: cancel failed because Lease is not registered for: {}/{}", appName, id);
                return false;
            } else {
								// 修改下线时间
                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);
                logger.info("Cancelled instance {}/{} (replication={})", appName, id, isReplication);
                return true;
            }
        } finally {
            read.unlock();
        }
    }
@Override
    public boolean cancel(final String appName, final String id,
                          final boolean isReplication) {
				// 服务下线
        if (super.cancel(appName, id, isReplication)) {
						//成功下线后要同步到其他eureka server节点
            replicateToPeers(Action.Cancel, appName, id, null, null, isReplication);
            synchronized (lock) {
								// 这里还要更新一下关于自我保护计算的两个核心值
                if (this.expectedNumberOfRenewsPerMin > 0) {
                    // Since the client wants to cancel it, reduce the threshold (1 for 30 seconds, 2 for a minute)
                    this.expectedNumberOfRenewsPerMin = this.expectedNumberOfRenewsPerMin - 2;
                    this.numberOfRenewsPerMinThreshold =
                            (int) (this.expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold());
                }
            }
            return true;
        }
        return false;
    }

大概流程:

  1. 从eureka server的注册表中移除服务实例信息
  2. 加入到recentlyChangedQueue中,做增量下发
  3. 读写缓存失效invalidateCache
  4. 同步到其他节点 replicateToPeers
  5. 更新自我保护机制核心变量值expectedNumberOfRenewsPerMinnumberOfRenewsPerMinThreshold


3.小结

从注册register,心跳发送rewLease,服务实例下线cancel这三个基本说完了。其实总结下来就是只有几点:

  1. 更新服务实例注册表 registry
  2. 更新服务实例状态表 overriddenInstanceStatusMap
  3. 添加到recentlyChangedQueue做增量下发
  4. 读写缓存失效
  5. 同步到其他eureka server节点
上一篇:c# C#设置WebBrowser使用Edge内核


下一篇:动态字节码技术 javassist 初探