REDIS清理死鍵

背景

在做一些項目的過程中,有些項目對于后端數(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,并將它做一些清理落地處理。

項目地址

github地址

命令科普

  • 死鍵
    所謂死鍵,在redis里有兩個定義。
    1. 死鍵是指redis中的key超過過期時間,但是沒有在內(nèi)存中被實際刪除的key。
      PS: 這種情況是可能發(fā)生的,在redis中過期鍵的刪除有兩種策略,一般采用的是定期刪除(比如每s刪除10個),這樣的話,如果我們過期鍵產(chǎn)生的速度是大于刪除的速度,則會產(chǎn)生死鍵。
    2. 死鍵是指在redis中長期未被訪問的key(需要根據(jù)業(yè)務(wù)需求,查看能否刪除)
  • 輪轉(zhuǎn)時間
    輪轉(zhuǎn)時間即idletime,是指該key有多長時間沒有被訪問過(單位 s)。
    OBJECT IDLETIME KEY
    image.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.png
    image.png
  • 查找并落地數(shù)據(jù)+刪除
    刪掉注釋,開始刪除數(shù)據(jù)


    image.png

    運行程序,用時26s 原因(生成數(shù)據(jù)value均為數(shù)字,存儲很快):


    image.png
    image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容