來源:Redislabsredis
做者:Kyle Davis安全
翻譯:Kevin (公衆號:中間件小哥)服務器
Redis 4.0給Redis生態帶來了一個驚人的功能:Modules(模塊)。Modules是Redis的一大轉變,它是Redis內部自定義數據類型和全速計算的開放環境。可是,儘管對該版本的大多數關注都集中在Modules上,但新版本還引入了一個很是重要的命令,它就是遊戲規則的改變者:UNLINK。網絡
您可使用redis-cli鏈接redis-server執行info命令,去查看當前redis版本中是否可使用UNLINK命令。info響應將告訴您有關服務器的全部信息。在第一部分(#Server)中,返回結果有一行值爲redis_version。若是該值大於4.0,則可使用UNLINK命令。並不是全部Redis提供商都保持最新版本,所以最好在更改代碼以前檢查redis版本。數據結構
讓咱們回顧一下Redis的關鍵架構功能之一:「單線程」。Redis在大多數狀況下是一個單線程應用程序。它一次只作一件事,這樣能夠把這些事作的更快。多線程有點複雜,而且引入了鎖和其餘可能下降應用程序速度的問題。儘管Redis(最高4.0版)經過多線程方式執行了少許操做,但它一般在啓動另外一個命令以前先要完成一個命令。多線程
相比於快速讀寫,您可能會以爲使用DEL命令去刪除一個鍵值不須要考慮太多,可是在不少狀況下,刪除數據一樣很重要。與Redis中的大多數命令同樣,DEL命令在單個線程中運行,若是您獲取一個幾千字節的鍵值,花費不到一毫秒的時間,這是您所感知不到的。然而,當您獲取的鍵值大小是兆字節、100兆字節或者500兆字節會發生什麼呢?哈希、排序、列表等數據結構會隨着時間的推移而添加更多的數據進去,這樣會生成一個數GB大小的數據集。而後用DEL命令去刪除大Key時會發生什麼呢?因爲Redis是單線程操做的,處理這種請求時整個服務都處於等待中,須要等待該命令執行完成才能執行其它操做。同時,咱們考慮更復雜的一種場景,這些鍵中保存的數據可能已經包含數以千萬個微小請求,所以應用程序或操做員可能沒法真正瞭解刪除這些數據須要花費多長時間。架構
理智會告訴咱們不要在擁有100萬元素的排序集上運行以下這樣的命令:性能
> ZRANGE some-zset 0 -1線程
可是,在上面的some-zset集合中執行DEL命令將花費和上面同樣的時間-中間沒有傳輸開銷,可是它會一直去分配內存,並且您會一直卡死在CPU繁忙中。在使用UNLINK以前,您可能會結合SCAN命令採用非原子性的方法進行一些少許刪除,去避免這種持續分配內存的噩夢。上面不管使用哪一種方式,都是讓人沒法接受的。翻譯
您可能已經猜到了,就是使用UNLINK命令來替換DEL!從語法上講,UNLINK與DEL相同,但UNLINK提供了更爲理想的解決方案。首先,它將鍵值從整個鍵值空間中刪除。而後,在另外一個線程中,它開始回收內存。從多線程的角度來看,這是一種安全的操做,由於它(在主線程中)從鍵空間中刪除了該項,從而使Redis其它命令沒法訪問。
若是你有一個快速增加的鍵值-無論鍵值的大小如何,UNLINK都是O(1)操做(每一個鍵;在主線程中)。使用DEL刪除一個大值可能須要幾百毫秒或更長時間,而UNLINK將在不到一毫秒的時間內完成(包括網絡往返)。固然,您的服務器仍將須要花一些時間在另外一個線程中從新分配該值的內存(其中的工做是O(N),其中N是已刪除值的分配數),可是主線程的性能不會被另外一個線程中正在進行的操做嚴重影響到。
所以,您是否應該用UNLINK命令替換代碼中的全部DEL命令?固然,在少數狀況下,DEL正是您所須要的。這裏我能夠想到兩點:
一、 在MULTI / EXEC或pipeline中,在添加和刪除大值時DEL命令是一種理想選擇。在這種狀況下,UNLINK不會當即釋放空間,而且在處理繁忙的狀況下(若是內存已滿),您可能會遇到麻煩。
二、 在更緊急的狀況下,在無快速響應驅逐數據下您能夠寫入數據。
在沒有極端內存限制的理想環境中,很難想到不使用UNLINK的狀況。UNLINK將提供更一致的行爲,整體上具備更好的性能,而且代碼更改很是小(若是能夠在客戶端中重命名命令,則無需更改)。若是UNLINK適合您的應用程序,請就此將您的DEL更改成UNLINK,而後查看它的性能提升。
更多優質中間件技術資訊/原創/翻譯文章/資料/乾貨,請關注「中間件小哥」公衆號!