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

Redis如何解决大Key问题

目录

    • **如何解决 Redis 大 Key(Big Key)问题?**
      • **1. 什么是大 Key?**
      • **2. 如何发现大 Key?**
        • **(1)使用 `SCAN` 命令遍历所有 Key**
        • **(2)统计 Key 的类型和大小**
      • **3. 如何解决大 Key 问题?**
    • **方案 1:大 Key 拆分(Sharding)**
      • **(1)String 过大:分片存储**
      • **(2)List/Set/Hash 过大:拆分 Key**
    • **方案 2:分页存储**
      • **示例**
    • **方案 3:Lazy Deletion(懒删除)**
      • **方案**
      • **示例**
    • **方案 4:使用 HyperLogLog 代替 Set**
      • **示例**
    • **方案 5:使用 Redis Stream 替代大 List**
      • **示例**
    • **方案 6:Redis 结合 MySQL 分层存储**
      • **示例**
    • **总结**
      • **面试标准回答**

如何解决 Redis 大 Key(Big Key)问题?

1. 什么是大 Key?

大 Key(Big Key) 指的是 单个 Key 的数据量特别大,通常体现在:

  • 单个 String 类型的 Key 存储了超长的内容(如超大 JSON、Base64 图片)。
  • 单个 List/Set/Zset/Hash 存储大量元素,导致:
    • 查询效率下降(一次查询数据过多)。
    • 删除或过期开销大(删除一个 Key 可能会卡 Redis)。
    • 主从复制或数据持久化时阻塞 Redis(大 Key 影响 RDB、AOF 复制)。

2. 如何发现大 Key?

(1)使用 SCAN 命令遍历所有 Key
redis-cli --bigkeys

示例:

# 扫描 Redis 找出最大的 Key
redis-cli --bigkeys

# 结果示例:
# Largest string found 'user_session' with 10MB
# Largest list found 'comments_list' with 1M elements

分析

  • user_session超大字符串(10MB)。
  • comments_list超长列表(100W 条)。

(2)统计 Key 的类型和大小
# 查看 Key 的类型
TYPE big_key_name

# 统计 List/Set/Hash/Zset 的元素数量
LLEN big_list_key   # List
SCARD big_set_key   # Set
HLEN big_hash_key   # Hash
ZCARD big_zset_key  # Zset

3. 如何解决大 Key 问题?

针对不同的数据结构,采取不同优化策略:


方案 1:大 Key 拆分(Sharding)

核心思路:将一个大 Key 拆分成多个小 Key,减少 Redis 负担。

(1)String 过大:分片存储

问题:单个 String 存储了超大 JSON 或图片,导致 GET 操作慢。
解决方案

  • 拆分成多个小 Key(如 big_key:0, big_key:1)。
  • 读取时分批合并

示例

// 存储时拆分
redis.set("big_key:0", sub_string_0);
redis.set("big_key:1", sub_string_1);
redis.set("big_key:2", sub_string_2);

// 读取时合并
string value = redis.get("big_key:0") + redis.get("big_key:1") + redis.get("big_key:2");

适用场景

  • 大 JSON 拆分(适用于超大用户配置)。
  • Base64 图片分片存储

(2)List/Set/Hash 过大:拆分 Key

问题:List/Set/Zset 里的元素过多,导致 LRANGESMEMBERS 查询慢。
解决方案

  • 按照 ID 取模拆分多个 Key,如 big_list:0, big_list:1
  • 查询时 Hash 计算 Key

示例

// 按 userId 取模
int index = userId % 5;
redis.lpush("big_list:" + index, data);

// 查询时按 hash 取 Key
redis.lrange("big_list:" + (userId % 5), 0, 10);

适用场景

  • 评论列表(List)
  • 大集合(Set/Hash)

方案 2:分页存储

核心思路:使用 分页查询,避免一次性读取过多数据。

示例

int page = 0;
int pageSize = 50;
redis.lrange("big_list", page * pageSize, (page + 1) * pageSize - 1);

适用场景

  • 排行榜(Zset)
  • 消息列表(List)

方案 3:Lazy Deletion(懒删除)

核心思路防止一次性删除大 Key 影响 Redis 性能,采用分批删除

方案

  1. 异步删除(Redis 4.0+ 提供 UNLINK 命令)
  2. 分批删除(Lua 脚本)

示例

