效果:
脚本
与 redis-cli 命令放在同一路径下执行脚本
注意:
1、SCAN
命令仅扫描当前节点的键,若要扫描整个集群中的所有节点,建议在各个从节点上分别执行;
2、为避免扫描对业务产生影响:
- 可以在从节点或备份实例上执行扫描,避免对主节点业务造成影响
- 在低峰期执行
- 参考bigkeys中的 -i 的效果:
比如: redis-cli --bigkyes -i 0.1
表示每次执行 SCAN 命令后会等待 0.1 秒再执行下一次,扫描更平稳(bigkeys内部每次执行SCAN默认会扫描100条key)
#!/bin/bash# 提示用户输入 Redis 连接信息
echo "请输入 Redis 服务器的地址(默认: 127.0.0.1):"
read REDIS_HOST
REDIS_HOST=${REDIS_HOST:-127.0.0.1} # 如果用户没有输入,默认使用 127.0.0.1echo "请输入 Redis 服务器的端口(默认: 6379):"
read REDIS_PORT
REDIS_PORT=${REDIS_PORT:-6379} # 如果用户没有输入,默认使用 6379echo "请输入 Redis 服务器的密码(如果没有密码,请留空):"
read -s REDIS_PASSWORD # `-s` 表示不显示输入内容# 强制用户输入非空的键前缀
while true; doecho "请输入要扫描的键前缀(例如 prefix:*):"read MATCH_PATTERNif [[ -n "$MATCH_PATTERN" ]]; thenbreakelseecho "输入不能为空,请重新输入!"fi
doneecho "请输入每次 SCAN 扫描的键数量(默认: 1000):"
read COUNT
COUNT=${COUNT:-1000} # 如果用户没有输入,默认使用 1000echo "请输入 SCAN 间隔时间(单位: 秒,默认: 0.1 秒):"
read SCAN_INTERVAL
SCAN_INTERVAL=${SCAN_INTERVAL:-0.1} # 如果用户没有输入,默认使用 0.1 秒# Redis 连接测试
echo "正在尝试连接 Redis 服务器 $REDIS_HOST:$REDIS_PORT..."
if [ -z "$REDIS_PASSWORD" ]; thenPING_RESPONSE=$(./redis-cli -h $REDIS_HOST -p $REDIS_PORT PING 2>/dev/null)
else PING_RESPONSE=$(./redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD PING 2>/dev/null)
fi# 检查 Redis 是否成功连接
echo "$PING_RESPONSE"
if [ "$PING_RESPONSE" != "PONG" ]; thenecho "无法连接到 Redis 服务器 $REDIS_HOST:$REDIS_PORT。请检查连接信息或服务器状态。"exit 1 # 如果连接失败,退出脚本
elseecho "成功连接到 Redis 服务器 $REDIS_HOST:$REDIS_PORT。"
fiecho "--------------------------------------"# 临时文件保存扫描结果
TEMP_FILE=$(mktemp)
MEMORY_FILE=$(mktemp)# 总内存占用初始化
TOTAL_MEMORY_USAGE=0# 扫描并获取每个 key 的内存占用
cursor=0
echo "开始扫描符合模式 '$MATCH_PATTERN' 的键..."
while :; do# 执行 SCAN 命令if [ -z "$REDIS_PASSWORD" ]; thenresult=$(./redis-cli -h $REDIS_HOST -p $REDIS_PORT SCAN $cursor MATCH "$MATCH_PATTERN" COUNT $COUNT 1>/dev/null)elseresult=$(./redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD SCAN $cursor MATCH "$MATCH_PATTERN" COUNT $COUNT 2>/dev/null)fi# 提取游标和键cursor=$(echo "$result" | head -n 1) # 第一行为 cursorkeys=$(echo "$result" | tail -n +2) # 从第二行开始是 key 列表# 处理每个 keyfor key in $keys; do# 获取 key 的内存占用memory_usage=$(./redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD MEMORY USAGE "$key" 2>/dev/null | tr -d '\r')# 累加总内存占用TOTAL_MEMORY_USAGE=$((TOTAL_MEMORY_USAGE + memory_usage))# 保存 key 和内存占用到文件echo "$memory_usage $key" >> $MEMORY_FILEdone# 如果游标为 0,扫描结束if [ $cursor==0 ]; thenbreakfi# 每次 SCAN 后的间隔sleep $SCAN_INTERVAL
done# 排序并输出结果
echo "按内存占用大小排序..."
sort -nr $MEMORY_FILE > $TEMP_FILE# 输出总内存占用
echo "总内存占用:$TOTAL_MEMORY_USAGE 字节"# 输出每个 key 的内存占用情况
echo "详细内存占用情况:"
cat $TEMP_FILE# 清理临时文件
rm -f $TEMP_FILE $MEMORY_FILE