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); } } }
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于