zoukankan      html  css  js  c++  java
  • redis集群如何清理前缀相同的key

    最近经常收到redis集群告警,每天收到50多封邮件,实在不胜其烦,内存不够用,原因是有一些无用的key(约3000万)占用内存(具体不说了)。这部分内存不能被释放。

    原来的定期清理脚本的逻辑:

    打开一个redis链接,在内部循环从1000万到7亿之间的数据,然后加上前缀去批量删除,这种方式属于广撒网式的清理,穷举法,不但耗时,效果也不好。

    因为有的数字在redis中可能不存在,而且更重要的一点,如果有超过7亿的数字,这部分数据不会被清除,扩展性很差。

    (1)那么如何清理呢?redis集群没有keys这种方法,那么如何能快速准确地定位到这批key呢?

    我们可以根据RedisCluster集群提供的getClusterNodes方法,获取到这个redis-cluster的每个节点,然后再去逐个遍历节点,获取节点的Jedis对像,使用单个jedis对像

    再去获取前缀相同的keys

    (2)获取到key集合之后,再遍历这些key,使用JedisClusterCRC16.getSlot(key)方法,定位到key所在的slot,把在同一个slot的key批量删除,这样做,第一能保证需要删的key都存在于redis集群,第二批量删除,提高效率。

    具体代码:

                    Map<String, JedisPool> clusterNodes = jedis.getClusterNodes();
                    String keysPattern =  keyPrefix + ":*";
                    long countX = 0;
                    long sTime = System.currentTimeMillis();
                    for (Map.Entry<String, JedisPool> entry : clusterNodes.entrySet()) {  
                        Jedis jedisNode = entry.getValue().getResource();  
                        logger.info("redisip:{},port:{}" , jedisNode.getClient().getHost(), jedisNode.getClient().getPort());
                        if (!jedisNode.info("replication").contains("role:slave")) {  
                              Set<String> keys = jedisNode.keys(keysPattern);
                              logger.info("keys长度:{}" , keys.size());
                              Map<Integer, List<String>> map = new HashMap<>(6600);  
                              long countTmp = 0;
                                for (String key : keys) { int slot = JedisClusterCRC16.getSlot(key);
                                    /**
                                     * cluster模式执行多key操作的时候,这些key必须在同一个slot上,
                                     * 不然会报:JedisDataException 
                                     */
                                    //按slot将key分组,相同slot的key一起提交  
                                    if (map.containsKey(slot)) {  
                                        map.get(slot).add(key);  
                                    } else {  
                                         List<String> keyList = new ArrayList<String>();
                                         keyList.add(key);
                                         map.put(slot, keyList);  
                                        }
                                     
                                }
                                long count = 0;
                                for (Map.Entry<Integer, List<String>> integerListEntry : map.entrySet()) {  
                                    count += jedisNode.del(integerListEntry.getValue().toArray(new String[integerListEntry.getValue().size()]));  
                                    logger.info("删除:{}个",count);
                                    countX++;
                                }  
                         }
                    }
    //                 logger.info("删除完成,共删除:{}个",countX);
                        logger.info("删除userid key任务结束,一共删除key数量:{},耗时:{}", countX , System.currentTimeMillis() - sTime);
  • 相关阅读:
    logging——日志——转载02
    logging——日志——转载03
    c# 整型数据与字符串 的之间互换(原创)
    收到邮件且自动发送到对方提供的邮箱
    学习了1!+...10!
    Outlook 2003 Add in 部署笔记
    学会了调用方法
    c# 属性的作用
    (转)软件的围城,谈高级语言的学习(一位架构师的忠告!)
    常用命令控制行
  • 原文地址:https://www.cnblogs.com/fubaizhaizhuren/p/8405836.html
Copyright © 2011-2022 走看看