(八)EurekaServer-处理客户端下架请求

0. 前言

  • springboot版本:2.1.9.RELEASE
  • springcloud版本:Greenwich.SR4

1. 处理客户端下架请求

服务端处理处理客户端下架请求在 InstanceResource 类的 cancelLease() 方法

// InstanceResource.class
public Response cancelLease(
        @HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication) {
    // isReplication:是否是集群节点间的同步复制
    try {
        // 2 处理客户端下架
        boolean isSuccess = registry.cancel(app.getName(), id,
            "true".equals(isReplication));

        if (isSuccess) {
            logger.debug("Found (Cancel): {} - {}", app.getName(), id);
            // 处理成功返回200
            return Response.ok().build();
        } else {
            logger.info("Not Found (Cancel): {} - {}", app.getName(), id);
            // 处理失败返回404
            return Response.status(Status.NOT_FOUND).build();
        }
    } catch (Throwable e) {
        logger.error("Error (cancel): {} - {}", app.getName(), id, e);
        // 处理异常返回500
        return Response.serverError().build();
    }

}

2. registry.cancel()

// PeerAwareInstanceRegistryImpl.class
public boolean cancel(final String appName, final String id,
                      final boolean isReplication) {
    // 3 调用父类处理下架方法
    if (super.cancel(appName, id, isReplication)) {
        // 2.1 同步复制给集群节点
        replicateToPeers(Action.Cancel, appName, id, null, null, isReplication);
        synchronized (lock) {
            if (this.expectedNumberOfClientsSendingRenews > 0) {
                // Since the client wants to cancel it, reduce the number of clients to send renews
                // 处理成功后,预期收到心跳续租实例数-1
                this.expectedNumberOfClientsSendingRenews = this.expectedNumberOfClientsSendingRenews - 1;
                // 2.2 更新 预期每分钟收到心跳续租请求数
                updateRenewsPerMinThreshold();
            }
        }
        return true;
    }
    return false;
}
2.1 replicateToPeers()

《EurekaServer-同步注册表机制》中已讲解

2.2 updateRenewsPerMinThreshold()

《EurekaServer-同步注册表机制》中已讲解

3. super.cancel()

// AbstractInstanceRegistry.class
public boolean cancel(String appName, String id, boolean isReplication) {
    return internalCancel(appName, id, isReplication);
}

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 + ")"));
        }
        // 获取覆盖状态,并从 overriddenInstanceStatusMap 中删除
        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);
          // 如果获取不到实例租约信息,则返回 false
          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();
    }
}

4. 总结

  • 当服务端收到客户端下架请求时,会先从本地获取相应服务实例的租约信息并删除
  • 然后把实例下架时间和服务实例名的映射信息添加到最近下架队列,删除 overriddenInstanceStatusMap 中相应覆盖状态
  • 接着在实例租约信息中记录下架时间,转换成实例变更信息添加到最新变更队列,设置相应实例信息的最新修改时间戳(非脏时间戳)
  • 最后,让相应缓存失效,同步复制给集群节点,本地预期收到心跳续租实例数-1,更新预期每分钟收到心跳续租的请求数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值