最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Redis中Scan命令的踩坑實(shí)錄

 更新時(shí)間:2020年07月19日 15:03:11   作者:菠菜東  
這篇文章主要給大家介紹了關(guān)于Redis中Scan命令踩坑的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧

1、原本以為自己對redis命令還蠻熟悉的,各種數(shù)據(jù)模型各種基于redis的騷操作。但是最近在使用redis的scan的命令式卻踩了一個(gè)坑,頓時(shí)發(fā)覺自己原來對redis的游標(biāo)理解的很有限。所以記錄下這個(gè)踩坑的過程,背景如下:

公司因?yàn)閞edis服務(wù)器內(nèi)存吃緊,需要?jiǎng)h除一些無用的沒有設(shè)置過期時(shí)間的key。大概有500多w的key。雖然key的數(shù)目聽起來挺嚇人。但是自己玩redis也有年頭了,這種事還不是手到擒來?

當(dāng)時(shí)想了下,具體方案是通過lua腳本來過濾出500w的key。然后進(jìn)行刪除動作。lua腳本在redis server上執(zhí)行,執(zhí)行速度快,執(zhí)行一批只需要和redis server建立一次連接。篩選出來key,然后一次刪1w。然后通過shell腳本循環(huán)個(gè)500次就能刪完所有的。以前通過lua腳本做過類似批量更新的操作,3w一次也是秒級的?;静粫斐蓃edis的阻塞。這樣算起來,10分鐘就能搞定500w的key。

然后,我就開始直接寫lua腳本。首先是篩選。

用過redis的人,肯定知道redis是單線程作業(yè)的,肯定不能用keys命令來篩選,因?yàn)閗eys命令會一次性進(jìn)行全盤搜索,會造成redis的阻塞,從而會影響正常業(yè)務(wù)的命令執(zhí)行。

500w數(shù)據(jù)量的key,只能增量迭代來進(jìn)行。redis提供了scan命令,就是用于增量迭代的。這個(gè)命令可以每次返回少量的元素,所以這個(gè)命令十分適合用來處理大的數(shù)據(jù)集的迭代,可以用于生產(chǎn)環(huán)境。

scan命令會返回一個(gè)數(shù)組,第一項(xiàng)為游標(biāo)的位置,第二項(xiàng)是key的列表。如果游標(biāo)到達(dá)了末尾,第一項(xiàng)會返回0。

2、所以我寫的第一版的lua腳本如下:

local c = 0
local resp = redis.call('SCAN',c,'MATCH','authToken*','COUNT',10000)
c = tonumber(resp[1])
local dataList = resp[2]

for i=1,#dataList do
 local d = dataList[i]
 local ttl = redis.call('TTL',d)
 if ttl == -1 then
  redis.call('DEL',d)
 end
end

if 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值來運(yùn)行。具體過程如下:

我每刪1w數(shù)據(jù),執(zhí)行下dbsize(因?yàn)檫@是我本地的redis,里面只有mock的數(shù)據(jù),dbsize也就等同于這個(gè)前綴key的數(shù)量了)。

奇怪的是,前面幾行都是正常的。但是到了第三次的時(shí)候,dbsize變成了16999,多刪了1個(gè),我也沒太在意,但是最后在dbsize還剩下124204個(gè)的時(shí)候,數(shù)量就不動了。之后無論再執(zhí)行多少遍,數(shù)量還依舊是124204個(gè)。

隨即我直接運(yùn)行scan命令:

發(fā)現(xiàn)游標(biāo)雖然沒有到達(dá)末尾,但是key的列表卻是空的。

這個(gè)結(jié)果讓我懵逼了一段時(shí)間。我仔細(xì)檢查了lua腳本,沒有問題啊。難道是redis的scan命令有bug?難道我理解的有問題?

我再去翻看redis的命令文檔對count選項(xiàng)的解釋:

經(jīng)過詳細(xì)研讀,發(fā)現(xiàn)count選項(xiàng)所指定的返回?cái)?shù)量還不是一定的,雖然知道可能是count的問題,但無奈文檔的解釋實(shí)在難以很通俗的理解,依舊不知道具體問題在哪

3、后來經(jīng)過某個(gè)小伙伴的提示,看到了另外一篇對于scan命令count選項(xiàng)通俗的解釋:

看完之后恍然大悟。原來count選項(xiàng)后面跟的數(shù)字并不是意味著每次返回的元素?cái)?shù)量,而是scan命令每次遍歷字典槽的數(shù)量

我scan執(zhí)行的時(shí)候每一次都是從游標(biāo)0的位置開始遍歷,而并不是每一個(gè)字典槽里都存放著我所需要篩選的數(shù)據(jù),這就造成了我最后的一個(gè)現(xiàn)象:雖然我count后面跟的是10000,但是實(shí)際redis從開頭往下遍歷了10000個(gè)字典槽后,發(fā)現(xiàn)沒有數(shù)據(jù)槽存放著我所需要的數(shù)據(jù)。所以我最后的dbsize數(shù)量永遠(yuǎn)停留在了124204個(gè)。

