redis集群實現(xiàn)清理前綴相同的key
redis集群清理前綴相同的key
最近經(jīng)常收到redis集群告警,每天收到50多封郵件,實在不勝其煩,內(nèi)存不夠用,原因是有一些無用的key(約3000萬)占用內(nèi)存(具體不說了)。這部分內(nèi)存不能被釋放。
原來的定期清理腳本的邏輯
打開一個redis鏈接,在內(nèi)部循環(huán)從1000萬到7億之間的數(shù)據(jù),然后加上前綴去批量刪除,這種方式屬于廣撒網(wǎng)式的清理,窮舉法,不但耗時,效果也不好。
因為有的數(shù)字在redis中可能不存在,而且更重要的一點,如果有超過7億的數(shù)字,這部分數(shù)據(jù)不會被清除,擴展性很差。
(1)那么如何清理呢?redis集群沒有keys這種方法,那么如何能快速準(zhǔn)確地定位到這批key呢?
我們可以根據(jù)RedisCluster集群提供的getClusterNodes方法,獲取到這個redis-cluster的每個節(jié)點,然后再去逐個遍歷節(jié)點,獲取節(jié)點的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模式執(zhí)行多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任務(wù)結(jié)束,一共刪除key數(shù)量:{},耗時:{}", countX , System.currentTimeMillis() - sTime);
redis集群(jedis)批量刪除同一前綴
public Set<String> getByPrefix(String key) { Set<String> setResult = new HashSet<>(); try { ShardedJedis jedis = redisDataSource.getJedisClient(); Iterator<Jedis> jedisIterator = jedis.getAllShards().iterator(); while(jedisIterator.hasNext()){ setResult = jedisIterator.next().keys(key+"*"); } } catch (Exception e) { logger.error(e.getMessage(), e); } return setResult; }
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解Redis數(shù)據(jù)結(jié)構(gòu)之跳躍表
這篇文章主要介紹了Redis數(shù)據(jù)結(jié)構(gòu)中的跳躍表的相關(guān)知識,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-11-11記錄一次并發(fā)情況下的redis導(dǎo)致服務(wù)假死的問題解決
由于Redis需要依賴于操作系統(tǒng)環(huán)境,如果系統(tǒng)資源受限,比如過量的進程在擠占系統(tǒng)資源、系統(tǒng)死鎖等情況,本文主要介紹了記錄一次并發(fā)情況下的redis導(dǎo)致服務(wù)假死的問題解決,感興趣的可以了解一下2023-09-09緩存替換策略及應(yīng)用(以Redis、InnoDB為例)
本文以Redis、InnoDB為例給大家講解緩存替換策略及應(yīng)用,本文給大家提到五種置換策略,通過實例代碼給大家介紹的非常詳細,需要的朋友參考下吧2021-07-07嵌入式Redis服務(wù)器在Spring Boot測試中的使用教程
這篇文章主要介紹了嵌入式Redis服務(wù)器在Spring Boot測試中的使用,本文通過實例代碼場景分析給大家介紹的非常詳細,需要的朋友參考下吧2021-07-07在CenOS系統(tǒng)下安裝和配置Redis數(shù)據(jù)庫的教程
這篇文章主要介紹了在CenOS系統(tǒng)下安裝和配置Redis數(shù)據(jù)庫的教程,Redis是一個可基于內(nèi)存的高性能NoSQL數(shù)據(jù)庫,需要的朋友可以參考下2015-11-11