SpringCloudEureka服务下线和剔除流程及源码

服务下线在这里插入图片描述
在这里插入图片描述


```java
/**
     * @Description: 服务下线
     * @Author: PABLO
     * @Date: 2022/5/18 15:27
     * @Params: [appName, id, isReplication]
     * @Return: boolean
     **/
    protected boolean internalCancel(String appName, String id, boolean isReplication) {
    
    

        read.lock();
        try {
    
    
            CANCEL.increment(isReplication);
            //获取对应集群
            Map<String, Lease<InstanceInfo>> gMap = registry.get(appName);
            Lease<InstanceInfo> leaseToCancel = null;
            if (gMap != null) {
    
    
                //删除对应节点信息
                leaseToCancel = gMap.remove(id);
            }
            recentCanceledQueue.add(new Pair<Long, String>(System.currentTimeMillis(), appName + "(" + id + ")"));
            InstanceInfo.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) {
    
    
                    //状态更改delete
                    instanceInfo.setActionType(InstanceInfo.ActionType.DELETED);
                    recentlyChangedQueue.add(new AbstractInstanceRegistry.RecentlyChangedItem(leaseToCancel));
                    instanceInfo.setLastUpdatedTimestamp();
                    vip = instanceInfo.getVIPAddress();
                    svip = instanceInfo.getSecureVipAddress();
                }
                //删除缓存
                invalidateCache(appName, vip, svip);
                logger.info("Cancelled instance {}/{} (replication={})", appName, id, isReplication);
            }
        } finally {
    
    
            read.unlock();
        }

        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();
            }
        }

        return true;
    }

服务剔除

/**
     * @Description: 服务剔除
     * @Author: PABLO
     * @Date: 2022/5/18 15:56
     * @Params: [additionalLeaseMs]
     * @Return: void
     **/
    public void evict(long additionalLeaseMs) {
    
    
        logger.debug("Running the evict task");
        //判断自我保护机制,如打开不可剔除,如关闭自我保护,心跳检测不到的节点就会被剔除
        //自我保护机制的目的是为了避免误杀(如网络原因导致心跳超时),这样正常的服务将不会被访问到
        //但如自身出现故障,将接受不到节点的心跳,导致服务瘫痪
        //可设置阈值控制自我保护机制的是否开启,如到达阈值将不会剔除任何节点,当超过阈值,才恢复正常状态,剔除心跳检测不到的节点
        //阈值默认0.85,该阈值是所有微服务节点数量下界的阈值,如100台机器,宕机15+,就会触发自我保护
        if (!isLeaseExpirationEnabled()) {
    
    
            logger.debug("DS: lease expiration is currently disabled.");
            return;
        }

        //获取所有过期的节点(租约),我们的节点被Lease租约对象所包含,控制租约相关事宜
        List<Lease<InstanceInfo>> expiredLeases = new ArrayList<>();
        //遍历注册表
        for (Map.Entry<String, Map<String, Lease<InstanceInfo>>> groupEntry : registry.entrySet()) {
    
    
            Map<String, Lease<InstanceInfo>> leaseMap = groupEntry.getValue();
            if (leaseMap != null) {
    
    
                for (Map.Entry<String, Lease<InstanceInfo>> leaseEntry : leaseMap.entrySet()) {
    
    
                    Lease<InstanceInfo> lease = leaseEntry.getValue();
                    //判断租约是否过期
                    if (lease.isExpired(additionalLeaseMs) && lease.getHolder() != null) {
    
    
                        expiredLeases.add(lease);
                    }
                }
            }
        }

        //避免大量下线,判断阈值
        //获取当前注册表大小
        int registrySize = (int) getLocalRegistrySize();
        //计算阈值对应的机器数量 * 0.85 默认
        int registrySizeThreshold = (int) (registrySize * serverConfig.getRenewalPercentThreshold());
        //总数-阈值对应的值  ,用于判断当前过期节点(即将操作下线的节点的个数)和阈值控制的节点个数
        //自我保护默认开启,真正开启自我保护是接受客户端心跳未达到预期阈值,server进入自我保护后客户端服务不一定会剔除
        int evictionLimit = registrySize - registrySizeThreshold;
        int toEvict = Math.min(expiredLeases.size(), evictionLimit);
        if (toEvict > 0) {
    
    
            logger.info("Evicting {} items (expired={}, evictionLimit={})", toEvict, expiredLeases.size(), evictionLimit);
            Random random = new Random(System.currentTimeMillis());
            for (int i = 0; i < toEvict; i++) {
    
    
                //随机下线
                int next = i + random.nextInt(expiredLeases.size() - i);
                Collections.swap(expiredLeases, i, next);
                Lease<InstanceInfo> lease = expiredLeases.get(i);
                String appName = lease.getHolder().getAppName();
                String id = lease.getHolder().getId();
                EXPIRED.increment();
                logger.warn("DS: Registry: expired lease for {}/{}", appName, id);
                //剔除
                internalCancel(appName, id, false);
            }
        }
    }

猜你喜欢

转载自blog.csdn.net/GiantCrocodile/article/details/124843872