当前位置: 首页 > 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.lryc.cn/news/592142.html

相关文章:

  • web开发基础(CSS)
  • 【甲烷数据集】Sentinel-5P 卫星获取的全球甲烷数据集-TROPOMI L2 CH₄
  • 设计循环队列oj题(力口622)
  • 四足机器人远程视频与互动控制的全链路方案
  • 声画同步!5 个音视频素材适配的网站,创作更和谐
  • 如何使用 Jackson 处理 YAML
  • Linux 环境下 NNG 通讯库:在嵌入式设备上应用
  • iOS WebView 调试实战 全流程排查接口异常 请求丢失与跨域问题
  • 疯狂星期四文案网第11天运营日报
  • 1 初识C++
  • iOS加固工具有哪些?项目场景下的组合策略与实战指南
  • 第一篇htmlcss详细讲解
  • 某邮生活旋转验证码识别
  • Win11安装Docker,并使用Docker安装RabbitMQ
  • 零基础入门:用按键精灵实现视频自动操作(附完整脚本)
  • Docker搭建Elasticsearch和Kibana
  • Python编程进阶知识之第二课学习网络爬虫(selenium)
  • 基于单片机智能充电器系统设计
  • logback日志控制服务器日志输出
  • 【论文精读】基于共识的分布式量子分解算法用于考虑最优传输线切换的安全约束机组组合
  • CursorIP被Ban,设置HttpProxy(亲测可用!!!)
  • 差分隐私机器学习:通过添加噪声让模型更安全,也更智能
  • 【Python】DRF核心组件详解:Mixin与Generic视图
  • Django 实战:I18N 国际化与本地化配置、翻译与切换一步到位
  • Mysql数据库——增删改查CRUD
  • Jfinal+SQLite解决MYSQL迁移表未复制索引问题,完善迁移工具
  • 算法学习笔记:29.拓扑排序——从原理到实战,涵盖 LeetCode 与考研 408 例题
  • hadoop(服务器伪分布式搭建)
  • 瀚高数据库开启Oracle兼容模块
  • Oracle 11g RAC 高可用集群部署最佳实践