Redis 中的 Big Key(大 Key)问题 通常是指某个键(Key)对应的 Value 体积过大,这个“大”不是指键名长度,通常在String、list、hash、set、zset等类型中出现的问题比较多。其中String类型就是字符串的值比较大,而其他几个类型就是其中元素过多的情况。即:
大 Key 不只是 value 大,也包括 集合型类型中元素数量极多;
Redis 是单线程模型,大 Key 会拖慢整个实例的响应;
建议使用大 Key 分片拆分、预警监控、限流处理等手段规避风险。
Redis的Big Key可能存在以下几个危害:
1、影响性能:由于big key的values占用的内存会很大,所以读取它们的速度会很慢,会影响系统的性能。
2、占用内存: 大量的big key也会占满Redis的内存,让Redis无法继续存储新的数据,而且也会导致Redis卡住
3、内存空间不均匀:比如在 Redis 集群中,可能会因为某个节点上存储了Big Key,导致多个节点之间内存使用不均匀。
4、影响Redis备份和恢复:如果从RDB文件中恢复全量数据时,可能需要大量的时间,甚至无法正常恢复。
5、搜索困难:由于大key可能非常大,因此搜索key内容时非常困难,并且可能需要花费较长的时间完成搜索任务。
6、迁移困难:大对象的迁移和复制压力较大,极易破坏缓存的一致性
7、过期执行耗时:如果 Bigkey 设置了过期时间,当过期后,这个 key 会被删除,而大key的删除过程也比较耗时
对于Big Key问题的处理,重点要在识别和解决 value 内容过大的问题上。
✅ 一、大 Key 的两种情况:
✅ 二、为什么 Big Key 是问题?
阻塞线程
Redis 是单线程模型。
操作大 Key(如 DEL、LRANGE、HGETALL)会 阻塞整个 Redis 实例,影响其他请求的响应。
网络压力
获取一个大 Key 会导致网络 IO 激增,容易打满带宽,增加延迟。
慢日志 & 延迟监控报警
操作大 Key 往往触发 Redis 慢日志(slowlog)、延迟监控报警。
集群迁移困难
Redis Cluster 中的某个 Big Key 迁移非常慢,严重时会阻塞槽迁移。
✅ 三、如何发现大 Key?
命令查看(影响性能)
DEBUG OBJECT <key> # 查看键的大小信息
MEMORY USAGE <key> # Redis >= 4.0 推荐使用,单位字节
使用 scan 工具配合统计
scan 0 COUNT 10000 # 批量遍历键集合,结合 memory usage 估算
使用专业工具
redis-rdb-tools:解析 RDB 文件查看 key 体积。
redis-key-check:扫描分析大 key。
✅ 四、如何避免和优化 Big Key?
✅ 五、多大算大?哪些是大 Key 呢?
Redis中多大的key算作大key并没有一个固定的标准,因为这主要取决于具体的场景和应用需求。一般来说,如果一个key的value比较大,占用的内存比较多,或者某个key包含的元素数量比较多,这些都可以被认为是大key。
通常情况下,建议不要超过以下设定,超过这些数量就可能会影响Redis的性能。
对于 String 类型的 Value 值,值超过 5MB(腾讯云定义是10M,阿里云定义是5M,我认为5M合适一点)。
对于 Set 类型的 Value 值,含有的成员数量为 10000 个(成员数量多)。
对于 List 类型的 Value 值,含有的成员数量为 10000 个(成员数量多)。
对于 Hash 格式的 Value 值,含有的成员数量 1000 个,但所有成员变量的总 Value 值大小为 100MB(成员总的体积过大)。
但是,这些并不是绝对的限制,而是一个经验值,具体的情况还需要根据应用场景和实际情况进行调整。
✅ 六、识别big key
在识别方面,Redis中的big key可以识别的程序是“redis-cli”,用户可以通过在终端中输入“redis-cli –bigkeys” 来获取Redis中的big key。当redis-cli被调用时,它将搜索所有Redis数据库中包含大量内存数据的key,并且会将其保存在本地标准输出文件中:
[root@redis-cluster-01 ~]# redis-cli -h 127.0.0.1 -a 123456 -p 6379 --bigkeys
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
# Scanning the entire keyspace to find biggest keys as well as
# average sizes per key type. You can use -i 0.1 to sleep 0.1 sec
# per 100 SCAN commands (not usually needed).
-------- summary -------
Sampled 0 keys in the keyspace!
Total key length in bytes is 0 (avg len 0.00)
0 hashs with 0 fields (00.00% of keys, avg size 0.00)
0 lists with 0 items (00.00% of keys, avg size 0.00)
0 strings with 0 bytes (00.00% of keys, avg size 0.00)
0 streams with 0 entries (00.00% of keys, avg size 0.00)
0 sets with 0 members (00.00% of keys, avg size 0.00)
0 zsets with 0 members (00.00% of keys, avg size 0.00)
[root@redis-cluster-01 ~]#
# Scanning the entire keyspace to find biggest keys as well as
# average sizes per key type. You can use -i 0.1 to sleep 0.1 sec
# per 100 SCAN commands (not usually needed).
Biggest string found so far 'mykey' with 160012 bytes
Biggest list found so far 'mylist' with 2304 items
Biggest set found so far 'myset' with 1230 members
Biggest zset found so far 'myzset' with 3220 members
Biggest hash found so far 'myhash' with 412 fields
✅ 七、处理Big Key
想要解决Big Key的问题,根据具体的业务情况有很多不同的方案,下面简单列几个:
1、有选择地删除Big Key:针对Big Key,我们可以针对一些访问频率低的进行有选择性的删除,删除Big Key来优化内存占用。
2、除了手动删除以外,还可以通过合理的设置缓存TTL,避免过期缓存不及时删除而增大key大小。
3、Big Key的主要问题就是Big,所以我们可以想办法解决big的问题,那就是拆分呗,把big的key拆分开:
在业务代码中,将一个big key有意的进行拆分,比如根据日期或者用户尾号之类的进行拆分。使用小键替代大键可以有效减小存储空间,从而避免影响系统性能
使用Cluster集群模式,以将大 key 分散到不同服务器上,以加快响应速度。
4、部分迁移:将大键存放在单独的数据库中,从而实现对大键的部分迁移
✅ 八、脚本自动检测 Redis 实例中的大 Key
Redis 大 Key 自动检测脚本(支持内存大小和元素数量双重判断)
📌 特点:
支持检测所有类型:String、Hash、List、Set、ZSet、Bitmap 等;
过滤占用内存大(如 > 512KB)或元素数多(如 > 1w)的 Key;
输出格式清晰:Key 名、类型、内存占用、元素数量。
🧰 支持特性
支持批量 scan,避免阻塞
支持配置 redis 地址、密码、db 等
支持设置各类型大 Key 判断阈值(如字符串长度 > 100KB,集合元素数 > 10000 等)
支持输出到日志
脚本有点问题,待我调试以后再更新~~~
#!/bin/bash
# --------------- 配置项 -----------------
REDIS_CLI="/usr/bin/redis-cli"
HOST="127.0.0.1"
PORT="6379"
AUTH=""
DB="0"
# 大Key阈值设置
MAX_STRING_SIZE=102400 # 100KB
MAX_LIST_LENGTH=10000
MAX_SET_CARD=10000
MAX_ZSET_CARD=10000
MAX_HASH_CARD=10000
# ----------------------------------------
echo "[INFO] Redis 大 Key 扫描启动..."
cursor=0
while :
do
# 获取 scan 结果:key 列表和下一次的 cursor
result=$($REDIS_CLI -h "$HOST" -p "$PORT" -n "$DB" --raw $AUTH SCAN $cursor COUNT 100)
cursor=$(echo "$result" | head -n1)
keys=$(echo "$result" | tail -n +2)
for key in $keys; do
type=$($REDIS_CLI -h "$HOST" -p "$PORT" -n "$DB" --raw $AUTH TYPE "$key")
case "$type" in
string)
size=$($REDIS_CLI -h "$HOST" -p "$PORT" -n "$DB" --raw $AUTH STRLEN "$key")
if [ "$size" -ge "$MAX_STRING_SIZE" ]; then
echo "[BigKey-STRING] key=$key size=${size}B"
fi
;;
list)
length=$($REDIS_CLI -h "$HOST" -p "$PORT" -n "$DB" --raw $AUTH LLEN "$key")
if [ "$length" -ge "$MAX_LIST_LENGTH" ]; then
echo "[BigKey-LIST] key=$key length=$length"
fi
;;
set)
card=$($REDIS_CLI -h "$HOST" -p "$PORT" -n "$DB" --raw $AUTH SCARD "$key")
if [ "$card" -ge "$MAX_SET_CARD" ]; then
echo "[BigKey-SET] key=$key cardinality=$card"
fi
;;
zset)
zcard=$($REDIS_CLI -h "$HOST" -p "$PORT" -n "$DB" --raw $AUTH ZCARD "$key")
if [ "$zcard" -ge "$MAX_ZSET_CARD" ]; then
echo "[BigKey-ZSET] key=$key zcard=$zcard"
fi
;;
hash)
hlen=$($REDIS_CLI -h "$HOST" -p "$PORT" -n "$DB" --raw $AUTH HLEN "$key")
if [ "$hlen" -ge "$MAX_HASH_CARD" ]; then
echo "[BigKey-HASH] key=$key field_count=$hlen"
fi
;;
esac
done
if [ "$cursor" == "0" ]; then
break
fi
done
echo "[INFO] Redis 大 Key 扫描完成。"
#!/bin/bash
# 自动探测 redis-cli 路径
REDIS_CLI=$(command -v redis-cli)
if [ -z "$REDIS_CLI" ]; then
echo "❌ 未找到 redis-cli,请确保它已安装并加入 PATH"
exit 1
fi
# Redis 配置(可通过参数传入)
REDIS_HOST=${1:-127.0.0.1}
REDIS_PORT=${2:-6379}
REDIS_DB=${3:-0}
# 大 Key 判断阈值(可按需调整)
BIG_STRING_SIZE=1024 # 1KB
BIG_LIST_LENGTH=1000
BIG_HASH_FIELDS=500
BIG_SET_MEMBERS=1000
BIG_ZSET_MEMBERS=1000
echo "🔍 开始检测 Redis(${REDIS_HOST}:${REDIS_PORT}, DB: $REDIS_DB) 中的大 Key ..."
echo "============================================================="
# 获取所有 keys(仅用于测试或小数据量环境,生产建议使用 scan)
KEYS=$($REDIS_CLI -h "$REDIS_HOST" -p "$REDIS_PORT" -n "$REDIS_DB" --raw keys '*')
for KEY in $KEYS; do
TYPE=$($REDIS_CLI -h "$REDIS_HOST" -p "$REDIS_PORT" -n "$REDIS_DB" type "$KEY")
case $TYPE in
string)
SIZE=$($REDIS_CLI -h "$REDIS_HOST" -p "$REDIS_PORT" -n "$REDIS_DB" strlen "$KEY")
if [ "$SIZE" -ge "$BIG_STRING_SIZE" ]; then
echo "📦 BIG STRING → key=$KEY, size=${SIZE} bytes"
fi
;;
list)
LEN=$($REDIS_CLI -h "$REDIS_HOST" -p "$REDIS_PORT" -n "$REDIS_DB" llen "$KEY")
if [ "$LEN" -ge "$BIG_LIST_LENGTH" ]; then
echo "📋 BIG LIST → key=$KEY, length=$LEN"
fi
;;
hash)
FIELDS=$($REDIS_CLI -h "$REDIS_HOST" -p "$REDIS_PORT" -n "$REDIS_DB" hlen "$KEY")
if [ "$FIELDS" -ge "$BIG_HASH_FIELDS" ]; then
echo "🗂️ BIG HASH → key=$KEY, fields=$FIELDS"
fi
;;
set)
MEMBERS=$($REDIS_CLI -h "$REDIS_HOST" -p "$REDIS_PORT" -n "$REDIS_DB" scard "$KEY")
if [ "$MEMBERS" -ge "$BIG_SET_MEMBERS" ]; then
echo "📚 BIG SET → key=$KEY, members=$MEMBERS"
fi
;;
zset)
ZMEMBERS=$($REDIS_CLI -h "$REDIS_HOST" -p "$REDIS_PORT" -n "$REDIS_DB" zcard "$KEY")
if [ "$ZMEMBERS" -ge "$BIG_ZSET_MEMBERS" ]; then
echo "🎯 BIG ZSET → key=$KEY, members=$ZMEMBERS"
fi
;;
*)
echo "⚠️ 未识别类型 key=$KEY, type=$TYPE"
;;
esac
done
echo "✅ 检测完毕"
✅ 使用说明:
chmod +x redis_bigkey_checker.sh
./redis_bigkey_checker.sh
评论区