| 
1 | 1 | package com.sohu.cache.redis.impl;  | 
2 | 2 | 
 
  | 
 | 3 | +import com.sohu.cache.constant.ClusterOperateResult;  | 
3 | 4 | import com.sohu.cache.constant.InstanceStatusEnum;  | 
4 | 5 | import com.sohu.cache.dao.AppDao;  | 
5 | 6 | import com.sohu.cache.dao.InstanceDao;  | 
6 | 7 | import com.sohu.cache.dao.MachineDao;  | 
7 | 8 | import com.sohu.cache.entity.AppDesc;  | 
8 | 9 | import com.sohu.cache.entity.InstanceInfo;  | 
 | 10 | +import com.sohu.cache.entity.InstanceSlotModel;  | 
9 | 11 | import com.sohu.cache.entity.MachineInfo;  | 
10 | 12 | import com.sohu.cache.machine.MachineCenter;  | 
11 | 13 | import com.sohu.cache.protocol.MachineProtocol;  | 
 | 
15 | 17 | import com.sohu.cache.redis.RedisConfigTemplateService;  | 
16 | 18 | import com.sohu.cache.redis.RedisDeployCenter;  | 
17 | 19 | import com.sohu.cache.redis.enums.RedisConfigEnum;  | 
 | 20 | +import com.sohu.cache.stats.instance.InstanceDeployCenter;  | 
