redis集群實(shí)現(xiàn)清理前綴相同的key
redis集群清理前綴相同的key
最近經(jīng)常收到redis集群告警,每天收到50多封郵件,實(shí)在不勝其煩,內(nèi)存不夠用,原因是有一些無(wú)用的key(約3000萬(wàn))占用內(nèi)存(具體不說(shuō)了)。這部分內(nèi)存不能被釋放。
原來(lái)的定期清理腳本的邏輯
打開(kāi)一個(gè)redis鏈接,在內(nèi)部循環(huán)從1000萬(wàn)到7億之間的數(shù)據(jù),然后加上前綴去批量刪除,這種方式屬于廣撒網(wǎng)式的清理,窮舉法,不但耗時(shí),效果也不好。
因?yàn)橛械臄?shù)字在redis中可能不存在,而且更重要的一點(diǎn),如果有超過(guò)7億的數(shù)字,這部分?jǐn)?shù)據(jù)不會(huì)被清除,擴(kuò)展性很差。
(1)那么如何清理呢?redis集群沒(méi)有keys這種方法,那么如何能快速準(zhǔn)確地定位到這批key呢?
我們可以根據(jù)RedisCluster集群提供的getClusterNodes方法,獲取到這個(gè)redis-cluster的每個(gè)節(jié)點(diǎn),然后再去逐個(gè)遍歷節(jié)點(diǎn),獲取節(jié)點(diǎn)的Jedis對(duì)像,使用單個(gè)jedis對(duì)像 再去獲取前綴相同的keys
(2)獲取到key集合之后,再遍歷這些key,使用JedisClusterCRC16.getSlot(key)方法,定位到key所在的slot,把在同一個(gè)slot的key批量刪除,這樣做,第一能保證需要?jiǎng)h的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長(zhǎng)度:{}" , 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操作的時(shí)候,這些key必須在同一個(gè)slot上,
* 不然會(huì)報(bào):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("刪除:{}個(gè)",count);
countX++;
}
}
}
// logger.info("刪除完成,共刪除:{}個(gè)",countX);
logger.info("刪除userid key任務(wù)結(jié)束,一共刪除key數(shù)量:{},耗時(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;
}
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Redis高可用部署架構(gòu)的實(shí)現(xiàn)
本文主要介紹了Redis高可用部署架構(gòu)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08
Redis?的內(nèi)存淘汰策略和過(guò)期刪除策略的區(qū)別
這篇文章主要介紹了Redis?的內(nèi)存淘汰策略和過(guò)期刪除策略的區(qū)別,Redis?是可以對(duì)?key?設(shè)置過(guò)期時(shí)間的,因此需要有相應(yīng)的機(jī)制將已過(guò)期的鍵值對(duì)刪除,而做這個(gè)工作的就是過(guò)期鍵值刪除策略2022-07-07
淺談一下Redis的數(shù)據(jù)結(jié)構(gòu)
這篇文章主要介紹了淺談一下Redis的數(shù)據(jù)結(jié)構(gòu),簡(jiǎn)單字符串結(jié)構(gòu)被用于存儲(chǔ)redis的key對(duì)象和String類型的value對(duì)象,其中的free和len字段可以輕松的使得在該字符串被修改時(shí)判斷是否需要擴(kuò)容,需要的朋友可以參考下2023-08-08
redis通過(guò)lua腳本,獲取滿足key pattern的所有值方式
這篇文章主要介紹了redis通過(guò)lua腳本,獲取滿足key pattern的所有值方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-03-03
Redis如何實(shí)現(xiàn)計(jì)數(shù)統(tǒng)計(jì)
這篇文章主要介紹了Redis如何實(shí)現(xiàn)計(jì)數(shù)統(tǒng)計(jì)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04
Redis數(shù)據(jù)庫(kù)分布式設(shè)計(jì)方案介紹
大家好,本篇文章主要講的是Redis數(shù)據(jù)庫(kù)分布式設(shè)計(jì)方案介紹,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下2022-01-01
Redis?RESP?協(xié)議實(shí)現(xiàn)實(shí)例詳解
這篇文章主要為大家介紹了Redis?RESP?協(xié)議實(shí)現(xiàn)實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
window手動(dòng)操作清理redis緩存的技巧總結(jié)
在本篇文章中小編給大家分享了關(guān)于window環(huán)境手動(dòng)操作清理redis緩存的方法和技巧,有興趣的朋友們可以跟著學(xué)習(xí)下。2019-07-07

