背景
在做一些項目的過程中,有些項目對于后端數(shù)據(jù)的接口請求時間要求更高,數(shù)據(jù)存儲讀取較頻繁,一般的mysql數(shù)據(jù)庫不能支持這種需求,所以對于這類項目,一般采用內(nèi)存型數(shù)據(jù)庫存儲-redis。
而對于redis,它相比于mysql資源成本是更高的,因此redis適合存儲一些重要或者緊要的數(shù)據(jù)。
在這類項目運行久了之后,一些老的key會不斷在redis里積壓,導(dǎo)致redis內(nèi)存越來越高,對redis的使用效率產(chǎn)生影響,因此需要對于redis數(shù)據(jù)進行定期清理。
這個項目是對于redis中的key進行篩選,查找到輪轉(zhuǎn)時間(長期沒有使用的時間)大于某個閾值的key,并將它做一些清理落地處理。
項目地址
命令科普
- 死鍵
所謂死鍵,在redis里有兩個定義。- 死鍵是指redis中的key超過過期時間,但是沒有在內(nèi)存中被實際刪除的key。
PS: 這種情況是可能發(fā)生的,在redis中過期鍵的刪除有兩種策略,一般采用的是定期刪除(比如每s刪除10個),這樣的話,如果我們過期鍵產(chǎn)生的速度是大于刪除的速度,則會產(chǎn)生死鍵。 - 死鍵是指在redis中長期未被訪問的key(需要根據(jù)業(yè)務(wù)需求,查看能否刪除)
- 死鍵是指redis中的key超過過期時間,但是沒有在內(nèi)存中被實際刪除的key。
- 輪轉(zhuǎn)時間
輪轉(zhuǎn)時間即idletime,是指該key有多長時間沒有被訪問過(單位 s)。
OBJECT IDLETIME KEYimage.png - 其他命令
SCAN key start match * count 1000 # 增量迭代 遍歷redis
get key # string類型
LRANGE key 0 -1 #list 類型
SMEMBERS key #set 類型
HGETALL key # hash 類型
ZRANGE key 0 -1 WITHSCORES # zset 類型
項目實現(xiàn)
語言:shell+lua
- shell腳本
redisCom="redis-cli -p 3310 -a password"
start=0
fileNamePre="unUseData_"
time=$(date "+%Y-%m-%d %H:%M:%S")
echo "拆分執(zhí)行 開始時間:${time} 開始索引 ${start}"
data=`${redisCom} --eval getUnusedData2.0.lua , ${start}`
echo ${data} | sed 's/ / \n/g' > "${fileNamePre}""${start}"
start=`echo ${data} | cut -d ' ' -f1`
time=$(date "+%Y-%m-%d %H:%M:%S")
echo "拆分執(zhí)行 結(jié)束時間:${time}"
while(( $start>0 ))
do
time=$(date "+%Y-%m-%d %H:%M:%S")
echo "拆分執(zhí)行 開始時間:${time} 開始索引 ${start}"
data=`${redisCom} --eval getUnusedData2.0.lua , ${start}`
echo ${data} | sed 's/ / \n/g' > "${fileNamePre}""${start}"
start=`echo ${data} | cut -d ' ' -f1`
time=$(date "+%Y-%m-%d %H:%M:%S")
echo "拆分執(zhí)行 結(jié)束時間:${time}"
done
time=$(date "+%Y-%m-%d %H:%M:%S")
echo "結(jié)束時間:${time}"
shell腳本主要是做一個觸發(fā)作用,循環(huán)調(diào)用getUnusedData2.0的LUA腳本。LUA腳本的目的就是每次遍歷10000條數(shù)據(jù),找到死鍵,然后做相應(yīng)處理。返回值如果為0表示redis遍歷完畢,都則繼續(xù)進行遍歷。
最后shell將遍歷后的結(jié)果進行簡單切割處理后,存儲至文件。
- LUA腳本-getUnusedData2.0
-- 獲取在臨界時間外的數(shù)據(jù)
local function getUnuseData()
data = nextCycle(start, count, match)
start = tonumber(data[1])
--開始判斷
for key,value in pairs(data[2])
do
local curTime = 0
curTime = getIdleTime(value)
if(curTime > maxTime)
then
local delData = {}
delData[1] = value
delData[2] = curTime
delData[3] , delData[4] = getkey(value)
--return delData
--delKey(value)
table.insert(keyData , delData)
--delKey(value)
end
end
return keyData , start
end
具體操作可以查看github源代碼
- LUA腳本-createRaw
-- 測試使用 為數(shù)據(jù)庫創(chuàng)建隨機數(shù)據(jù)
-- 隨機數(shù)
local num = 1000000
local function createRaw(num)
local value = math.random(num)
local key = "create_rew_data_"..tostring(math.random(num))
--local value = math.randomseed(num)
--return value
return redis.call("SET" , key, value)
end
math.randomseed(num)
--return num
--return createRaw(num)
for i=num,1,-1
do
createRaw(num)
end
目的是為了測試,在自己測試庫中寫入隨機數(shù)據(jù)。
項目運行
- 生成隨機數(shù)據(jù)
redis-cli --eval createRawData.lua
生成63萬數(shù)據(jù)
image.png -
查找數(shù)據(jù)
只查找符合要求的數(shù)據(jù),因為我們數(shù)據(jù)都是新生成的,所以我們設(shè)置閾值時間為0,一次查找10000條數(shù)據(jù)。
修改如下:
image.png運行腳本 耗時16s
image.pngimage.png -
查找并落地數(shù)據(jù)+刪除
刪掉注釋,開始刪除數(shù)據(jù)
image.png
運行程序,用時26s 原因(生成數(shù)據(jù)value均為數(shù)字,存儲很快):
image.pngimage.png







