加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

Redis 刪除 key用 del 和 unlink 有啥區(qū)別?

2023/04/17
3193
閱讀需 4 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

問題

del 和 unlink 有啥區(qū)別???為什么String類型刪除不會(huì)做異步刪除?

彬彬回答

DEL 和 UNLINK 都是同步的釋放 key 對象,區(qū)別是怎么釋放后面的 value 對象

DEL 每次都是同步釋放 value 部分,如果 value 很大,例如一個(gè) list 里很多元素,這會(huì)阻塞 Redis 工作線程。

為了規(guī)避這個(gè)問題,4.0 里引出了 UNLINK 命令,可以異步釋放 value 對象,放到一個(gè)子線程中。

這邊需要引出一個(gè)釋放的閾值,見后面解釋。

目前默認(rèn)的閾值是 64,例如只有一個(gè) list 里面含有超過 64 個(gè)元素,才會(huì)異步釋放,否則也是會(huì)同步釋放

不同的數(shù)據(jù)結(jié)構(gòu)的計(jì)算閾值的方式不一樣,不過大致遵循一個(gè)原則:就是要釋放多少塊內(nèi)存

即在小對象上使用 UNLINK 效果等同于 DEL,也是同步釋放,區(qū)別就是要多走幾個(gè)函數(shù)調(diào)用,例如判斷 list 里需要判斷列表的長度等

大 value 對象的釋放是異步的,放在一個(gè)子線程上,小對象之所以不異步釋放,是因?yàn)楫惒结尫?,主線程和子線程之間需要做一些同步操作(這是有代價(jià)的),然后小對象釋放,本身也很快就也不值得進(jìn)行異步釋放,內(nèi)存釋放也更及時(shí)。

即可能異步釋放,實(shí)際上會(huì)比同步釋放更慢,所以作者設(shè)置了個(gè) 64 的經(jīng)驗(yàn)值

所以如果是一個(gè)小對象,DEL 和 UNLINK 其實(shí)一樣;如果是一個(gè)大對象,UNLINK 會(huì)更加好。

所以大部分情況下都可以用 UNLINK 代替 DEL,而 Redis 其實(shí)也有個(gè)配置項(xiàng),可以控制將 DEL 默認(rèn)轉(zhuǎn)換為 UNLINK(實(shí)現(xiàn)上都是同一個(gè)函數(shù),只是入口 async 參數(shù)不同)

不過我們需要知道異步釋放的好處(不阻塞主線程)和它的壞處(需要進(jìn)行一些線程同步相關(guān)的操作,內(nèi)存釋放不及時(shí))。

至于說 string 為啥不異步釋放,主要是作者認(rèn)為它是一整塊內(nèi)存空間,計(jì)算閾值的時(shí)候 string 的結(jié)果固定是 1,那么就 <= 64,就是同步釋放。

在補(bǔ)充一點(diǎn),前面舉例是說的 list,底層是用的 quicklist,嚴(yán)格來說統(tǒng)計(jì)的是 quicklistNode 的節(jié)點(diǎn)數(shù)量,就不是列表元素?cái)?shù)量。

像 zset 那些如果用的 ziplist/listpack 編碼的話,這種計(jì)算出來的閾值是 1,就也不是元素?cái)?shù)量。如果是跳表編碼的話就是統(tǒng)計(jì)的元素?cái)?shù)量。

然后至于選擇的話,大部分情況可以無腦用 UNLINK,不過需要知道壞處。

例如對于每一次的 async delete,主線程給子線程提交任務(wù)時(shí)需要加鎖解鎖,bio 子線程消費(fèi)任務(wù)的時(shí)候也要加鎖解鎖,要做一些線程同步,還有線程上下文切換,這些都是可能會(huì)有的潛在的問題,如果小元素都異步釋放的話,的確代價(jià)可能會(huì)大,多線程做事情的確是會(huì)有這些麻煩。

可以多做壓測來驗(yàn)證環(huán)境里到底哪個(gè)好,不過大部分情況這些我們不用關(guān)系,只要寫代碼的時(shí)候有意識的注意大 key 的釋放就好。

 

相關(guān)推薦

電子產(chǎn)業(yè)圖譜