1. 程式人生 > 實用技巧 >Redis 雜湊物件

Redis 雜湊物件

雜湊物件的編碼可以是ziplist或者hashtable

ziplist編碼的雜湊物件使用壓縮列表作為底層實現, 每當有新的鍵值對要加入到雜湊物件時, 程式會先將儲存了鍵的壓縮列表節點推入到壓縮列表表尾, 然後再將儲存了值的壓縮列表節點推入到壓縮列表表尾, 因此:

  • 儲存了同一鍵值對的兩個節點總是緊挨在一起, 儲存鍵的節點在前, 儲存值的節點在後;
  • 先新增到雜湊物件中的鍵值對會被放在壓縮列表的表頭方向, 而後來新增到雜湊物件中的鍵值對會被放在壓縮列表的表尾方向。

舉個例子, 如果我們執行以下HSET命令, 那麼伺服器將建立一個列表物件作為profile鍵的值:

redis> HSET profile name "
Tom" (integer) 1 redis> HSET profile age 25 (integer) 1 redis> HSET profile career "Programmer" (integer) 1

如果profile鍵的值物件使用的是ziplist編碼, 那麼這個值物件將會是圖 8-9 所示的樣子, 其中物件所使用的壓縮列表如圖 8-10 所示。

另一方面,hashtable編碼的雜湊物件使用字典作為底層實現, 雜湊物件中的每個鍵值對都使用一個字典鍵值對來儲存:

  • 字典的每個鍵都是一個字串物件, 物件中儲存了鍵值對的鍵;
  • 字典的每個值都是一個字串物件, 物件中儲存了鍵值對的值。

舉個例子, 如果前面profile鍵建立的不是ziplist編碼的雜湊物件, 而是hashtable編碼的雜湊物件, 那麼這個雜湊物件應該會是圖 8-11 所示的樣子。

編碼轉換

當雜湊物件可以同時滿足以下兩個條件時, 雜湊物件使用ziplist編碼:

  1. 雜湊物件儲存的所有鍵值對的鍵和值的字串長度都小於64位元組
  2. 雜湊物件儲存的鍵值對數量小於512

不能滿足這兩個條件的雜湊物件需要使用hashtable編碼。

注意

這兩個條件的上限值是可以修改的, 具體請看配置檔案中關於hash-max-ziplist-value選項和hash-max-ziplist-entries選項的說明。

對於使用ziplist

編碼的列表物件來說, 當使用ziplist編碼所需的兩個條件的任意一個不能被滿足時, 物件的編碼轉換操作就會被執行: 原本儲存在壓縮列表裡的所有鍵值對都會被轉移並儲存到字典裡面, 物件的編碼也會從ziplist變為hashtable

以下程式碼展示了雜湊物件因為鍵值對的鍵長度太大而引起編碼轉換的情況:

# 雜湊物件只包含一個鍵和值都不超過 64 個位元組的鍵值對
redis> HSET book name "Mastering C++ in 21 days"
(integer) 1

redis> OBJECT ENCODING book
"ziplist"

# 向雜湊物件新增一個新的鍵值對,鍵的長度為 66 位元組
redis> HSET book long_long_long_long_long_long_long_long_long_long_long_description "content"
(integer) 1

# 編碼已改變
redis> OBJECT ENCODING book
"hashtable"

除了鍵的長度太大會引起編碼轉換之外, 值的長度太大也會引起編碼轉換, 以下程式碼展示了這種情況的一個示例:

# 雜湊物件只包含一個鍵和值都不超過 64 個位元組的鍵值對
redis> HSET blah greeting "hello world"
(integer) 1

redis> OBJECT ENCODING blah
"ziplist"

# 向雜湊物件新增一個新的鍵值對,值的長度為 68 位元組
redis> HSET blah story "many string ... many string ... many string ... many string ... many"
(integer) 1

# 編碼已改變
redis> OBJECT ENCODING blah
"hashtable"

最後, 以下程式碼展示了雜湊物件因為包含的鍵值對數量過多而引起編碼轉換的情況:

# 建立一個包含 512 個鍵值對的雜湊物件
redis> EVAL "for i=1, 512 do redis.call('HSET', KEYS[1], i, i) end" 1 "numbers"
(nil)

redis> HLEN numbers
(integer) 512

redis> OBJECT ENCODING numbers
"ziplist"

# 再向雜湊物件新增一個新的鍵值對,使得鍵值對的數量變成 513 個
redis> HMSET numbers "key" "value"
OK

redis> HLEN numbers
(integer) 513

# 編碼改變
redis> OBJECT ENCODING numbers
"hashtable"