18 | 21 | import com.sohu.cache.util.ConstUtils;  | 
19 | 22 | import com.sohu.cache.util.IdempotentConfirmer;  | 
20 | 23 | import com.sohu.cache.util.TypeUtil;  | 
@@ -51,6 +54,8 @@ public class RedisDeployCenterImpl implements RedisDeployCenter {  | 
51 | 54 | 
 
  | 
52 | 55 |     private RedisConfigTemplateService redisConfigTemplateService;  | 
53 | 56 | 
 
  | 
 | 57 | +    private InstanceDeployCenter instanceDeployCenter;  | 
 | 58 | +      | 
54 | 59 |     @Override  | 
55 | 60 |     public boolean deployClusterInstance(long appId, List<RedisClusterNode> clusterNodes, int maxMemory) {  | 
56 | 61 |         if (!isExist(appId)) {  | 
@@ -975,7 +980,7 @@ public boolean clusterFailover(final long appId, int slaveInstanceId, final Stri  | 
975 | 980 |         Assert.isTrue(appDesc != null);  | 
976 | 981 |         int type = appDesc.getType();  | 
977 | 982 |         if (!TypeUtil.isRedisCluster(type)) {  | 
978 |  | -            logger.error("{} is not redis type", appDesc);  | 
 | 983 | +            logger.error("{} is not redis cluster type", appDesc);  | 
979 | 984 |             return false;  | 
980 | 985 |         }  | 
981 | 986 |         InstanceInfo instanceInfo = instanceDao.getInstanceInfoById(slaveInstanceId);  | 
@@ -1007,6 +1012,115 @@ public boolean execute() {  | 
1007 | 1012 |         }  | 
1008 | 1013 |         return true;  | 
1009 | 1014 |     }  | 
 | 1015 | +      | 
 | 1016 | +    @Override  | 
 | 1017 | +    public ClusterOperateResult delNode(final Long appId, int delNodeInstanceId) {  | 
 | 1018 | +        final InstanceInfo forgetInstanceInfo = instanceDao.getInstanceInfoById(delNodeInstanceId);  | 
 | 1019 | +        final String forgetNodeId = redisCenter.getNodeId(appId, forgetInstanceInfo.getIp(),  | 
 | 1020 | +                forgetInstanceInfo.getPort());  | 
 | 1021 | +        if (StringUtils.isBlank(forgetNodeId)) {  | 
 | 1022 | +            logger.warn("{} nodeId is null", forgetInstanceInfo.getHostPort());  | 
 | 1023 | +            return ClusterOperateResult.fail(String.format("%s nodeId is null", forgetInstanceInfo.getHostPort()));  | 
 | 1024 | +        }  | 
 | 1025 | +        List<InstanceInfo> instanceInfos = instanceDao.getInstListByAppId(appId);  | 
 | 1026 | +        for (InstanceInfo instanceInfo : instanceInfos) {  | 
 | 1027 | +            if (instanceInfo == null) {  | 
 | 1028 | +                continue;  | 
 | 1029 | +            }  | 
 | 1030 | +            if (instanceInfo.isOffline()) {  | 
 | 1031 | +                continue;  | 
 | 1032 | +            }  | 
 | 1033 | +            // 过滤当前节点  | 
 | 1034 | +            if (forgetInstanceInfo.getHostPort().equals(instanceInfo.getHostPort())) {  | 
 | 1035 | +                continue;  | 
 | 1036 | +            }  | 
 | 1037 | +            final String instanceHost = instanceInfo.getIp();  | 
 | 1038 | +            final int instancePort = instanceInfo.getPort();  | 
 | 1039 | +            boolean isForget = new IdempotentConfirmer() {  | 
 | 1040 | +                @Override  | 
 | 1041 | +                public boolean execute() {  | 
 | 1042 | +                    String response = null;  | 
 | 1043 | +                    Jedis jedis = null;  | 
 | 1044 | +                    try {  | 
 | 1045 | +                        jedis = redisCenter.getJedis(appId, instanceHost, instancePort);  | 
 | 1046 | +                        logger.warn("{}:{} is forgetting {}", instanceHost, instancePort, forgetNodeId);  | 
 | 1047 | +                        response = jedis.clusterForget(forgetNodeId);  | 
 | 1048 | +                        boolean success = response != null && response.equalsIgnoreCase("OK");  | 
 | 1049 | +                        logger.warn("{}:{} is forgetting {} result is {}", instanceHost, instancePort, forgetNodeId,  | 
 | 1050 | +                                success);  | 
 | 1051 | +                        return success;  | 
 | 1052 | +                    } catch (Exception e) {  | 
 | 1053 | +                        logger.error(e.getMessage());  | 
 | 1054 | +                    } finally {  | 
 | 1055 | +                        if (jedis != null) {  | 
 | 1056 | +                            jedis.close();  | 
 | 1057 | +                        }  | 
 | 1058 | +                    }  | 
 | 1059 | +                    return response != null && response.equalsIgnoreCase("OK");  | 
 | 1060 | +                }  | 
 | 1061 | +            }.run();  | 
 | 1062 | +            if (!isForget) {  | 
 | 1063 | +                logger.warn("{}:{} forget {} failed", instanceHost, instancePort, forgetNodeId);  | 
 | 1064 | +                return ClusterOperateResult.fail(String.format("%s:%s forget %s failed", instanceHost, instancePort, forgetNodeId));  | 
 | 1065 | +            }  | 
 | 1066 | +        }  | 
 | 1067 | +          | 
 | 1068 | +        // shutdown  | 
 | 1069 | +        boolean isShutdown = instanceDeployCenter.shutdownExistInstance(appId, delNodeInstanceId);  | 
 | 1070 | +        if (!isShutdown) {  | 
 | 1071 | +            logger.warn("{} shutdown failed", forgetInstanceInfo.getHostPort());  | 
 | 1072 | +            return ClusterOperateResult.fail(String.format("%s shutdown failed", forgetInstanceInfo.getHostPort()));  | 
 | 1073 | +        }  | 
 | 1074 | +          | 
 | 1075 | +        return ClusterOperateResult.success();  | 
 | 1076 | +    }  | 
 | 1077 | +      | 
 | 1078 | +      | 
 | 1079 | +    /**  | 
 | 1080 | +     * 1. 被forget的节点必须在线(这个条件有待验证)   | 
 | 1081 | +     * 2. 被forget的节点不能有从节点   | 
 | 1082 | +     * 3. 被forget的节点不能有slots  | 
 | 1083 | +     */  | 
 | 1084 | +    @Override  | 
 | 1085 | +    public ClusterOperateResult checkClusterForget(Long appId, int forgetInstanceId) {  | 
 | 1086 | +        // 0.各种验证  | 
 | 1087 | +        Assert.isTrue(appId > 0);  | 
 | 1088 | +        Assert.isTrue(forgetInstanceId > 0);  | 
 | 1089 | +        AppDesc appDesc = appDao.getAppDescById(appId);  | 
 | 1090 | +        Assert.isTrue(appDesc != null);  | 
 | 1091 | +        int type = appDesc.getType();  | 
 | 1092 | +        if (!TypeUtil.isRedisCluster(type)) {  | 
 | 1093 | +            logger.error("{} is not redis cluster type", appDesc);  | 
 | 1094 | +            return ClusterOperateResult.fail(String.format("instanceId: %s must be cluster type", forgetInstanceId));  | 
 | 1095 | +        }  | 
 | 1096 | +        InstanceInfo instanceInfo = instanceDao.getInstanceInfoById(forgetInstanceId);  | 
 | 1097 | +        Assert.isTrue(instanceInfo != null);  | 
 | 1098 | +        String forgetHost = instanceInfo.getIp();  | 
 | 1099 | +        int forgetPort = instanceInfo.getPort();  | 
 | 1100 | +        // 1.是否在线  | 
 | 1101 | +        boolean isRun = redisCenter.isRun(appId, forgetHost, forgetPort);  | 
 | 1102 | +        if (!isRun) {  | 
 | 1103 | +            logger.warn("{}:{} is not run", forgetHost, forgetPort);  | 
 | 1104 | +            return ClusterOperateResult.fail(String.format("被forget的节点(%s:%s)必须在线", forgetHost, forgetPort));  | 
 | 1105 | +        }  | 
 | 1106 | +        // 2.被forget的节点不能有从节点  | 
 | 1107 | +        Boolean hasSlaves = redisCenter.hasSlaves(appId, forgetHost, forgetPort);  | 
 | 1108 | +        if (hasSlaves == null || hasSlaves) {  | 
 | 1109 | +            logger.warn("{}:{} has slave", forgetHost, forgetPort);  | 
 | 1110 | +            return ClusterOperateResult.fail(String.format("被forget的节点(%s:%s)不能有从节点", forgetHost, forgetPort));  | 
 | 1111 | +        }  | 
 | 1112 | + | 
 | 1113 | +        // 3.被forget的节点不能有slots  | 
 | 1114 | +        Map<String, InstanceSlotModel> clusterSlotsMap = redisCenter.getClusterSlotsMap(appId);  | 
 | 1115 | +        InstanceSlotModel instanceSlotModel = clusterSlotsMap.get(instanceInfo.getHostPort());  | 
 | 1116 | +        if (instanceSlotModel != null && instanceSlotModel.getSlotList() != null  | 
 | 1117 | +                && instanceSlotModel.getSlotList().size() > 0) {  | 
 | 1118 | +            logger.warn("{}:{} has slots", forgetHost, forgetPort);  | 
 | 1119 | +            return ClusterOperateResult.fail(String.format("被forget的节点(%s:%s)不能持有slot", forgetHost, forgetPort));  | 
 | 1120 | +        }  | 
 | 1121 | + | 
 | 1122 | +        return ClusterOperateResult.success();  | 
 | 1123 | +    }  | 
1010 | 1124 | 
 
  | 
1011 | 1125 |     /**  | 
1012 | 1126 |      * 拷贝redis配置  | 
 | 
0 commit comments