本文目录导读:

是的,脚本可以自动清理Redis中的大Key,但需要谨慎操作,因为不当的清理可能导致长时间阻塞、数据丢失或集群不稳定。
以下是几种常用的脚本方案及关键注意事项:
核心思路:分批删除
直接使用 DEL 删除一个大Key(如一个包含百万元素的List/Set/Hash)会阻塞Redis主线程,导致服务中断,脚本的核心是分批、延迟、扫描删除。
常用脚本方案
针对不同类型的大Key,使用对应的游标式命令
#!/bin/bash
# 示例:自动扫描并删除超过 10KB 的 key(针对 Hash/List/Set/ZSet/SortedSet)
REDIS_CLI="redis-cli -h 127.0.0.1 -p 6379 -a yourpassword --no-auth-warning"
THRESHOLD_BYTES=10240 # 10KB
# 使用 SCAN 命令渐进式遍历所有 key
cursor=0
while true; do
result=$(redis-cli --no-auth-warning -a yourpassword SCAN $cursor COUNT 100)
cursor=$(echo "$result" | head -1)
keys=$(echo "$result" | tail -n +2)
for key in $keys; do
# 检查内存大小 (DEBUG OBJECT 会返回 serializedlength)
size=$(redis-cli --no-auth-warning -a yourpassword DEBUG OBJECT "$key" 2>/dev/null | grep -oP 'serializedlength:\K[0-9]+')
if [ "$size" -ge "$THRESHOLD_BYTES" ]; then
type=$(redis-cli --no-auth-warning -a yourpassword TYPE "$key")
echo "Found Large Key: $key (Type: $type, Size: ${size}bytes)"
# 根据不同结构分批删除
case "$type" in
string)
# String 可以直删 (但建议确认业务)
redis-cli --no-auth-warning -a yourpassword DEL "$key"
;;
list)
# 每次 LTRIM 1000 个元素
while true; do
result=$(redis-cli --no-auth-warning -a yourpassword LTRIM "$key" 1000 -1)
# 如果剩余长度 <= 1000,直接 DEL
len=$(redis-cli --no-auth-warning -a yourpassword LLEN "$key")
if [ "$len" -le 1000 ]; then
redis-cli --no-auth-warning -a yourpassword DEL "$key"
break
fi
sleep 0.1 # 延迟,避免阻塞
done
;;
set)
# 每次 SPOP 1000
while true; do
size=$(redis-cli --no-auth-warning -a yourpassword SCARD "$key")
if [ "$size" -eq 0 ]; then break; fi
redis-cli --no-auth-warning -a yourpassword SPOP "$key" 1000 > /dev/null 2>&1
sleep 0.1
done
;;
hash)
# 每次 HDEL 1000 字段
while true; do
fields=$(redis-cli --no-auth-warning -a yourpassword HKEYS "$key" | head -1000)
if [ -z "$fields" ]; then break; fi
redis-cli --no-auth-warning -a yourpassword HDEL "$key" $fields
sleep 0.1
done
;;
zset)
# 每次 ZREMRANGEBYRANK 0 999 (删除前1000个)
while true; do
count=$(redis-cli --no-auth-warning -a yourpassword ZCARD "$key")
if [ "$count" -eq 0 ]; then break; fi
redis-cli --no-auth-warning -a yourpassword ZREMRANGEBYRANK "$key" 0 999
sleep 0.1
done
;;
esac
fi
done
if [ "$cursor" -eq 0 ]; then
break
fi
done
使用 Python 脚本(更可控、更适合复杂逻辑)
import redis
import time
r = redis.Redis(host='127.0.0.1', port=6379, password='yourpassword')
THRESHOLD = 10000 # 元素数超过 1 万视为大Key
def delete_large_key(key):
key_type = r.type(key).decode('utf-8')
print(f"Deleting large key: {key}, type: {key_type}")
if key_type == 'string':
# String 特殊处理:确认是否可删除
r.delete(key)
elif key_type == 'list':
while r.llen(key) > 1000:
# 保留最后 1000 个,前面的全部清除
r.ltrim(key, 0, -1001)
time.sleep(0.1)
r.delete(key)
elif key_type == 'set':
while r.scard(key) > 0:
# 每次 1000 个
members = r.spop(key, 1000)
if not members:
break
time.sleep(0.1)
elif key_type == 'hash':
while True:
fields = list(r.hkeys(key)[:1000])
if not fields:
break
r.hdel(key, *fields)
time.sleep(0.1)
r.delete(key) # 清理空Key
elif key_type == 'zset':
while r.zcard(key) > 0:
# 每次删除排序最小的 1000 个
r.zremrangebyrank(key, 0, 999)
time.sleep(0.1)
# 扫描所有 key
cursor = 0
while True:
cursor, keys = r.scan(cursor=cursor, count=100)
for key in keys:
# 检查元素数量或内存大小
key_type = r.type(key).decode('utf-8')
if key_type in ('list', 'set', 'hash', 'zset'):
size = eval(f'r.{key_type.lower() if key_type != "zset" else "zcard"}(key)')
if size > THRESHOLD:
delete_large_key(key)
elif key_type == 'string':
# 通过 STRLEN 或 DEBUG OBJECT 检查大小
if r.strlen(key) > 10240: # 大于10KB
delete_large_key(key)
if cursor == 0:
break
注意事项(非常重要)
- 绝对避免在高峰期直删大Key:即使使用分批方法,如果主库写入压力大,仍可能造成延迟抖动,建议在低峰期执行。
SCAN命令弱一致性:它不保证完整遍历所有Key,但对于清理大Key,通常可接受。- 对String类型特殊处理:String没有分批删除接口,如果要删一个非常大的String(如几MB),直接
DEL会阻塞,这种情况下,可以考虑:- 使用
UNLINK命令(Redis 4.0+):异步删除,不阻塞,这是最安全的方式。 - 先
GET设空再删(不推荐,只能减少数据拷贝)。
- 使用
- 集群环境:如果使用Redis Cluster,脚本需要处理节点槽位,可以使用
redis-cli --cluster模式或自行遍历每个节点。 - 权限控制:生产环境建议使用只读账号扫描,以避免误删。
- 监控与回滚:执行前记录Key列表,删除后观察主从延迟和内存释放情况。
推荐的专业工具
如果不想自己写脚本,可以使用以下成熟工具:
- Redis Labs 的
redis-rdb-tools:分析RDB文件找到大Key,再针对性删除。 redis-cli --bigkeys:扫描并报告大Key(只读,不删除)。- 阿里巴巴开源的
redis-shake:支持过滤和迁移,可配置删除大Key规则。
脚本可以自动清理,但强烈建议:
- 优先使用
UNLINK异步删除(如果版本 ≥ 4.0)。 - 对于复杂数据类型,使用游标或截断命令分批删除。
- 加上睡眠延迟(0.1~0.5s) 和并发限制,防止阻塞。
- 先在测试环境验证,生产环境慎重执行。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播