java实现删除千万级数据的大key

来源:互联网 发布:lofter(乐乎) 编辑:程序博客网 时间:2024/03/02 13:39

redis删除千万级大key问题处理-20171017


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<Map.Entry<String, String>> hscanResult=jedis.hscan(key, cursor, scanParameters);
                cursor = hscanResult.getStringCursor();// 返回0 说明遍历完成
                List<Map.Entry<String, String>> scanResult = hscanResult.getResult();
                long t1 = System.currentTimeMillis();
                for(int m = 0;m < scanResult.size();m++){  
                    Map.Entry<String, String> 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);
        }
    }
    }
已经在使用中,删除大key无任何异常,且速度很快
原创粉丝点击