這篇文章主要介紹“如何使用redis中scan命令”,在日常操作中,相信很多人在如何使用Redis中scan命令問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”如何使用Redis中scan命令”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
新沂ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為創(chuàng)新互聯(lián)公司的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18982081108(備注:SSL證書合作)期待與您的合作!
所以記錄下這個踩坑的過程,背景如下:
公司因為redis服務(wù)器內(nèi)存吃緊,需要刪除一些無用的沒有設(shè)置過期時間的key。大概有500多w的key。雖然key的數(shù)目聽起來挺嚇人。但是自己玩redis也有年頭了,這種事還不是手到擒來?
當(dāng)時想了下,具體方案是通過lua腳本來過濾出500w的key。然后進(jìn)行刪除動作。lua腳本在redis server上執(zhí)行,執(zhí)行速度快,執(zhí)行一批只需要和redis server建立一次連接。篩選出來key,然后一次刪1w。然后通過shell腳本循環(huán)個500次就能刪完所有的。以前通過lua腳本做過類似批量更新的操作,3w一次也是秒級的。基本不會造成redis的阻塞。這樣算起來,10分鐘就能搞定500w的key。
然后,我就開始直接寫lua腳本。首先是篩選。
用過redis的人,肯定知道redis是單線程作業(yè)的,肯定不能用keys命令來篩選,因為keys命令會一次性進(jìn)行全盤搜索,會造成redis的阻塞,從而會影響正常業(yè)務(wù)的命令執(zhí)行。
500w數(shù)據(jù)量的key,只能增量迭代來進(jìn)行。redis提供了scan命令,就是用于增量迭代的。這個命令可以每次返回少量的元素,所以這個命令十分適合用來處理大的數(shù)據(jù)集的迭代,可以用于生產(chǎn)環(huán)境。
scan命令會返回一個數(shù)組,第一項為游標(biāo)的位置,第二項是key的列表。如果游標(biāo)到達(dá)了末尾,第一項會返回0。
所以我寫的第一版的lua腳本如下:
local c = 0local resp = redis.call('SCAN',c,'MATCH','authToken*','COUNT',10000) c = tonumber(resp[1])local dataList = resp[2]for i=1,#dataList dolocal d = dataList[i]local ttl = redis.call('TTL',d)if ttl == -1 thenredis.call('DEL',d)endendif c==0 then return 'all finished'else return 'end'end
在本地的測試redis環(huán)境中,通過執(zhí)行以下命令mock了20w的測試數(shù)據(jù):
eval "for i = 1, 200000 do redis.call('SET','authToken_' .. i,i) end" 0
然后執(zhí)行script load命令上傳lua腳本得到SHA值,然后執(zhí)行evalsha去執(zhí)行得到的SHA值來運行。具體過程如下:
發(fā)現(xiàn)游標(biāo)雖然沒有到達(dá)末尾,但是key的列表卻是空的。
這個結(jié)果讓我懵逼了一段時間。我仔細(xì)檢查了lua腳本,沒有問題啊。難道是redis的scan命令有bug?難道我理解的有問題?
我再去翻看redis的命令文檔對count選項的解釋:
看完之后恍然大悟。原來count選項后面跟的數(shù)字并不是意味著每次返回的元素數(shù)量,而是scan命令每次遍歷字典槽的數(shù)量
我scan執(zhí)行的時候每一次都是從游標(biāo)0的位置開始遍歷,而并不是每一個字典槽里都存放著我所需要篩選的數(shù)據(jù),這就造成了我最后的一個現(xiàn)象:雖然我count后面跟的是10000,但是實際redis從開頭往下遍歷了10000個字典槽后,發(fā)現(xiàn)沒有數(shù)據(jù)槽存放著我所需要的數(shù)據(jù)。所以我最后的dbsize數(shù)量永遠(yuǎn)停留在了124204個。
所以在使用scan命令的時候,如果需要迭代的遍歷,需要每次調(diào)用都需要使用上一次這個調(diào)用返回的游標(biāo)作為該次調(diào)用的游標(biāo)參數(shù),以此來延續(xù)之前的迭代過程。
至此,心中的疑惑就此解開,改了一版lua:
local c = tonumber(ARGV[1])local resp = redis.call('SCAN',c,'MATCH','authToken*','COUNT',10000) c = tonumber(resp[1])local dataList = resp[2]for i=1,#dataList dolocal d = dataList[i]local ttl = redis.call('TTL',d)if ttl == -1 thenredis.call('DEL',d)endendreturn c
在本地上傳后執(zhí)行:
可以看到,scan命令沒法完全保證每次篩選的數(shù)量完全等同于給定的count,但是整個迭代卻很好的延續(xù)下去了。最后也得到了游標(biāo)返回0,也就是到了末尾。至此,測試數(shù)據(jù)20w被全部刪完。
這段lua只要在套上shell進(jìn)行循環(huán)就可以直接在生產(chǎn)上跑了。經(jīng)過估算大概在12分鐘左右能刪除掉500w的數(shù)據(jù)。
到此,關(guān)于“如何使用Redis中scan命令”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
本文題目:如何使用Redis中scan命令
網(wǎng)站路徑:http://weahome.cn/article/jdpcep.html