緩存神器Redis的五種數據類型及使用

         Redis作爲Nosql的代表,想必大家已經再熟悉不過了,除了作爲緩存來使用,Redis還提供了其他很多有用的功能,例如可作爲消息隊列、分佈式鎖、不隆過濾器、限流等功能使用。今天先來說一說redis作爲緩存使用,提供了5 種基礎數據結構,分別爲:string (字符串)、list (列表)、set (集合)、hash (哈 希) 和 zset (有序集合)。

一、string (字符串)

字符串 string 是 Redis 最簡單的數據結構。Redis 所有的數據結構都是以唯一的 key 字符串作爲名稱,然後通過這個唯一key值來獲取相應的 value 數據。不同類型的數據結構的差異就在於value 的結構不一樣。字符串結構使用非常廣泛,一個常見的用途就是緩存用戶信息。我們將用戶信息結構體 使用 JSON 序列化成字符串,然後將序列化後的字符串塞進 Redis 來緩存。同樣,取用戶 信息會經過一次反序列化的過程。Redis 的字符串是動態字符串,是可以修改的字符串,內部結構實現上類似於 Java 的 ArrayList,採用預分配冗餘空間的方式來減少內存的頻繁分配,字符串最大長度爲 512M。使用命令如下:

設置鍵值對:set [key] [value]

獲取對應鍵的值:get [key]

批量操作鍵值對:mset [key] [value] [key] [value] [key] [value] ...

批量獲取對應鍵的值:mget [key] [key] [key]...

批量操作可以節省網絡耗時開銷。

可以對 key 設置過期時間,到點自動刪除,這個功能常用來控制緩存的失效時間。在保證緩存是熱點數據或者保證緩存和數據庫一致性的解決方案時,設置失效時間是必不可少的。還有就是整數的自增或者自減功能,如果 value 值是一個整數,可以對它進行自增操作。自增是有範圍的,它的範圍是signed long 的最大最小值,超過了這個值,Redis 會報錯。

設置過期可以用set+expire的組合,但是保證不了原子性,如果想保證原子性,就用setex命令:

關於自增和自減:

incr/decr:自增/自減 1

incrby/decrby [key] [num]:自增/自減 num

二、list (列表)

Redis 的列表相當於 Java 語言裏面的 LinkedList,注意它是鏈表而不是數組。鏈表由於有前後節點,特點是插入和刪除快,查詢慢;數組由於有索引,所以特點是查詢快,但是插入和刪除慢;這意味着 list 的插入和刪除操作非常快,時間複雜度爲 O(1),但是索引定位很慢,時間複雜度爲 O(n)。當列表彈出了最後一個元素之後,該數據結構自動被刪除,內存被回收。Redis 的列表結構常用來做異步隊列使用。將需要延後處理的任務結構體序列化成字符串塞進 Redis 的列表,另一個線程從這個列表中輪詢數據進行處理。

操作命令:

Lpush——先進後出,在列表頭部插入元素
Rpush——先進先出,在列表的尾部插入元素
Lrange——出棧,根據索引,獲取列表元素
Lpop——左邊出棧,獲取列表的第一個元素
Rpop——右邊出棧,獲取列表的最後一個元素
Lindex——根據索引,取出元素
Llen——鏈表長度,元素個數
Lrem——根據key,刪除n個value
Ltrim——根據索引,刪除指定元素
Lset——根據index,設置value
Linsert before——根據value,在之前插入值
Linsert after——根據value,在之後插入值
BLPOP/BRPOP key -- 移出並獲取列表的第一個元素, 如果列表沒有元素會阻塞列表直到等待超時或發現可彈出元素爲止
BRPOPLPUSH source destination timeout -- 從列表中彈出一個值,將彈出的元素插入到另外一個列表中並返回它; 如果列表沒有元素會阻塞列表直到等待超時或發現可彈出元素爲止。
LPUSHX -- 將一個值插入到已存在的列表頭部


命令lindex 相當於 Java 鏈表的 get(int index)方法,它需要對鏈表進行遍歷,性能隨着參數 index 增大而變差。如果再深入一點,你會發現 Redis 底層存儲的還不是一個簡單的linkedlist, 而是稱之爲快速鏈表 quicklist 的一個結構。首先在列表元素較少的情況下會使用一塊連續的內存存儲,這個結構是 ziplist,也即是壓縮列表。它將所有的元素緊挨着一起存儲,分配的是一塊連續的內存。當數據量比較多的時候纔會改成 quicklist。因爲普通的鏈表需要的附加指針空間太大,會比較浪費空間,而且會加重內存的碎片化。快速列表既滿足了快速的插入刪除性能,又不會出現太大的空間冗餘。

三、hash (字典)

Redis 的字典相當於 Java 語言裏面的 HashMap,它是無序字典。內部實現結構上同 Java 的 HashMap 也是一致的,同樣的數組 + 鏈表二維結構。第一維 hash 的數組位置碰撞時,就會將碰撞的元素使用鏈表串接起來。所以特點也是和Java中Map結構相似。不同的是,Redis 的字典的值只能是字符串,另外它們 rehash 的方式不一樣,因爲 Java 的 HashMap 在字典很大時,rehash 是個耗時的操作,需要一次性全部 rehash。Redis 爲了高性能,不能堵塞服務,所以採用了漸進式 rehash 策略。漸進式 rehash 會在 rehash 的同時,保留新舊兩個 hash 結構,查詢時會同時查詢兩個 hash 結構,然後在後續的定時任務中以及 hash 的子指令中,循序漸進地將舊 hash 的內容 一點點遷移到新的 hash 結構中。當 hash 移除了最後一個元素之後,該數據結構自動被刪除,內存被回收。

