目录
- redis集群清理前缀相同的key
- 原来的定期清理脚本的逻辑
- redis集群(jedis)批量删除同一前缀
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);
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;
}
以上为个人经验,希望能给大家一个参考,也希望大家多多支持www.887551.com。