1、问题描述
redis 数据存储了几千万的数据的 key,使用 del 无法删除,占用大量 redis 内存,且会导致 redis 切机
2、问题分析
redis 使用 del 每秒可清理 100w~几百万个值,假如是几千万的大数据量的 key 时,会导致 redis 阻塞 10 秒以上,sentinel 会检测 redis 状态判断 redis 故障,而进行切换,应用程序也会在这期间连不上 redis 而崩溃,所以需分批处理,别因删除数据而阻塞 redis,从而导致程序故障。
3、问题处理
redis v2.8 以上推出了 scan 命令,以时间复杂度为 O(1)的方式,遍历包含 n 个元素的大 key,避免使用单个 O(n)的大 key 命令,导致 redis 阻塞,java 实现代码为:
public boolean delLargeHashKey(String key, int scanCount) throws Exception{
boolean broken = false;
Jedis jedis = pool.getSentineJedis();
try{
if (jedis!=null)
{
ScanParams scanParameters = new ScanParams();
//一次获取500条,可自定义条数
scanParameters.count(scanCount);
String cursor = "";
while ((!cursor.equals("0")) || (cursor == "0")){
//使用hscan命令获取500条数据,使用cursor游标记录位置,下次循环使用
ScanResult> hscanResult=jedis.hscan(key, cursor, scanParameters);
cursor = hscanResult.getStringCursor();// 返回0 说明遍历完成
List> scanResult = hscanResult.getResult();
long t1 = System.currentTimeMillis();
for(int m = 0;m < scanResult.size();m++){
Map.Entry mapentry = scanResult.get(m);
//System.out.println("key: "+mapentry.getKey()+" value: "+mapentry.getValue());
jedis.hdel(key, mapentry.getKey());
}
long t2 = System.currentTimeMillis();
System.out.println("删除"+scanResult.size()+"条数据,耗时: "+(t2-t1)+"毫秒,cursor:"+cursor);
}
return true;
}
return false;
}catch (JedisException e) {
broken = pool.handleJedisException(e);
if (broken) {
pool.closeResource(jedis, broken);
}
throw e;
} finally {
if (!broken && jedis != null) {
pool.sentinel_close(jedis);
}
}
}
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于