操作命令:

HSET key field value -- 將哈希表 key 中的字段 field 的值設爲 value 
HSETNX key field value -- 只有在字段 field 不存在時,設置哈希表字段的值。
HVALS key -- 獲取哈希表中所有值
HSCAN key cursor [MATCH pattern] [COUNT count] -- 迭代哈希表中的鍵值對。
HMSET key field1 value1 [field2 value2 ] -- 同時將多個 field-value (域-值)對設置到哈希表 key 中。
HMGET key field1 [field2] -- 獲取所有給定字段的值
HLEN key -- 獲取哈希表中字段的數量
HKEYS key -- 獲取所有哈希表中的字段
HINCRBYFLOAT key field increment -- 爲哈希表 key 中的指定字段的浮點數值加上增量 increment 
HINCRBY key field increment -- 爲哈希表 key 中的指定字段的整數值加上增量 increment 
HGETALL key -- 獲取在哈希表中指定 key 的所有字段和值
HGET key field -- 獲取存儲在哈希表中指定字段的值
HEXISTS key field -- 查看哈希表 key 中,指定的字段是否存在
HDEL key field1 [field2] -- 刪除一個或多個哈希表字段


四、set (集合)

Redis 的集合相當於 Java 語言裏面的 HashSet,它內部的鍵值對是無序的唯一的。它的內部實現相當於一個特殊的字典,字典中所有的 value 都是一個值 NULL,Java中的HashSet也是基於一個value爲null的HashMap。當集合中最後一個元素移除之後,數據結構自動刪除,內存被回收。 set 結構可以用來做有去重需求需要實現的功能,可以保證唯一性。

操作命令:

SADD key member1 [member2] -- 向集合添加一個或多個成員
SCARD key -- 獲取集合的成員數
SDIFF key1 [key2] -- 返回給定所有集合的差集
SDIFFSTORE destination key1 [key2] -- 返回給定所有集合的差集並存儲在 destination 中
SINTER key1 [key2] -- 返回給定所有集合的交集
SINTERSTORE destination key1 [key2] -- 返回給定所有集合的交集並存儲在 destination 中
SISMEMBER key member -- 判斷 member 元素是否是集合 key 的成員
SMEMBERS key -- 返回集合中的所有成員
SMOVE source destination member -- 將 member 元素從 source 集合移動到 destination 集合
SPOP key -- 移除並返回集合中的一個隨機元素
SRANDMEMBER key [count] -- 返回集合中一個或多個隨機數
SREM key member1 [member2] -- 移除集合中一個或多個成員
SUNION key1 [key2] -- 返回所有給定集合的並集
SUNIONSTORE destination key1 [key2] -- 所有給定集合的並集存儲在 destination 集合中
SSCAN key cursor [MATCH pattern] [COUNT count] -- 迭代集合中的元素


spop命令是隨機移除一個value,這一操作,剛好是baidu從bat中給移除去了,冥冥之中自有天意呀!不過baidu的技術還是最牛逼的!

五、zset (有序列表)

zset 是 Redis 提供的最爲特色的數據結構,它類似於 Java 的 SortedSet 和 HashMap 的結合體,一方面它是一個 set,保證了內部 value 的唯一性,另一方面它可以給每個 value 賦予一個 score,代表這個 value 的排序權重。它的內部實現用的是一種叫着“跳躍列表”的數據結構。當zset 中最後一個 value 被移除後,數據結構自動刪除,內存被回收。

操作命令:

ZADD key score1 member1 [score2 member2] -- 向有序集合添加一個或多個成員,或者更新已存在成員的分數
ZCARD key -- 獲取有序集合的成員數
ZCOUNT key min max -- 計算在有序集合中指定區間分數的成員數
ZINCRBY key increment member -- 有序集合中對指定成員的分數加上增量 increment
ZINTERSTORE destination numkeys key [key ...] -- 計算給定的一個或多個有序集的交集並將結果集存儲在新的有序集合 key 中
ZLEXCOUNT key min max -- 在有序集合中計算指定字典區間內成員數量
ZRANGE key start stop [WITHSCORES] -- 通過索引區間返回有序集合指定區間內的成員
ZRANGEBYLEX key min max [LIMIT offset count] -- 通過字典區間返回有序集合的成員
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT] -- 通過分數返回有序集合指定區間內的成員
ZRANK key member -- 返回有序集合中指定成員的索引
ZREM key member [member ...] -- 移除有序集合中的一個或多個成員
ZREMRANGEBYLEX key min max -- 移除有序集合中給定的字典區間的所有成員
ZREMRANGEBYRANK key start stop -- 移除有序集合中給定的排名區間的所有成員
ZREMRANGEBYSCORE key min max -- 移除有序集合中給定的分數區間的所有成員
ZREVRANGE key start stop [WITHSCORES] -- 返回有序集中指定區間內的成員,通過索引,分數從高到低
ZREVRANGEBYSCORE key max min [WITHSCORES] -- 返回有序集中指定分數區間內的成員,分數從高到低排序
ZREVRANK key member -- 返回有序集合中指定成員的排名,有序集成員按分數值遞減(從大到小)排序
ZSCORE key member -- 返回有序集中,成員的分數值
ZUNIONSTORE destination numkeys key [key ...] -- 計算給定的一個或多個有序集的並集,並存儲在新的 key 中
ZSCAN key cursor [MATCH pattern] [COUNT count] -- 迭代有序集合中的元素(包括元素成員和元素分值)

zset 內部的排序功能是通過"跳躍列表"數據結構來實現的,它的結構非常特殊,也比較複雜。因爲 zset 要支持隨機的插入和刪除,所以它不好使用數組來實現。

 

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