02.Redis_資料型別
Redis_資料型別
目錄Redis支援5種資料型別:string(字串),hash(雜湊),list(列表),set(集合)及zset(sorted set:有序集合)以及HyperLogLog、Geo、Pub/Sub。
資料型別及應用場景
1)String
常用命令
a)set
- NX:當資料庫中key不存在時,可以將key-value新增資料庫
- XX:當資料庫中key存在時,可以將key-value新增資料庫,與NX引數互斥
- EX:key的超時秒數
- PX:key的超時毫秒數,與EX互斥
b)get
c)append
d)strlen
e)setnx
f)incr
- 將 key 中儲存的數字值增1,只能對數字值操作,如果為空,新增值為1
g)decr
- 將 key 中儲存的數字值減1,只能對數字值操作,如果為空,新增值為-1
h)incrby / decrby
- 自定義步長。
Redis 中的 String 不僅僅表示 字串,還可以表示 整型、浮點型。
String 的編碼可以是 int、raw 或者 embstr;單說普通的字串,就有 raw 和 embstr 兩種實現方式,embstr 是 Redis 3.0 新增的資料結構:
字串長度小於 39 位元組,就用 embstr 物件,否則用傳統的raw物件(Redis 3.2版本之後,這裡變成了以 44 位元組為分界)。
embstr 的優勢在於建立時少分配一次空間(RedisObject 和 sds 是連續的),刪除時少釋放一次空間,以及物件的所有資料連在一起,尋找方便;
當然缺點也非常明顯,如果字串的長度增加,需要重新分配記憶體的時候,整個 RedisObject 和 sds 都需要重新分配空間。
修改 embstr 物件的時候,Redis 會將其轉換成 raw 格式再進行修改,所以 embstr 物件修改之後的物件,一定是 raw 的。
應用場景:
1)快取功能。Redis 作為快取層,MySQL 作為儲存層,首先從 Redis 獲取資料,如果失敗就從 MySQL 獲取並將結果寫回 Redis 並新增過期時間。2)計數。Redis可以實現快速計數功能,例如視訊每播放一次就用 incy 把播放數加 1。3)共享Session。一個分散式 Web 服務將使用者的 Session 資訊儲存在各自伺服器,但會造成一個問題,出於負載均衡的考慮,分散式服務會將使用者的訪問負載到不同伺服器上,使用者重新整理一次可能會發現需要重新登陸。為解決該問題,可以使用 Redis 將使用者的 Session 進行集中管理,在這種模式下只要保證 Redis 是高可用和擴充套件性的,每次使用者更新或查詢登入資訊都直接從 Redis 集中獲取。4)限速。例如為了簡訊介面不被頻繁訪問會限制使用者每分鐘獲取驗證碼的次數或者網站限制一個 IP 地址不能在一秒內訪問超過 n次。可以使用鍵過期策略和自增計數實現。
2)Hash
常用方法:
設定值
hset key field value
,如果設定成功會返回 1,反之會返回 0,此外還提供了 hsetnx 命令,作用和 setnx 類似,只是作用於由鍵變為 field。
獲取值
hget key field
,如果不存在會返回 nil。
刪除 field
hdel key field [field...]
,會刪除一個或多個 field,返回結果為刪除成功 field 的個數。
計算 field 個數
hlen key
批量設定或獲取 field-value
hmget key field [field...]
hmset key field value [field value...]
判斷 field 是否存在
hexists key field
,存在返回 1,否則返回 0。
獲取所有的 field
hkeys key
,返回指定雜湊鍵的所有 field。
獲取所有 value
hvals key
,獲取指定鍵的所有 value。
獲取所有的 field-value
hgetall key
,獲取指定鍵的所有 field-value。
Hash 物件的底層實現可以是 ziplist 或者 hashtable。
ziplist:在這個資料結構中,是按照 key1, value1, key2, value2 這樣的順序存放來儲存的;
hashTable:是由 dict 這個結構來實現的。(這個結構比較複雜,後面單寫一篇來說)
Hash型別對應的資料結構是兩種:ziplist(壓縮列表),hashtable(雜湊表)。當field-value長度較短且個數較少時,使用ziplist,否則使用hashtable。
應用場景:快取使用者資訊,每個使用者屬性使用一對 field-value,但只用一個鍵儲存。
優點:簡單直觀,如果合理使用可以減少記憶體空間使用。
缺點:要控制雜湊在 ziplist 和 hashtable 兩種內部編碼的轉換,hashtable 會消耗更多記憶體。
3)List
常用命令
新增
從右邊插入元素:rpush key value [value...]
從左到右獲取列表的所有元素:lrange 0 -1
從左邊插入元素:lpush key value [value...]
向某個元素前或者後插入元素:linsert key before|after pivot value
,會在列表中找到等於 pivot 的元素,在其前或後插入一個新的元素 value。
查詢
獲取指定範圍內的元素列表:lrange key start end
,索引從左到右的範圍是 0~N-1,從右到左是 -1~-N,lrange 中的 end 包含了自身。
獲取列表指定索引下標的元素:lindex key index
,獲取最後一個元素可以使用 lindex key -1
。
獲取列表長度:llen key
刪除
從列表左側彈出元素:lpop key
從列表右側彈出元素:rpop key
刪除指定元素:lrem key count value
,如果 count 大於 0,從左到右刪除最多 count 個元素,如果 count 小於 0,從右到左刪除最多個 count 絕對值個元素,如果 count 等於 0,刪除所有。
按照索引範圍修剪列表:ltrim key start end
,只會保留 start ~ end 範圍的元素。
修改
修改指定索引下標的元素:lset key index newValue
。
阻塞操作
阻塞式彈出:blpop/brpop key [key...] timeout
,timeout 表示阻塞時間。
當列表為空時,如果 timeout = 0,客戶端會一直阻塞,如果在此期間添加了元素,客戶端會立即返回。
如果是多個鍵,那麼brpop會從左至右遍歷鍵,一旦有一個鍵能彈出元素,客戶端立即返回。
如果多個客戶端對同一個鍵執行 brpop,那麼最先執行該命令的客戶端可以獲取彈出的值。
-
ziplist 壓縮列表:跟雜湊的 zipilist 相同,元素個數和大小小於配置值(預設 512 個和 64 位元組)時使用。
-
linkedlist 連結串列:當列表型別無法滿足 ziplist 的條件時會使用linkedlist。
-
Redis 3.2 提供了 quicklist 內部編碼,它是以一個 ziplist 為節點的 linkedlist,它結合了兩者的優勢,為列表類提供了一種更為優秀的內部編碼實現。
應用場景:1)訊息佇列。Redis 的 lpush + brpop 即可實現阻塞佇列,生產者客戶端使用 lpush 從列表左側插入元素,多個消費者客戶端使用 brpop 命令阻塞式地搶列表尾部的元素,多個客戶端保證了消費的負載均衡和高可用性。2)文章列表。每個使用者有屬於自己的文章列表,現在需要分頁展示文章列表,就可以考慮使用列表。因為列表不但有序,同時支援按照索引範圍獲取元素。每篇文章使用雜湊結構儲存。lpush + lpop = 棧、lpush + rpop = 佇列、lpush + ltrim = 優先集合、lpush + brpop = 訊息佇列。
通常網站上的訊息列表,可以使用 List 來進行儲存;另外 lrange 命令,從某個元素開始,讀取多少個元素,可以看做是分頁查詢,比如很多網站上那種不斷下拉,不斷分頁的效果。
4)Set
常用方法
新增元素
sadd key element [element...]
,返回結果為新增成功的元素個數。
刪除元素
srem key element [element...]
,返回結果為成功刪除的元素個數。
計算元素個數
scard key
,時間複雜度為 O(1),會直接使用 Redis 內部的遍歷。
判斷元素是否在集合中
sismember key element
,如果存在返回 1,否則返回 0。
隨機從集合返回指定個數個元素
srandmember key [count]
,如果不指定 count 預設為 1。
從集合隨機彈出元素
spop key
,可以從集合中隨機彈出一個元素。
獲取所有元素
smembers key
求多個集合的交集/並集/差集
sinter key [key...]
sunion key [key...]
sdiff key [key...]
儲存交集、並集、差集的結果
sinterstore/sunionstore/sdiffstore destination key [key...]
集合間運算在元素較多情況下比較耗時,Redis 提供這三個指令將集合間交集、並集、差集的結果儲存在 destination key 中。
Set資料結構是dict字典,字典是用雜湊表實現的。
intset 整數集合:當集合中的元素個數小於配置值(預設 512 個時),使用 intset。
hashtable 雜湊表:當集合型別無法滿足 intset 條件時使用 hashtable。當某個元素不為整數時,也會使用 hashtable。
intset:是一個整數集合,支援三種長度的整數:int16_t、int32_t、int64_t;集合中的資料長度必須是一致的,比如一個 int16_t 長度的 Set,當插入了一條 int32_t 長度的資料,那麼所有的資料都會轉成 int32_t 長度(不支援降級)。
hashTable:對於 Set 來說,hashTable 的 value 永遠為 NULL。
應用場景:1)標籤。set 比較典型的使用場景是標籤,例如一個使用者可能與娛樂、體育比較感興趣,另一個使用者可能對歷史、新聞比較感興趣,這些興趣點就是標籤。這些資料對於使用者體驗以及增強使用者黏度比較重要。sadd = 標籤、spop/srandmember = 生成隨機數,比如抽獎、sadd + sinter = 社交需求。
如果要儲存一個列表,同時又需要做資料排重的時候,可以使用 set ;另外,Redis 還為 Set 提供了求交集、並集、差集等操作,比如微博上面的【共同關注】這個功能,就可以用 Set 實現。
5)ZSet / Sorted Set
常用方法
- zadd
…將一個或多個 member 元素及其 score 值加入到有序集 key 當中。 - zrange
[WITHSCORES] 返回有序集 key 中,下標在 之間的元素,帶WITHSCORES,可以讓分數一起和值返回到結果集。 - zrangebyscore key minmax [withscores] [limit offset count]返回有序集 key 中,所有 score 值介於 min 和 max 之間(包括等於 min 或 max)的成員。有序整合員按 score 值遞增(從小到大)次序排列。
- zrevrangebyscore key maxmin [withscores] [limit offset count] 同上,改為從大到小排列。
- zincrby
為元素的score加上增量 - zrem
刪除該集合下,指定值的元素 - zcount
統計該集合,分數區間內的元素個數 - zrank
返回該值在集合中的排名,從0開始。
和 Set 相比,ZSet 增加了一個引數 score,集合中的元素按照 score 進行有序排列。
有序集合的編碼可能兩種,一種是 ziplist,另一種是 skipList 與 hashTable 的結合。
ziplist:和 Hash 類似,元素 和 score 都是按順序存放的;比較適合用於元素內容不大的場景。
skipList + hashTable:是一種新增,移除,更新元素等操作更高效的資料結構,這個跳躍表的資料結構,我近期會發一篇文章單獨介紹。
應用場景:有序集合的典型使用場景就是排行榜系統,例如使用者上傳了一個視訊並獲得了贊,可以使用 zadd 和 zincrby。如果需要將使用者從榜單刪除,可以使用 zrem。如果要展示獲取贊數最多的十個使用者,可以使用 zrange。
6)Bitmaps
常用方法:
a)setbit
b)getbit
c)bitcount
d)bitop and(or/not/xor)
使用場景:使用者周活躍、統計活躍使用者、使用者線上狀態、使用者簽到
7)HyperLogLog
常用方法:
a) PFADD key element [element ...]
b)PFCOUNT key [key ...]
c)PFMERGE destkey sourcekey [sourcekey ...]
使用場景:統計APP或網頁的一個頁面,每天有多少使用者點選進入的次數。同一個使用者的反覆點選進入記為 1 次。
8)Geospatial
常用方法:
a) geoadd
b)geopos
c)geodist
d) georadius
e) georadiusbymember:根據儲存在位置集合裡面的某個地點獲取指定範圍內的地理位置集合。
f) geohash:返回一個或多個位置物件的 geohash 值。
應用場景:自如、蛋殼、鏈家、還有美團都有根據距離找房源或者商鋪的功能,都是用的空間索引。但是RedisGEO 適合精度不是很高的場景,微信附近的人用Redis GeoHash比較合適。但是滴滴打車精度高的場景一般用的是Google S2.
首先上傳房源和店鋪的時候,通過高德地圖可以獲取到目標物的經緯度,然後上傳到Redis中。查詢的時候根據自身所在位置的經緯度,然後加上範圍,就能查詢到附近的房源和店鋪列表名稱和經緯度,放到高德地圖中,就能完美展現出列表來。