当前位置: 首页 > news >正文

Redis——BigKey

BigKey

1 多大算 BigKey?

阿里云 Redis 开发规范:

  • string 类型的数据控制在 10KB 以内,hash, list, set, zset 元素数量不要超过 5000
  • 非字符串的 BigKey,不要使用 del 删除,而是使用 hsacn, sscan, zscan 方式 渐进式删除。同时,要防止 BigKey 过期时自动删除,因为自动删除会使用 del 指令

2. BigKey 有什么危害?

  • 如果没有配置 Redis 非阻塞删除,则在过期自动删除 BigKey 时会导致 Redis 主进程阻塞。
  • 如果在分片集群中,则会造成某个节点被频繁访问,单点流量过高的问题。
  • 如果有主从复制,则可能延长主从不一致的时间。
  • 在查询 BigKey 时,可能导致网络设备带宽耗尽,从而超时。

3. BigKey 是如何产生的?

BigKey 一般不是突然就产生的,而是 逐步积累 的。比如粉丝列表、统计报表。

如果使用 Redis 不当,也可能会造成 BigKey,例如:

  • 把大文件直接存入 Redis。
  • 把对象的键作为 hash 数据结构内部的键,从而往一个 hash 数据结构中存储大量对象。

4. 如何发现 BigKey?

  • redis-cli --bigkeys:在 shell 中执行这个命令后,可以分析出最大的数据。
  • memory useage xxx:在 redis-cli 里执行这个命令后,可以获取 xxx 所占的字节数。

5. 如何删除 BigKey?

5.1 string 类型

一般用 del,保险起见,可以使用 unlink

5.2 hash 类型

使用 hscan + hdel,每次删除 100 个键值对,使用 redisTemplate 来操作是这样的:

final int BATCH_SIZE = 100;
ScanOptions options = ScanOptions.scanOptions().count(BATCH_SIZE).build();
Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan(KEY, options);
while (cursor.hasNext()) {Object[] keys = new Object[BATCH_SIZE];int elementCount = 0;while (cursor.hasNext() && elementCount < BATCH_SIZE) {Map.Entry<Object, Object> entry = cursor.next();keys[elementCount++] = entry.getKey();}redisTemplate.opsForHash().delete(KEY, keys);
}
cursor.close();
redisTemplate.delete(KEY);

5.3 list 类型

使用 ltrim,每次删除 100 个元素,使用 redisTemplate 来操作是这样的:

final int BATCH_SIZE = 100;
long size = Optional.ofNullable(redisTemplate.opsForList().size(KEY)).orElse(0L);
long end = size - 1;
while (end > 0) {end -= BATCH_SIZE;redisTemplate.opsForList().trim(KEY, 0, end);
}
redisTemplate.delete(KEY);

注:这些操作不是原子的,按理应该写一个 lua 脚本来保证操作的原子性,但是 lua 脚本在 Redis 中执行时会阻塞其他操作,还不如直接使用 del 指令。一般情况下,删除这个 list 时需要确保没有人访问它,所以不是原子的也可以

5.4 set 类型

使用 sscan + srem,每次删除 100 个元素,使用 redisTemplate 来操作是这样的:

final int BATCH_SIZE = 100;
ScanOptions scanOptions = ScanOptions.scanOptions().count(BATCH_SIZE).build();
Cursor<Object> cursor = redisTemplate.opsForSet().scan(KEY, scanOptions);
while (cursor.hasNext()) {Object[] keys = new Object[BATCH_SIZE];int elementCount = 0;while (cursor.hasNext() && elementCount < BATCH_SIZE) {keys[elementCount++] = cursor.next();}redisTemplate.opsForSet().remove(KEY, keys);
}
cursor.close();
redisTemplate.delete(KEY);

5.5 zset 类型

使用 zscan + zrem,每次删除 100 个元素,使用 redisTemplate 来操作是这样的:

final int BATCH_SIZE = 100;
ScanOptions scanOptions = ScanOptions.scanOptions().count(BATCH_SIZE).build();
Cursor<TypedTuple<Object>> cursor = redisTemplate.opsForZSet().scan(KEY, scanOptions);
while (cursor.hasNext()) {Object[] keys = new Object[BATCH_SIZE];int elementCount = 0;while (cursor.hasNext() && elementCount < BATCH_SIZE) {TypedTuple<Object> typedTuple = cursor.next();keys[elementCount++] = typedTuple.getValue();}redisTemplate.opsForZSet().remove(KEY, keys);
}
cursor.close();
redisTemplate.delete(KEY);

6. BigKey 优化

Redis 默认的过期删除策略用的删除指令是 del,这个指令是 阻塞 的,所以在删除 BigKey 时会造成 Redis 卡顿。此外,Redis 还提供了一个指令 unlink,这个指令是 非阻塞 的,可以通过配置来让 Redis 使用 unlink 删除过期的数据,配置如下:

# 当 Redis 服务器主动删除对象(如 过期键、内存淘汰)时,是否使用异步线程执行实际内存释放
lazyfree-lazy-server-del yes
# 当执行 FLUSHDB 或 FLUSHALL 命令清空数据库时,是否使用异步线程执行实际内存释放
lazyfree-lazy-flush yes
# 当用户通过 DEL 命令主动删除键时,是否使用异步线程执行实际内存释放
lazyfree-lazy-user-del yes

7. 总结

本文对 BigKey 的定义做了诠释,介绍了 BigKey 的危害,提到了 BigKey 的产生原因,主要讲解了如何发现和删除 BigKey,除此之外,还介绍了可以通过配置文件让 Redis 在删除数据时使用非阻塞的方式。

http://www.dtcms.com/a/286324.html

相关文章:

  • Radix-4 Booth乘法器计算步骤
  • 【AI论文】CLiFT:面向计算高效与自适应神经渲染的压缩光场标记
  • vue2 面试题及详细答案150道(41 - 60)
  • Node.js链接MySql
  • Vue常见指令
  • Java大厂面试实录:从Spring Boot到AI微服务架构的深度解析
  • 深度学习零基础入门(3)-图像与神经网络
  • UE5 一些关于过场动画sequencer,轨道track的一些Python操作
  • 力扣347:前K个高频元素
  • 科技照亮童心|激光院与跳伞塔社区开展公益活动
  • Day24| 93.复原IP地址、78.子集、90.子集II
  • NIO简单介绍和运用
  • MySQL计数函数count原理分析
  • 深入理解Linux文件I/O:系统调用与标志位应用
  • 区块链加密技术全景解析
  • 高效VLP蛋白表达|病毒样颗粒生产|疫苗研发平台
  • 【无标题】标准模型粒子行为与11维拓扑量子色动力学模型严格对应的全面论述
  • 文献分享0719
  • MyBatis:配置文件完成增删改查_添加
  • 智慧后厨检测算法构建智能厨房防护网
  • 零基础入门:用按键精灵实现视频自动操作(附完整脚本)
  • C语言:数组
  • MySQL的关键日志
  • 洛谷 P1395 会议
  • Logback 配置的利器:深入理解<property>与<variable>
  • 教育行业网络升级最佳实践:SD-WAN、传统方案与混合方案对比分析
  • Android sdk 升级 34到35
  • SpringBoot中解决SpringApplication入口和其他Bean不在同属目录下的问题。
  • 暑期自学嵌入式——Day05补充(C语言阶段)
  • STM32+w5500+TcpClient学习笔记