所以在使用scan命令的時(shí)候,如果需要迭代的遍歷,需要每次調(diào)用都需要使用上一次這個(gè)調(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 do
 local d = dataList[i]
 local ttl = redis.call('TTL',d)
 if ttl == -1 then
  redis.call('DEL',d)
 end
end

return c

在本地上傳后執(zhí)行:

可以看到,scan命令沒法完全保證每次篩選的數(shù)量完全等同于給定的count,但是整個(gè)迭代卻很好的延續(xù)下去了。最后也得到了游標(biāo)返回0,也就是到了末尾。至此,測試數(shù)據(jù)20w被全部刪完。

這段lua只要在套上shell進(jìn)行循環(huán)就可以直接在生產(chǎn)上跑了。經(jīng)過估算大概在12分鐘左右能刪除掉500w的數(shù)據(jù)。

知其然,知其所以然。雖然scan命令以前也曾玩過。但是的確不知道其中的細(xì)節(jié)。況且文檔的翻譯也不是那么的準(zhǔn)確,以至于自己在面對錯(cuò)誤的結(jié)果時(shí)整整浪費(fèi)了近1個(gè)多小時(shí)的時(shí)間。記錄下來,加深理解。

總結(jié)

到此這篇關(guān)于Redis中Scan命令踩坑的文章就介紹到這了,更多相關(guān)Redis Scan命令踩坑內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 深入解析Redis中常見的應(yīng)用場景

    深入解析Redis中常見的應(yīng)用場景

    這篇文章主要給大家介紹了關(guān)于Redis中常見的應(yīng)用場景的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-09-09
  • Redis分布式鎖的超時(shí)問題及解決

    Redis分布式鎖的超時(shí)問題及解決

    這篇文章主要介紹了Redis分布式鎖的超時(shí)問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • Redis中Lua腳本的常見場景

    Redis中Lua腳本的常見場景

    Redis 的 Lua 腳本可以極大提升操作的原子性和效率,特別適用于需要多個(gè) Redis 命令組合執(zhí)行的場景,本文就來詳細(xì)的介紹一下Redis中Lua腳本的常見場景,感興趣的可以了解一下
    2025-10-10
  • 深入理解Redis內(nèi)存回收和內(nèi)存淘汰機(jī)制

    深入理解Redis內(nèi)存回收和內(nèi)存淘汰機(jī)制

    Redis使用多種過期策略和內(nèi)存淘汰機(jī)制來管理內(nèi)存,本文主要介紹了深入理解Redis內(nèi)存回收和內(nèi)存淘汰機(jī)制, 具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-06-06
  • 詳解Redis中地理位置功能Geospatial的應(yīng)用

    詳解Redis中地理位置功能Geospatial的應(yīng)用

    Geospatial?Indexes?是?Redis?提供的一種數(shù)據(jù)結(jié)構(gòu),用于存儲和查詢地理位置信息,這篇文章就來和大家詳細(xì)講講Geospatial的具體應(yīng)用吧
    2023-06-06
  • Redis中緩存穿透的實(shí)現(xiàn)示例

    Redis中緩存穿透的實(shí)現(xiàn)示例

    本文主要介紹了Redis中緩存穿透的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-07-07
  • Redis中的過期策略和淘汰策略使用詳解

    Redis中的過期策略和淘汰策略使用詳解

    這篇文章主要介紹了Redis中的過期策略和淘汰策略使用方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-06-06
  • Redis實(shí)現(xiàn)持久化的方式匯總

    Redis實(shí)現(xiàn)持久化的方式匯總

    Redis是一種高級key-value數(shù)據(jù)庫。它跟memcached類似,不過數(shù)據(jù)可以持久化,而且支持的數(shù)據(jù)類型很豐富。今天我們就來看看如何實(shí)現(xiàn)Redis持久化,需要的朋友可以參考下
    2022-10-10
  • 淺談Redis的事件驅(qū)動模型

    淺談Redis的事件驅(qū)動模型

    本文主要介紹了淺談Redis的事件驅(qū)動模型,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • Redis Cluster集群主從切換的踩坑與填坑

    Redis Cluster集群主從切換的踩坑與填坑

    這篇文章主要介紹了Redis Cluster集群主從切換的踩坑與填坑,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04

最新評論

永德县| 赤水市| 和龙市| 浑源县| 南部县| 平武县| 常德市| 长葛市| 桂平市| 瓮安县| 句容市| 大余县| 溧阳市| 大足县| 武威市| 周至县| 三江| 广饶县| 湖州市| 潢川县| 磐安县| 宣恩县| 汾阳市| 丰顺县| 丰都县| 历史| 山阳县| 包头市| 太谷县| 靖州| 肥东县| 咸阳市| 饶平县| 万全县| 廉江市| 韶关市| 剑川县| 印江| 赞皇县| 阿城市| 易门县|