一、前言
由于代码BUG原因,未设置给Redis的key设置过期时间,并且未配置Redis淘汰策略,长期导致环境服务器Redis占内存过大。
二、处理过程
1.环境数据分析
通过分析测试环境redis的数据,永久key数据如下:
CITICS_TRAIL_USER_X…(省略了)
CITICS_TRAIL_USER_X…
CiticsFundWholeIndustryX…
HistoryProduct1995Q420X…
ownValue2005Q4201908X…
yearlyRate2011Q4201908X…
把源头代码修改,给Redis的key设置过期时间。
2.脚本批量设置永久key过期时间
在redis中bin目录下执行该脚本:
#!/bin/bash
db_ip=127.0.0.1
db_port=6379
password=123456
cursor=0
cnt=100
new_cursor=0
exec_time=$(date +%Y%m%d)
#创建目录
function mkdirs(){
filedir=./redis_modify_key
if [ ! -d "$filedir" ]; then
mkdir -p $filedir
fi
}
#给Redis永久Key设置过期时间
function modifyKeyTime(){
#使用Redis中的scan命令,以非阻塞的方式实现key值的分页查找
./redis-cli -h $db_ip -p $db_port -a $password scan $cursor count $cnt > scan_tmp_result
#获取第一行,scan返回游标值
new_cursor=`sed -n '1p' scan_tmp_result`
#获取第二行到最后一行,100行key数据
sed -n '2,$p' scan_tmp_result > scan_result
cat scan_result |while read line
do
ttl_result=`./redis-cli -h $db_ip -p $db_port -a $password ttl $line`
if [[ $ttl_result == -1 ]];then
echo 'key:'$line >> ./redis_modify_key/modify_key_$exec_time.log
#获取5位不为0开始的随机数,避免设置同一过期时间,引起缓存雪崩
time=`tr -cd '1-9' </dev/urandom | head -c 5`
value=`./redis-cli -h $db_ip -p $db_port -a $password get $line`
result=`./redis-cli -h $db_ip -p $db_port -a $password expire $line $time`
echo 'value:'$value >> ./redis_modify_key/modify_key_$exec_time.log
echo 'expire:'$time >> ./redis_modify_key/modify_key_$exec_time.log
echo 'result:'$result >> ./redis_modify_key/modify_key_$exec_time.log
fi
done
#以 0 作为游标开始一次新的迭代, 一直调用 SCAN 命令, 直到命令返回游标 0 ,遍历完毕
while [ $cursor -ne $new_cursor ]
do
./redis-cli -h $db_ip -p $db_port -a $password scan $new_cursor count $cnt > scan_tmp_result
new_cursor=`sed -n '1p' scan_tmp_result`
sed -n '2,$p' scan_tmp_result > scan_result
cat scan_result |while read line
do
ttl_result=`./redis-cli -h $db_ip -p $db_port -a $password ttl $line`
if [[ $ttl_result == -1 ]];then
echo 'key:'$line >> ./redis_modify_key/modify_key_$exec_time.log
#获取5位不为0开始的随机数,避免设置同一过期时间,引起缓存雪崩
time=`tr -cd '1-9' </dev/urandom | head -c 5`
value=`./redis-cli -h $db_ip -p $db_port -a $password get $line`
result=`./redis-cli -h $db_ip -p $db_port -a $password expire $line $time`
echo 'value:'$value >> ./redis_modify_key/modify_key_$exec_time.log
echo 'expire:'$time >> ./redis_modify_key/modify_key_$exec_time.log
echo 'result:'$result >> ./redis_modify_key/modify_key_$exec_time.log
fi
done
done
rm -rf scan_tmp_result
rm -rf scan_result
}
#脚本主函数(入口)
function main(){
echo "[$(date "+%Y-%m-%d %H:%M:%S")] start..."
echo "脚本作用说明:给Redis永久Key设置过期时间"
mkdirs
modifyKeyTime
echo "[$(date "+%Y-%m-%d %H:%M:%S")] done!"
}
main
注意:windows下编辑过的.sh脚本
必须脚本执行以下命令,将windows下换行结尾是\n\r,转换成linux下\n:
命令1:sed -i 's/\r$//' 脚本名称
比如:sed -i 's/\r$//' setRedisKeyTime.sh
脚本赋于权限:
命令2:chmod -R 755 脚本名称
比如:chmod -R 755 setRedisKeyTime.sh
如果是找redis某些前缀key可以用以下命令:
比如找"prefix_"前缀key
./redis-cli -h $db_ip -p $db_port -a $password keys "prefix_*" | xargs -i ./redis-cli -h $db_ip -p $db_port -a $password expire {} $time
3.修改Redis淘汰策略
注意:假如修改maxmemory 1024mb,由于Redis前期没有配置淘汰策略,而且有些key是永久key,可能目前Redis占的内存大于1024mb以上,最好top命令看下Redis目前占内存多少,再配置淘汰策略限定内存,配置淘汰策略限定内存一定要大于目前Redis已使用的内存,否则会丢失一些key。建议把Redis一些永久key设置过期时间后,到了永久key过期时间后,内存降下来时再配置Redis淘汰策略。
noeviction:当内存使用达到阈值的时候,所有引起申请内存的命令会报错。
allkeys-lru:在主键空间中,优先移除最近未使用的key。(推荐)
volatile-lru:在设置了过期时间的键空间中,优先移除最近未使用的key。
allkeys-random:在主键空间中,随机移除某个key。
volatile-random:在设置了过期时间的键空间中,随机移除某个key。
volatile-ttl:在设置了过期时间的键空间中,具有更早过期时间的key优先移除。
Redis默认淘汰策略用noeviction。
在redis.conf文件中:
设置Redis 内存大小的限制,我们可以设置maxmemory ,当数据达到限定大小后,会选择配置的策略淘汰数据
比如:maxmemory 1024mb。
通过配置 设置Redis的淘汰策略。比如:maxmemory-policy allkeys-lru。