# 使用 UNLINK 异步删除
UNLINK big_key
-- Lua 脚本:分批删除
local key = KEYS[1]
local count = ARGV[1]
for i = 1, count do
    redis.call("LPOP", key) -- 每次删除部分元素
end

适用场景

  • 避免 DEL 造成阻塞

方案 4:使用 HyperLogLog 代替 Set

核心思路:如果不需要存储所有数据,只需要计数,使用 HyperLogLog

示例

# 统计 UV(去重访问量)
PFADD unique_users user_1
PFADD unique_users user_2
PFCOUNT unique_users

适用场景

  • UV 统计(网站访问量)
  • 去重计数

方案 5:使用 Redis Stream 替代大 List

核心思路Redis Stream 支持自动删除老数据,适合高并发大数据流场景。

示例

# 添加消息
XADD messages * user "Tom" text "Hello"

# 只保留最近 10W 条消息
XTRIM messages MAXLEN 100000

适用场景

  • 日志流、消息队列

方案 6:Redis 结合 MySQL 分层存储

核心思路冷数据移到 MySQL,Redis 只存热点数据

示例

if (redis.exists(key)) {
    return redis.get(key);  // 先查 Redis
} else {
    std::string value = queryDatabase(key); // 查 MySQL
    redis.setex(key, 3600, value); // 重新写入 Redis
    return value;
}

适用场景

  • 超大用户数据、订单记录

总结

问题解决方案适用场景
String 过大分片存储JSON 配置、Base64 图片
List/Set 过大分页存储 + Key 拆分评论列表、好友列表
删除大 Key 慢UNLINK + 分批删除热点数据过期
Set 计数过大用 HyperLogLog 代替UV 统计、去重计数
高并发大数据流Redis Stream 代替 List消息流、日志
数据分层Redis + MySQL 冷热数据存储超大用户数据

面试标准回答

解决 Redis 大 Key 需要 5 大方案

  1. 拆分 Key(Sharding) → 把大 Key 拆成多个 Key,分摊压力。
  2. 分页存储 → 使用 LRANGE 分页查询,避免一次性返回过多数据。
  3. Lazy Deletion(懒删除) → 用 UNLINK 或分批删除,避免 Redis 卡顿。
  4. HyperLogLog/Stream 替代 → 用 HyperLogLog 代替 Set 计数,用 Stream 代替 List。
  5. 冷数据存 MySQL,Redis 只存热点数据 → Redis + MySQL 分层存储,减少大 Key 占用。

推荐最佳方案Key 拆分 + 分批删除 + 分层存储,结合业务需求优化。🚀

相关文章:

  • SpringCloud面试题----什么是Feign?是如何实现负载均衡的
  • VGGNet 图像分类实现
  • 8.PG实例层连接访问管理(pg系列课程) 第2遍
  • 【Spring+MyBatis】_图书管理系统(下篇)
  • 升级 SpringBoot3 全项目讲解 — Spring Boot 3 中如何发Http请求?
  • 检测网络安全漏洞 工具
  • 【R语言】非参数检验
  • 技术总结 | MySQL面试知识点
  • Mysql基础语句
  • AIGC:开启内容创作新纪元,我们如何看待它的影响与前景?
  • ApplicationContextInitializer钩子函数学习
  • Linux环境开发工具
  • Three.js 快速入门教程【二】透视投影相机
  • 【个人总结】7. Linux 工作三年的嵌入式常见知识点梳理及开发技术要点(欢迎指正、补充)
  • 在IDEA的Maven中(同步所有Maven项目)和(重新加载所有Maven项目)的区别
  • 《95015网络安全应急响应分析报告(2024)》
  • 激光雷达YDLIDAR X2 SDK安装
  • RESTful 的特点与普通 Web API 的区别
  • 【GPT】从GPT1到GPT3
  • 某大型业务系统技术栈介绍【应对面试】
  • 胖东来发布和田玉、翡翠退货说明:不扣手续费等任何费用
  • 上海优化营商环境十大攻坚突破任务中,为何第一项是实施世行对标改革?
  • 加力、攻坚、借力、问效,上海为优化营商环境推出增量举措
  • 五一期间7名游客接连被困青海荒漠,警方提醒严禁非法穿越
  • 印巴冲突升级,巴防长称已击落5架印度战机
  • 潘功胜:将创设科技创新债券风险分担工具