keys * 这个命令千万别在生产环境乱用。特别是数据庞大的情况下。因为Keys会引发Redis锁,并且增加Redis的CPU占用。
在生产环境中可以使用scan命令。
public void deleteRedisMd5Phone(){
//设置需要删除的key前缀
String key = "md5Phone";
try {
deleteKeysByScan(key)
}catch (Exception e){
log.error(e.getMessage());
}
}
/**
* 删除指定前缀的一系列key
*
* @param pattern 匹配keys的规则
*/
public void deleteKeysByScan(String pattern) {
long start = System.currentTimeMillis();
log.info("清理redis{}key记录缓存的定时任务开始执行", pattern);
String param = pattern + "*";
int count = 0;
while(true){
long start1 = System.currentTimeMillis();
log.info("第{}轮Redis删除开始",count);
//设置每轮搜索到10W条数据
Set<String> keys = getValuesForStringByScan(param);
count++;
//找不到或者最多删除6千万条 可以自己设置
if(keys.isEmpty()||count>600){
break;
}
redisTemplate.delete(keys);
log.info("第{}轮Redis删除开始,该轮执行了{}毫秒",count,(System.currentTimeMillis() - start1));
}
log.info("清理redis{}key记录缓存的定时任务执行结束,耗时:{}", pattern, (System.currentTimeMillis() - start));
}
/**
* 获取匹配的所有key,使用scan避免阻塞
*
* @param patten 匹配keys的规则
* @return 返回获取到的keys
*/
public Set<String> getValuesForStringByScan(String patten) {
Set<String> res = new HashSet<>();
redisTemplate.execute(connect -> {
Set<String> binaryKeys = new HashSet<>();
Cursor<byte[]> cursor = connect.scan(new ScanOptions.ScanOptionsBuilder().match(patten).count(100000).build());
while (cursor.hasNext() && binaryKeys.size() < 100000) {
binaryKeys.add(new String(cursor.next()));
}
res.addAll(binaryKeys);
return binaryKeys;
}, true);
return res;
}