學習筆記 | Redis的核心數據類型

Redis 有 8 種核心數據類型

  • string 字符串類型;
  • list 列表類型;
  • set 集合類型;
  • sorted set 有序集合類型;
  • hash 類型;
  • bitmap 位圖類型;
  • geo 地理位置類型;
  • HyperLogLog 基數統計類型。

string 字符串

  • string 是 Redis 的最基本數據類型。可以把它理解爲 Mc 中 key 對應的 value 類型。string 類型是二進制安全的,即 string 中可以包含任何數據。
  • Redis 中的普通 string 採用 raw encoding 即原始編碼方式,該編碼方式會動態擴容,並通過提前預分配冗餘空間,來減少內存頻繁分配的開銷。
  • 在字符串長度小於 1MB 時,按所需長度的 2 倍來分配,超過 1MB,則按照每次額外增加 1MB 的容量來預分配。
  • Redis 中的數字也存爲 string 類型,但編碼方式跟普通 string 不同,數字採用整型編碼,字符串內容直接設爲整數值的二進制字節序列。
  • 在存儲普通字符串,序列化對象,以及計數器等場景時,都可以使用 Redis 的字符串類型,字符串數據類型對應使用的指令包括 set、get、mset、incr、decr 等。

list 列表

  • Redis 的 list 列表,是一個快速雙向鏈表,存儲了一系列的 string 類型的字串值。list 中的元素按照插入順序排列。插入元素的方式,可以通過 lpush 將一個或多個元素插入到列表的頭部,也可以通過 rpush 將一個或多個元素插入到隊列尾部,還可以通過 lset、linsert 將元素插入到指定位置或指定元素的前後。

  • list 列表的獲取,可以通過 lpop、rpop 從對頭或隊尾彈出元素,如果隊列爲空,則返回 nil。還可以通過 Blpop、Brpop 從隊頭/隊尾阻塞式彈出元素,如果 list 列表爲空,沒有元素可供彈出,則持續阻塞,直到有其他 client 插入新的元素。這裏阻塞彈出元素,可以設置過期時間,避免無限期等待。最後,list 列表還可以通過 LrangeR 獲取隊列內指定範圍內的所有元素。Redis 中,list 列表的偏移位置都是基於 0 的下標,即列表第一個元素的下標是 0,第二個是 1。偏移量也可以是負數,倒數第一個是 -1,倒數第二個是 -2,依次類推。
    在這裏插入圖片描述

  • list 列表,對於常規的 pop、push 元素,性能很高,時間複雜度爲 O(1),因爲是列表直接追加或彈出。但對於通過隨機插入、隨機刪除,以及隨機範圍獲取,需要輪詢列表確定位置,性能就比較低下了。

  • feed timeline 存儲時,由於 feed id 一般是遞增的,可以直接存爲 list,用戶發表新 feed,就直接追加到隊尾。另外消息隊列、熱門 feed 等業務場景,都可以使用 list 數據結構。

  • 操作 list 列表時,可以用 lpush、lpop、rpush、rpop、lrange 來進行常規的隊列進出及範圍獲取操作,在某些特殊場景下,也可以用 lset、linsert 進行隨機插入操作,用 lrem 進行指定元素刪除操作;最後,在消息列表的消費時,還可以用 Blpop、Brpop 進行阻塞式獲取,從而在列表暫時沒有元素時,可以安靜的等待新元素的插入,而不需要額外持續的查詢。

set 集合

  • set 是 string 類型的無序集合,set 中的元素是唯一的,即 set 中不會出現重複的元素。Redis 中的集合一般是通過 dict 哈希表實現的,所以插入、刪除,以及查詢元素,可以根據元素 hash 值直接定位,時間複雜度爲 O(1)。
  • 對 set 類型數據的操作,除了常規的添加、刪除、查找元素外,還可以用以下指令對 set 進行操作。
  • sismember 指令判斷該 key 對應的 set 數據結構中,是否存在某個元素,如果存在返回 1,否則返回 0;
  • sdiff 指令來對多個 set 集合執行差集;
  • sinter 指令對多個集合執行交集;
  • sunion 指令對多個集合執行並集;
  • spop 指令彈出一個隨機元素;
  • srandmember 指令返回一個或多個隨機元素。

set 集合的特點是查找、插入、刪除特別高效,時間複雜度爲 O(1),所以在社交系統中,可以用於存儲關注的好友列表,用來判斷是否關注,還可以用來做好友推薦使用。另外,還可以利用 set 的唯一性,來對服務的來源業務、來源 IP 進行精確統計。

sorted set 有序集合

  • Redis 中的 sorted set 有序集合也稱爲 zset,有序集合同 set 集合類似,也是 string 類型元素的集合,且所有元素不允許重複。

  • 但有序集合中,每個元素都會關聯一個 double 類型的 score 分數值。有序集合通過這個 score 值進行由小到大的排序。有序集合中,元素不允許重複,但 score 分數值卻允許重複。

  • 有序集合除了常規的添加、刪除、查找元素外,還可以通過以下指令對 sorted set 進行操作。

  • zscan 指令:按順序獲取有序集合中的元素;

  • zscore 指令:獲取元素的 score 值;

  • zrange指令:通過指定 score 返回指定 score 範圍內的元素;

  • 在某個元素的 score 值發生變更時,還可以通過 zincrby 指令對該元素的 score 值進行加減。

  • 通過 zinterstore、zunionstore 指令對多個有序集合進行取交集和並集,然後將新的有序集合存到一個新的 key 中,如果有重複元素,重複元素的 score 進行相加,然後作爲新集合中該元素的 score 值。

sorted set 有序集合的特點是:

  • 所有元素按 score 排序,而且不重複;
  • 查找、插入、刪除非常高效,時間複雜度爲 O(1)。

因此,可以用有序集合來統計排行榜,實時刷新榜單,還可以用來記錄學生成績,從而輕鬆獲取某個成績範圍內的學生名單,還可以用來對系統統計增加權重值,從而在 dashboard 實時展示。

hash 哈希

  • Redis 中的哈希實際是 field 和 value 的一個映射表。

  • hash 數據結構的特點是在單個 key 對應的哈希結構內部,可以記錄多個鍵值對,即 field 和 value 對,value 可以是任何字符串。而且這些鍵值對查詢和修改很高效。

  • 所以可以用 hash 來存儲具有多個元素的複雜對象,然後分別修改或獲取這些元素。hash 結構中的一些重要指令,包括:hmset、hmget、hexists、hgetall、hincrby 等。

  • hmset 指令批量插入多個 field、value 映射;

  • hmget 指令獲取多個 field 對應的 value 值;

  • hexists 指令判斷某個 field 是否存在;

  • 如果 field 對應的 value 是整數,還可以用 hincrby 來對該 value 進行修改。

bitmap 位圖

  • Redis 中的 bitmap 位圖是一串連續的二進制數字,底層實際是基於 string 進行封裝存儲的,按 bit 位進行指令操作的。bitmap 中每一 bit 位所在的位置就是 offset 偏移,可以用 setbit、bitfield 對 bitmap 中每個 bit 進行置 0 或置 1 操作,也可以用 bitcount 來統計 bitmap 中的被置 1 的 bit 數,還可以用 bitop 來對多個 bitmap 進行求與、或、異或等操作。

在這裏插入圖片描述

  • bitmap 位圖的特點是按位設置、求與、求或等操作很高效,而且存儲成本非常低,用來存對象標籤屬性的話,一個 bit 即可存一個標籤。可以用 bitmap,存用戶最近 N 天的登錄情況,每天用 1 bit,登錄則置 1。個性推薦在社交應用中非常重要,可以對新聞、feed 設置一系列標籤,如軍事、娛樂、視頻、圖片、文字等,用 bitmap 來存儲這些標籤,在對應標籤 bit 位上置 1。對用戶,也可以採用類似方式,記錄用戶的多種屬性,並可以很方便的根據標籤來進行多維度統計。bitmap 位圖的重要指令包括:setbit、 getbit、bitcount、bitfield、 bitop、bitpos 等。

  • 在移動社交時代,LBS 應用越來越多,比如微信、陌陌中附近的人,美團、大衆點評中附近的美食、電影院,滴滴、優步中附近的專車等。要實現這些功能,就得使用地理位置信息進行搜索。地球的地理位置是使用二維的經緯度進行表示的,我們只要確定一個點的經緯度,就可以確認它在地球的位置。

  • Redis 在 3.2 版本之後增加了對 GEO 地理位置的處理功能。Redis 的 GEO 地理位置本質上是基於 sorted set 封裝實現的。在存儲分類 key 下的地理位置信息時,需要對該分類 key 構建一個 sorted set 作爲內部存儲結構,用於存儲一系列位置點。

  • 在存儲某個位置點時,首先利用 Geohash 算法,將該位置二維的經緯度,映射編碼成一維的 52 位整數值,將位置名稱、經緯度編碼 score 作爲鍵值對,存儲到分類 key 對應的 sorted set 中。

  • 需要計算某個位置點 A 附近的人時,首先以指定位置 A 爲中心點,以距離作爲半徑,算出 GEO 哈希 8 個方位的範圍, 然後依次輪詢方位範圍內的所有位置點,只要這些位置點到中心位置 A 的距離在要求距離範圍內,就是目標位置點。輪詢完所有範圍內的位置點後,重新排序即得到位置點 A 附近的所有目標。

  • 使用 geoadd,將位置名稱(如人、車輛、店名)與對應的地理位置信息添加到指定的位置分類 key 中;

  • 使用 geopos 方便地查詢某個名稱所在的位置信息;

  • 使用 georadius 獲取指定位置附近,不超過指定距離的所有元素;

  • 使用 geodist 來獲取指定的兩個位置之間的距離。

這樣,是不是就可以實現,找到附近的餐廳,算出當前位置到對應餐廳的距離,這樣的功能了?

Redis GEO 地理位置,利用 Geohash 將大量的二維經緯度轉一維的整數值,這樣可以方便的對地理位置進行查詢、距離測量、範圍搜索。但由於地理位置點非常多,一個地理分類 key 下可能會有大量元素,在 GEO 設計時,需要提前進行規劃,避免單 key 過度膨脹。

Redis 的 GEO 地理位置數據結構,應用場景很多,比如查詢某個地方的具體位置,查當前位置到目的地的距離,查附近的人、餐廳、電影院等。GEO 地理位置數據結構中,重要指令包括 geoadd、geopos、geodist、georadius、georadiusbymember 等。

hyperLogLog 基數統計

Redis 的 hyperLogLog 是用來做基數統計的數據類型,當輸入巨大數量的元素做統計時,只需要很小的內存即可完成。HyperLogLog 不保存元數據,只記錄待統計元素的估算數量,這個估算數量是一個帶有 0.81% 標準差的近似值,在大多數業務場景,對海量數據,不足 1% 的誤差是可以接受的。

  • Redis 的 HyperLogLog 在統計時,如果計數數量不大,採用稀疏矩陣存儲,隨着計數的增加,稀疏矩陣佔用的空間也會逐漸增加,當超過閥值後,則改爲稠密矩陣,稠密矩陣佔用的空間是固定的,約爲12KB字節。

  • 通過 hyperLoglog 數據類型,你可以利用 pfadd 向基數統計中增加新的元素,可以用 pfcount 獲得 hyperLogLog 結構中存儲的近似基數數量,還可以用 hypermerge 將多個 hyperLogLog 合併爲一個 hyperLogLog 結構,從而可以方便的獲取合併後的基數數量。

  • hyperLogLog 的特點是統計過程不記錄獨立元素,佔用內存非常少,非常適合統計海量數據。在大中型系統中,統計每日、每月的 UV 即獨立訪客數,或者統計海量用戶搜索的獨立詞條數,都可以用 hyperLogLog 數據類型來進行處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章