redis的key删除的时候,是一个阻塞操作;

为什么会阻塞呢,是在删除key的时候,首先要寻找的key,然后进行删除,然而当key已经过期了,或者被他人删除之后,在删除的时候,就找不到这个key,那么它就一直寻找,新版的redis
有最大重试次数(以前的版本直接死循环),那么就会导致一直阻塞.这对于一线上项目来说,阻塞的这段时间可能是致命的;

如何避免??
1 删除普通key,删除key的时候,可以提前判断是否存在,在的时候再进行删除,这样就可以很大概率减少此类事件发生,例如这样:
if (redisTemplate.hasKey(RedisConstant.CASCADE_CHECK_COUNT +
cascadeDownTask.getId())) {
redisTemplate.delete(RedisConstant.CASCADE_CHECK_COUNT +
cascadeDownTask.getId()); }
不要直接删除
2 其实还有一种情况,删除的这个key为大 key,什么是大key,不是key有多大,而是key对应的value 很大,例如
redis有五种数据类型,有四个是集合,那么当key对应的集合 非常大的时候,此key 就叫做大key,那么删除的时候,也会导致阻塞问题;

我们可以利用类如 分段处理的方式去处理,例如: 目前redis中对应的数据类型是hash,然后hash中有大量 hk
,我们可以分段去删除,然后每次删除休眠一下,这样可以有效减少redis的压力
@SpringBootTest @Slf4j class AreaDemoControllerTest { // @Autowired //
IAreaDemoService areaDemoService; // // @Autowired // AreaDemoMapper
areaDemoMapper; // @Test // public void aaa(){ // List<AreaDemo> list =
areaDemoService.list(); // // List<AreaDemo> areaDemos1 = list.subList(0, 10);
// areaDemos1.forEach(demo -> demo.setId(null)); //
areaDemoMapper.updateBatch(areaDemos1); // } @Autowired RedisTemplate
redisTemplate; /** * @Description 模拟批量删除大key * @Author FL * @Date 11:08
2022/5/12 * @Param [] **/ @Test public void tetsts() { String key = "mapKey";
redisTemplate.opsForHash().put(key, "NAME", "小明");
redisTemplate.opsForHash().put(key, "age", "32");
redisTemplate.opsForHash().put(key, "add", "西湖");
redisTemplate.opsForHash().put(key, "tianqi", "晴朗");
redisTemplate.opsForHash().put(key, "heart", "nice");
redisTemplate.opsForHash().put(key, "shoot", "nike");
redisTemplate.opsForHash().put(key, "sex", "男"); Cursor scan =
redisTemplate.opsForHash().scan(key, ScanOptions.NONE); int i = 0; while
(scan.hasNext()) { Object next = scan.next(); System.out.println(++i); } //
redisTemplate.opsForHash().delete(key); removeBigKey(key, 2, 100);// 每次删除两个
休眠100ms } public void removeBigKey(String key, int scanCount, long
intervalMills) throws CacheException { final ScanOptions scanOptions =
ScanOptions.scanOptions().count(scanCount).build(); // 避免内存泄漏 // 执行循环删除
List<String> fieldKeyList = new ArrayList<>(); try { Cursor<Map.Entry<Object,
Object>> cursor = redisTemplate.opsForHash().scan(key, scanOptions); if
(ObjectUtil.isNotNull(cursor)) { while (cursor.hasNext()) { String fieldKey =
String.valueOf(cursor.next().getKey()); fieldKeyList.add(fieldKey); if
(fieldKeyList.size() >= scanCount) { // 批量删除 Object[] fields =
fieldKeyList.toArray(); redisTemplate.opsForHash().delete(key, fields);
log.info("[Big key] remove key: {}, fields size: {}", key, fields.length); //
清空列表,重置操作 fieldKeyList.clear(); // 沉睡等待,避免对 redis 压力太大 //
DateUtil.sleepInterval(intervalMills, TimeUnit.MILLISECONDS);
Thread.sleep(intervalMills); } } } // 最后 fieldKeyList
中可能还有剩余,不过一般数量不大,直接删除速度不会很慢 // 执行 key 本身的删除 //
redisTemplate.opsForHash().delete(key,fieldKeyList);
redisTemplate.opsForHash().delete(key, fieldKeyList.toArray()); } catch
(Exception e) { // log.error(); } } }
代码均在 test中

技术
下载桌面版
GitHub
Gitee
SourceForge
百度网盘(提取码:draw)
云服务器优惠
华为云优惠券
腾讯云优惠券
阿里云优惠券
Vultr优惠券
站点信息
问题反馈
邮箱:[email protected]
吐槽一下
QQ群:766591547
关注微信