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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM