1. 程式人生 > 遊戲資訊 >【桌遊更新】《Marvel Zombies攻略》:#89—90

【桌遊更新】《Marvel Zombies攻略》:#89—90

雜湊在很多程式語言中都有著很廣泛的應用,而在Redis中也是如此,在redis中,雜湊型別是指Redis鍵值對中的值本身又是一個鍵值對結構,形如value=[{field1,value1},...{fieldN,valueN}],其與Redis字串物件的區別如下圖所示:

一、內部編碼#

雜湊型別的內部編碼有兩種:ziplist(壓縮列表),hashtable(雜湊表)。只有當儲存的資料量比較小的情況下,Redis 才使用壓縮列表來實現字典型別。具體需要滿足兩個條件:

  • 當雜湊型別元素個數小於hash-max-ziplist-entries配置(預設512個)

  • 所有值都小於hash-max-ziplist-value配置(預設64位元組)
    ziplist

    使用更加緊湊的結構實現多個元素的連續儲存,所以在節省記憶體方面比hashtable更加優秀。當雜湊型別無法滿足ziplist的條件時,Redis會使用hashtable作為雜湊的內部實現,因為此時ziplist的讀寫效率會下降,而hashtable的讀寫時間複雜度為O(1)。
    有關ziplist和hashtable這兩種redis底層資料結構的具體實現可以參考我的另外兩篇文章。

    Redis資料結構——壓縮列表

    Redis資料結構——字典

二、常用命令#

Redis雜湊物件常用命令如下表(點選命令可檢視命令詳細說明)。

命令 說明 時間複雜度
[HDEL key field field ...]
刪除一個或多個Hash的field O(N) N是被刪除的欄位數量。
HEXISTS key field 判斷field是否存在於hash中 O(1)
HGET key field 獲取hash中field的值 O(1)
HGETALL key 從hash中讀取全部的域和值 O(N) N是Hash的長度
HINCRBY key field increment 將hash中指定域的值增加給定的數字 O(1)
HINCRBYFLOAT key field increment 將hash中指定域的值增加給定的浮點數 O(1)
HKEYS key 獲取hash的所有欄位 O(N) N是Hash的長度
HLEN key 獲取hash裡所有欄位的數量 O(1)
[HMGET key field field ...] 獲取hash裡面指定欄位的值 O(N) N是請求的欄位數
[HMSET key field value field value ...] 設定hash欄位值 O(N) N是設定的欄位數
HSET key field value 設定hash裡面一個欄位的值 O(1)
HSETNX key field value 設定hash的一個欄位,只有當這個欄位不存在時有效 O(1)
HSTRLEN key field 獲取hash裡面指定field的長度 O(1)
HVALS key 獲得hash的所有值 O(N) N是Hash的長度
[HSCAN key cursor MATCH pattern] [COUNT count] 迭代hash裡面的元素

三、適用場景#

3.1 儲存物件#

Redis雜湊物件常常用來快取一些物件資訊,如使用者資訊、商品資訊、配置資訊等。

我們以使用者資訊為例,它在關係型資料庫中的結構是這樣的

uid name age
1 Tom 15
2 Jerry 13

而使用Redis Hash儲存其結構如下圖:

相比較於使用Redis字串儲存,其有以下幾個優缺點:

  1. 原生字串每個屬性一個鍵。

    Copyset user:1:name Tom
    set user:1:age 15
    

    優點:簡單直觀,每個屬性都支援更新操作。
    缺點:佔用過多的鍵,記憶體佔用量較大,同時使用者資訊內聚性比較差,所以此種方案一般不會在生產環境使用。

  2. 序列化字串後,將使用者資訊序列化後用一個鍵儲存

    Copyset user:1 serialize(userInfo)
    

    優點:簡化程式設計,如果合理的使用序列化可以提高記憶體的使用效率。
    缺點:序列化和反序列化有一定的開銷,同時每次更新屬性都需要把全部資料取出進行反序列化,更新後再序列化到Redis中。

  3. 序列化字串後,將使用者資訊序列化後用一個鍵儲存

    Copyhmset user:1 name Tom age 15 
    

    優點:簡單直觀,如果使用合理可以減少記憶體空間的使用。
    缺點:要控制雜湊在ziplist和hashtable兩種內部編碼的轉換,hashtable會消耗更多記憶體。

此外,我們曾經在做配置中心繫統的時候,使用Hash來快取每個應用的配置資訊,其在資料庫中的資料結構大致如下表

AppId SettingKey SettingValue
10001 AppName myblog
10001 Version 1.0
10002 AppName admin site

在使用Redis Hash進行儲存的時候

新增或更新一個配置項

Copy127.0.0.1:6379> HSET 10001 AppName myblog
(integer) 1

獲取一個配置項

Copy127.0.0.1:6379> HGET 10001 AppName 
"myblog"

刪除一個配置項

Copy127.0.0.1:6379> HDEL 10001 AppName
(integer) 1

3.2 購物車#

很多電商網站都會使用 cookie實現購物車,也就是將整個購物車都儲存到 cookie裡面。這種做法的一大優點:無須對資料庫進行寫入就可以實現購物車功能,這種方式大大提高了購物車的效能,而缺點則是程式需要重新解析和驗證( validate) cookie,確保cookie的格式正確,並且包含的商品都是真正可購買的商品。cookie購物車還有一個缺點:因為瀏覽器每次傳送請求都會連 cookie一起傳送,所以如果購物車cookie的體積比較大,那麼請求傳送和處理的速度可能會有所降低。

購物車的定義非常簡單:我們以每個使用者的使用者ID(或者CookieId)作為Redis的Key,每個使用者的購物車都是一個雜湊表,這個雜湊表儲存了商品ID與商品訂購數量之間的對映。在商品的訂購數量出現變化時,我們操作Redis雜湊對購物車進行更新:

如果使用者訂購某件商品的數量大於0,那麼程式會將這件商品的ID以及使用者訂購該商品的數量新增到雜湊裡面。

Copy//使用者1 商品1 數量1
127.0.0.1:6379> HSET uid:1 pid:1 1
(integer) 1 //返回值0代表改field在雜湊表中不存在,為新增的field

如果使用者購買的商品已經存在於雜湊裡面,那麼新的訂購數量會覆蓋已有的訂購數量;

Copy//使用者1 商品1 數量5
127.0.0.1:6379> HSET uid:1 pid:1 5
(integer) 0 //返回值0代表改field在雜湊表中已經存在

相反地,如果使用者訂購某件商品的數量不大於0,那麼程式將從雜湊裡面移除該條目。

Copy//使用者1 商品1
127.0.0.1:6379> HDEL uid:1 pid:2
(integer) 1

3.3 計數器#

Redis 雜湊表作為計數器的使用也非常廣泛。它常常被用在記錄網站每一天、一月、一年的訪問數量。每一次訪問,我們在對應的field上自增1

Copy//記錄我的
127.0.0.1:6379> HINCRBY MyBlog  202001 1
(integer) 1
127.0.0.1:6379> HINCRBY MyBlog  202001 1
(integer) 2
127.0.0.1:6379> HINCRBY MyBlog  202002 1
(integer) 1
127.0.0.1:6379> HINCRBY MyBlog  202002 1
(integer) 2

也經常被用在記錄商品的好評數量,差評數量上

Copy127.0.0.1:6379> HINCRBY pid:1  Good 1
(integer) 1
127.0.0.1:6379> HINCRBY pid:1  Good 1
(integer) 2
127.0.0.1:6379> HINCRBY pid:1  bad  1
(integer) 1

也可以實時記錄當天的線上的人數。

Copy//有人登陸
127.0.0.1:6379> HINCRBY MySite  20200310 1
(integer) 1
//有人登陸
127.0.0.1:6379> HINCRBY MySite  20200310 1
(integer) 2
//有人登出
127.0.0.1:6379> HINCRBY MySite  20200310 -1
(integer) 1

小結#

本篇文章我們總結了Redis 雜湊物件的內部實現、常用命令以及常用的一些場景,那麼大家在專案中對Redis雜湊物件的使用都有哪些場景呢,歡迎在評論區給我留言和分享,我會第一時間反饋!我們共同學習與進步!