其他分享
首页 > 其他分享> > (九)EurekaServer-处理客户端变更状态、删除状态请求

(九)EurekaServer-处理客户端变更状态、删除状态请求

作者:互联网

0. 前言

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