Redis原始碼系列之rename講解

Kuper發表於2021-09-13

前言

文章來自部落格,檢視最新文章,請點選檢視部落格,歡迎大家關注與討論

當使用 rename oldKey newKey 命令時,主要會執行如下兩個操作

1、隱式刪除newKey

由於rename操作不是renameNX,而是強制性的把舊Key名修改為新Key名。因此如果新Key名指向了資料,Redis就必先把這個資料刪掉!

image.png 注 :key對應的Value抽象為memory記憶體

(1) 原始碼

在Redis中,無論執行rename還是renameNX命令,都會執行一個通用的renameGenericCommand函式,只是傳遞的第二個NX引數不一樣而已,而client引數就是如其名,表示客戶端,用於獲取命令攜帶的引數

  • c->argv[1]表示oldKey
  • c->argv[2]表示newKey

所以核心看renameGenericCommand函式即可

image.png

如下程式碼中 if(lookupKeyWrite(c->db,c->argv[2]) != NULL) ,其中lookupKeyWrite 函式會返回Key所指向的記憶體指標,如果不為空,則說明已經有資料儲存,所以緊接著就會執行刪除newKey的邏輯

image.png

(2) 時間複雜度

時間複雜度為O(M) ,M為成員數量

(3) 測試

先寫一個有500W成員的Hash型別的bigkey,如下圖發現寫入後,記憶體增加約400MB,刪除它需要3秒左右

image.png

image.png

image.png

然後我們執行rename操作,結果如下

image.png

所以rename操作會隱式的同步刪除newKey,且刪除耗時為O(M)

2、修改指標指向

Redis有如下兩種方案可以實現rename效果,第一種是資料拷貝,第二種是修改指標指向。如果採用值拷貝的方式,會增加Redis的記憶體峰值,且拷貝記憶體的時間也會增加耗時,最重要的值拷貝在Redis場景中不需要,所以Redis使用的是第二種修改指標的方式

image.png

注 :key對應的Value抽象為memory記憶體

(1) 原始碼

如下原始碼中,在拿到oldKey指向的記憶體物件(值物件)指標後,記為o,然後依次做如下操作

  • 為o引用計數加1,此時o的引用計數為2
  • 把新的鍵值關係(newKey => o)增加到當前DB中,相當於讓newKey重新指向o
  • 刪除舊的鍵值(oldKey => o)關係,相當於刪除oldKey的指向

由於o的引用計數為2,在刪除了oldKey的指向關係後,o的引用計數還是1,並不會觸發GC,所以物件o所佔用的記憶體空間仍然是有效的,不過變成了由newKey指向

image.png

(2) 時間複雜度

O(1)

3、總結

rename操作耗時為O(1)是不準確的,應該為O(M)+O(1)

  • O(M)為刪除newKey的耗時,成員與刪除耗時成線性關係
  • O(1)為newKey指向新記憶體的耗時,是常數級別,可忽略
  1. find newKey :找到newKey所指向的值物件
  2. delete memory A :刪除值物件所指向的記憶體
  3. find oldKey :找到oldKey所指向的值物件
  4. incrRefCount :為oldKey所指向的值物件的引用計數+1
  5. add relation :把(newKey => o)新的鍵值對資訊加到資料庫中,讓newKey指向一個新的值物件
  6. delete relation :刪除(oldKey => o)舊的鍵值對資訊,讓oldKey不再指向之前的值物件

image.png

注 :key對應的Value抽象為memory記憶體

1、rename具有原子性嗎

從原始碼中看,rename過程需要經過刪除newKey和修改指標指向這兩步,而如果第二步失敗,第一步操作並不會回滾,所以不具有原子性

2、rename中的刪除操作是同步的嗎

從程式碼中可以看到是同步還是非同步,完全取決於配置的DEL機制,即由lazyfree-lazy-server-del配置決定。

image.png

image.png

3、如何解決rename耗時長的問題

之前測試中發現rename操作卡了3秒,執行config get *命令,發現確實配置的刪除方式為同步刪除

image.png

所以解決方法有兩個,要麼減少Key的member成員數量,要麼配置lazyfree-lazy-server-delyes

本文已結束,能力有限,文章錯誤地方煩請指出,感謝大家的閱讀

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章