2026/4/18 10:47:44
网站建设
项目流程
做类似美团的网站吗,做设备出口网站,河南智能网站建设平台,php注册网站源码带数据库一.基于shell脚本进行删除针对 Redis 三主三从集群#xff0c;要实现定时清理过期 Key 超过 10M 的超大 Key#xff0c;核心思路是#xff1a;自动识别集群所有主节点#xff08;从节点无需清理#xff0c;数据同步主节点#xff09;#xff1b;基于 SCAN 非阻塞遍历主…一.基于shell脚本进行删除针对 Redis 三主三从集群要实现定时清理过期 Key 超过 10M 的超大 Key核心思路是自动识别集群所有主节点从节点无需清理数据同步主节点基于SCAN非阻塞遍历主节点 Key筛选目标后删除通过 Linuxcrontab配置定时任务低峰期自动执行。以下是基于shell脚本实现#!/bin/bash # Redis 集群清理脚本删除过期 Key 超过10M的Key # 适配三主三从集群仅清理主节点 ########################## 配置区根据实际修改 ########################## # Redis 集群任意节点地址用于获取主节点列表 CLUSTER_ANY_NODE10.10.19.11:6379 # Redis 密码无密码则注释此行后续删除 -a $REDIS_PASSWORD REDIS_PASSWORDyour_redis_password # 超大 Key 阈值10M字节 MAX_KEY_SIZE$((10 * 1024 * 1024)) # SCAN 每次遍历 Key 数量建议 100-500越小越不阻塞 SCAN_COUNT500 # 日志文件路径 LOG_FILE/var/log/redis_cluster_clean.log ########################################################################### # 日志函数带时间戳 log() { echo [$(date %Y-%m-%d %H:%M:%S)] $1 $LOG_FILE } # 检查 redis-cli 是否存在 if ! command -v redis-cli /dev/null; then log 错误未找到 redis-cli请确保 Redis 客户端已安装 exit 1 fi # 步骤1获取集群所有主节点过滤从节点、空行 log 开始获取集群主节点列表... MASTER_NODES$(redis-cli -h $(echo $CLUSTER_ANY_NODE | cut -d: -f1) \ -p $(echo $CLUSTER_ANY_NODE | cut -d: -f2) \ -a $REDIS_PASSWORD --raw CLUSTER NODES 2 $LOG_FILE \ | grep -E master|myself,master \ | awk {print $2} \ | cut -d -f1 \ | sort -u) if [ -z $MASTER_NODES ]; then log 错误未获取到集群主节点请检查集群连接或密码 exit 1 fi log 获取到主节点列表$MASTER_NODES # 步骤2遍历每个主节点清理目标 Key TOTAL_DELETED_EXPIRED0 # 累计删除过期 Key 数 TOTAL_DELETED_LARGE0 # 累计删除超大 Key 数 for NODE in $MASTER_NODES; do NODE_HOST$(echo $NODE | cut -d: -f1) NODE_PORT$(echo $NODE | cut -d: -f2) log 开始清理主节点$NODE_HOST:$NODE_PORT # 初始化 SCAN 游标 CURSOR0 # 节点内删除计数 NODE_EXPIRED0 NODE_LARGE0 # 循环 SCAN 遍历当前节点所有 Key while :; do # 执行 SCAN 命令--raw 避免中文/特殊字符乱码 SCAN_RESULT$(redis-cli -h $NODE_HOST -p $NODE_PORT -a $REDIS_PASSWORD \ --raw SCAN $CURSOR COUNT $SCAN_COUNT 2 $LOG_FILE) # 解析游标第一行和 Key 列表剩余行 NEW_CURSOR$(echo $SCAN_RESULT | head -n 1) KEYS$(echo $SCAN_RESULT | tail -n 2) # 遍历当前批次 Key for KEY in $KEYS; do # 跳过空 Key [ -z $KEY ] continue # 条件1删除已过期 KeyTTL ≤ 0-2Key不存在-1永不过期0已过期 TTL$(redis-cli -h $NODE_HOST -p $NODE_PORT -a $REDIS_PASSWORD --raw TTL $KEY 2 $LOG_FILE) if [ $TTL -le 0 ] [ $TTL -ne -1 ]; then # 排除永不过期的 Key redis-cli -h $NODE_HOST -p $NODE_PORT -a $REDIS_PASSWORD DEL $KEY /dev/null 21 NODE_EXPIRED$((NODE_EXPIRED 1)) log [$NODE] 删除过期 Key: $KEY (TTL: $TTL) continue fi # 条件2删除超过10M的 Key KEY_SIZE$(redis-cli -h $NODE_HOST -p $NODE_PORT -a $REDIS_PASSWORD --raw MEMORY USAGE $KEY 2 $LOG_FILE) # 防止 MEMORY USAGE 返回非数字如 Key 被并发删除 if [[ $KEY_SIZE ~ ^[0-9]$ ]] [ $KEY_SIZE -gt $MAX_KEY_SIZE ]; then redis-cli -h $NODE_HOST -p $NODE_PORT -a $REDIS_PASSWORD DEL $KEY /dev/null 21 NODE_LARGE$((NODE_LARGE 1)) log [$NODE] 删除超大 Key: $KEY (大小: $KEY_SIZE 字节阈值: $MAX_KEY_SIZE 字节) fi done # 游标为 0 表示当前节点遍历完成 if [ $NEW_CURSOR 0 ]; then break fi CURSOR$NEW_CURSOR done # 累计节点删除数 TOTAL_DELETED_EXPIRED$((TOTAL_DELETED_EXPIRED NODE_EXPIRED)) TOTAL_DELETED_LARGE$((TOTAL_DELETED_LARGE NODE_LARGE)) log [$NODE] 清理完成过期 Key 删 $NODE_EXPIRED 个超大 Key 删 $NODE_LARGE 个 done # 步骤3输出总清理结果 log 清理汇总 log 集群总清理过期 Key 共 $TOTAL_DELETED_EXPIRED 个超大 Key 共 $TOTAL_DELETED_LARGE 个 log log # 空行分隔日志 exit 0二.基于lua脚本删除在 Redis 三主三从集群中使用 Lua 脚本清理过期 Key和超过 10M 的超大 Key核心优势是Lua 脚本在 Redis 服务端原子执行减少网络往返相比 Shell/Python 遍历更高效结合SCAN非阻塞遍历避免阻塞主线程适配集群特性仅清理主节点从节点同步删除结果。创建redis_clean.lua实现单节点的 Key 筛选与删除可直接在 Redis 节点执行-- Redis 单节点清理脚本删除过期 Key 超过10M的超大 Key -- 参数说明 -- ARGV[1] 超大 Key 阈值字节如 10485760 表示 10M -- ARGV[2] SCAN 每次遍历数量如 200 -- 初始化变量 local max_key_size tonumber(ARGV[1]) local scan_count tonumber(ARGV[2]) local cursor 0 local deleted_expired 0 -- 过期 Key 删除计数 local deleted_large 0 -- 超大 Key 删除计数 local batch_del {} -- 批量删除缓存避免频繁 DEL local batch_max 50 -- 每批次最多删 50 个 Key -- 循环 SCAN 遍历所有 Key repeat -- 执行 SCANcursor 下一个游标 keys 当前批次 Key 列表 local scan_result redis.call(SCAN, cursor, COUNT, scan_count) cursor scan_result[1] local keys scan_result[2] -- 遍历当前批次 Key for _, key in ipairs(keys) do -- 跳过空 Key if key nil or key then goto continue end -- 条件1删除已过期 Keyttl ≤ 0 且 不是永不过期 local ttl redis.call(TTL, key) if ttl 0 and ttl ~ -1 then table.insert(batch_del, key) deleted_expired deleted_expired 1 goto continue -- 满足过期条件无需检查大小 end -- 条件2删除超过阈值的超大 Key local size redis.call(MEMORY, USAGE, key) if tonumber(size) max_key_size then table.insert(batch_del, key) deleted_large deleted_large 1 end ::continue:: -- 批量删除达到批次上限则执行 DEL if #batch_del batch_max then redis.call(DEL, unpack(batch_del)) batch_del {} -- 清空缓存 end end -- 游标为 0 时结束遍历 until cursor 0 -- 处理剩余未删除的 Key if #batch_del 0 then redis.call(DEL, unpack(batch_del)) end -- 返回清理结果 return { [deleted_expired] deleted_expired, [deleted_large] deleted_large }编写redis_cluster_lua_clean.sh自动识别集群主节点逐个执行 Lua 脚本适配三主三从集群#!/bin/bash # Redis 三主三从集群清理脚本Lua 版 # 自动识别主节点 → 执行 Lua 脚本 → 输出清理结果 ########################## 配置区根据实际修改 ########################## # Redis 集群任意节点用于获取主节点列表 CLUSTER_NODE192.168.1.10:6379 # Redis 密码无密码则删除 -a $REDIS_PWD REDIS_PWDyour_redis_password # 超大 Key 阈值10M字节 MAX_SIZE$((10 * 1024 * 1024)) # SCAN 每次遍历数量建议 200-500 SCAN_COUNT200 # Lua 脚本路径 LUA_SCRIPT/path/to/redis_clean.lua # 日志文件 LOG_FILE/var/log/redis_cluster_lua_clean.log ########################################################################### # 日志函数带时间戳 log() { echo [$(date %Y-%m-%d %H:%M:%S)] $1 $LOG_FILE } # 检查依赖 if ! command -v redis-cli /dev/null; then log 错误未找到 redis-cli请安装 Redis 客户端 exit 1 fi if [ ! -f $LUA_SCRIPT ]; then log 错误Lua 脚本不存在 → $LUA_SCRIPT exit 1 fi # 步骤1获取集群所有主节点 log 开始获取集群主节点列表... MASTER_NODES$(redis-cli -h $(echo $CLUSTER_NODE | cut -d: -f1) \ -p $(echo $CLUSTER_NODE | cut -d: -f2) \ -a $REDIS_PWD --raw CLUSTER NODES 2 $LOG_FILE \ | grep -E master|myself,master \ | awk {print $2} | cut -d -f1 | sort -u) if [ -z $MASTER_NODES ]; then log 错误未获取到主节点请检查集群连接/密码 exit 1 fi log 获取到主节点$MASTER_NODES # 步骤2遍历主节点执行 Lua 脚本 TOTAL_EXPIRED0 TOTAL_LARGE0 for NODE in $MASTER_NODES; do HOST$(echo $NODE | cut -d: -f1) PORT$(echo $NODE | cut -d: -f2) log 开始清理主节点 → $HOST:$PORT # 执行 Lua 脚本--eval 加载脚本ARGV 传参 RESULT$(redis-cli -h $HOST -p $PORT -a $REDIS_PWD --raw \ EVAL $(cat $LUA_SCRIPT) 0 $MAX_SIZE $SCAN_COUNT 2 $LOG_FILE) # 解析 Lua 返回结果示例{deleted_expired10,deleted_large2} NODE_EXPIRED$(echo $RESULT | grep -oP deleted_expired\s*:\s*\K\d) NODE_LARGE$(echo $RESULT | grep -oP deleted_large\s*:\s*\K\d) # 兼容空结果 NODE_EXPIRED${NODE_EXPIRED:-0} NODE_LARGE${NODE_LARGE:-0} # 累计计数 TOTAL_EXPIRED$((TOTAL_EXPIRED NODE_EXPIRED)) TOTAL_LARGE$((TOTAL_LARGE NODE_LARGE)) log [$HOST:$PORT] 清理完成 → 过期 Key$NODE_EXPIRED 个超大 Key$NODE_LARGE 个 done # 步骤3输出汇总 log 集群清理汇总 log 总删除过期 Key $TOTAL_EXPIRED 个超大 Key $TOTAL_LARGE 个 log log # 空行分隔日志 exit 0