Redis簡單資料結構及適用場景記錄
Redis簡單資料結構及適用場景記錄
1、五種基礎資料結構
Redis 所有的資料結構都是以唯一的 key 字串作為名稱,然後通過這個唯一 key 值來獲取相應的 value 資料。不同型別的資料結構的差異就在於 value 的結構不一樣。
建議體驗線上操作redis,官網http://try.redis.io/
①String 字串
常見的用途就是快取使用者資訊,我們將使用者資訊結構體使用 JSON 序列化成字串,然後將序列化後的字串塞進 Redis 來快取。同樣,取使用者資訊會經過一次反序列化的過程。
Redis 的字串是動態字串,是可以修改的字串,內部結構實現上類似於 Java 的ArrayList,採用預分配冗餘空間的方式來減少記憶體的頻繁分配。
內部為當前字串實際分配的空間 capacity 一般要高於實際字串長度 len。當字串長度小於 1M 時, 擴容都是加倍現有的空間,如果超過 1M,擴容時一次只會多擴 1M 的空間。需要注意的是字串最大長度為 512M。
命令舉例(set key value,get key)
簡單設定,刪除,計數
set name helloOKget name"hello"exists name(integer) 1del name(integer) 1get name(nil)
合併操作
set name helloOKget name"hello"set name1 worldOKset name2 !OKmget name name1 name2
- "hello"
- "world"
- "!"
批量更新
mset name boy name1 girl name2 unknownOKmget name name1 name2
- "boy"
- "girl"
- "unknown"
過期和 set 命令擴充套件
get name"hello"expire name 2(integer) 1get name(nil)
setex等效於set +expire
setex name 5 wahahOKget name"wahah"get name(nil)
計數
set age 30
OK
incr age
(integer) 31
incrby age 10
(integer) 41
incrby age -10
(integer) 31
如果一個字串已經設定了過期時間,然後你呼叫了
set 方法修改了它,它的過期時間會消失。
②List (列表)
Redis 的列表相當於 Java 語言裡面的 LinkedList,注意它是連結串列而不是陣列。這意味著
list 的插入和刪除操作非常快,時間複雜度為 O(1),但是索引定位很慢,時間複雜度為O(n),這點讓人非常意外。
當列表彈出了最後一個元素之後,該資料結構自動被刪除,記憶體被回收。
Redis 的列表結構常用來做非同步佇列使用。將需要延後處理的任務結構體序列化成字串塞進 Redis 的列表,另一個執行緒從這個列表中輪詢資料進行處理。
key = books value=python java golang
lindex 相當於 Java 連結串列的get(int index)方法,它需要對連結串列進行遍歷,效能隨著引數
index 增大而變差。
ltrim 和字面上的含義不太一樣,個人覺得它叫 lretain(保留) 更合適一些,因為 ltrim 跟的兩個引數start_index 和end_index 定義了一個區間,在這個區間內的值,
ltrim 要保留,區間之外統統砍掉。
rpush books python java golang
(integer) 3
lindex books 1
"java"
lindex books 0
"python"
ltrim books 0 1
OK
lindex books 0
"python"
lindex books 1
"java"
lindex books 2
(nil)
lrange books 0 -1 # 獲取所有元素,O(n) 慎用 1)
"python"
③hash (字典)
Redis 的字典相當於 Java 語言裡面的 HashMap,它是無序字典。內部實現結構上同
Java 的 HashMap 也是一致的,同樣的陣列 + 連結串列二維結構。第一維 hash 的陣列位置碰撞時,就會將碰撞的元素使用連結串列串接起來。
不同的是,Redis 的字典的值只能是字串,另外它們 rehash 的方式不一樣,因為
Java 的 HashMap 在字典很大時,rehash 是個耗時的操作,需要一次性全部 rehash。Redis
為了高效能,不能堵塞服務,所以採用了漸進式 rehash 策略。
漸進式 rehash 會在 rehash 的同時,保留新舊兩個 hash 結構,查詢時會同時查詢兩個
hash 結構,然後在後續的定時任務中以及 hash 的子指令中,循序漸進地將舊 hash 的內容一點點遷移到新的 hash 結構中。
當 hash 移除了最後一個元素之後,該資料結構自動被刪除,記憶體被回收。
hash 結構也可以用來儲存使用者資訊,不同於字串一次性需要全部序列化整個物件,
hash 可以對使用者結構中的每個欄位單獨儲存。這樣當我們需要獲取使用者資訊時可以進行部分獲取。而以整個字串的形式去儲存使用者資訊的話就只能一次性全部讀取,這樣就會比較浪費網路流量。
hash 也有缺點,hash 結構的儲存消耗要高於單個字串,到底該使用 hash 還是字串,需要根據實際情況再三權衡。
hset bookss golang "concurrency in go"(integer) 1hset bookss java "think in java"(integer) 1hset bookss python "python cookbook"(integer) 1hgetall bookss
- "golang"
- "concurrency in go"
- "java"
- "think in java"
- "python"
- "python cookbook"
hlen books (integer) 3
hget books java "think in java"
hset books golang "learning go programming" # 因為是更新操作,所以返回 0 (integer) 0
hget books golang "learning go programming"
hmset books java "effective java" python "learning python" golang "modern golang programming" # 批量 set
OK
④set (集合)
Redis 的集合相當於 Java 語言裡面的 HashSet,它內部的鍵值對是無序的唯一的。它的內部實現相當於一個特殊的字典,字典中所有的 value 都是一個值NULL。
當集合中最後一個元素移除之後,資料結構自動刪除,記憶體被回收。 set 結構可以用來儲存活動中獎的使用者 ID,因為有去重功能,可以保證同一個使用者不會中獎兩次。
sadd books python
(integer) 1
sadd books python # 重複
(integer) 0
sadd books java golang
(integer) 2
smembers books # 注意順序,和插入的並不一致,因為 set 是無序的
- "java"
- "python"
- "golang"
sismember books java # 查詢某個 value 是否存在,相當於 contains(o)
(integer) 1
sismember books rust
(integer) 0
scard books # 獲取長度相當於 count()
(integer) 3
spop books # 彈出一個
"java"
⑤zset (有序列表)
zset 可能是 Redis 提供的最為特色的資料結構,它也是在面試中面試官最愛問的資料結構。它類似於 Java 的 SortedSet 和 HashMap 的結合體,一方面它是一個 set,保證了內部
value 的唯一性,另一方面它可以給每個 value 賦予一個 score,代表這個 value 的排序權重。它的內部實現用的是一種叫著「跳躍列表」的資料結構。
zset 中最後一個 value 被移除後,資料結構自動刪除,記憶體被回收。 zset 可以用來存粉絲列表,value 值是粉絲的使用者 ID,score 是關注時間。我們可以對粉絲列表按關注時間進行排序。
zset 還可以用來儲存學生的成績,value 值是學生的 ID,score 是他的考試成績。我們可以對成績按分數進行排序就可以得到他的名次。
zadd books 9.0 "think in java"
(integer) 1
zadd books 8.9 "java concurrency"
(integer) 1
zadd books 8.6 "java cookbook"
(integer) 1
zrange books 0 -1 # 按 score 排序列出,引數區間為排名範圍
- "java cookbook"
- "java concurrency"
- "think in java"
zrevrange books 0 -1 # 按 score 逆序列出,引數區間為排名範圍
- "think in java"
- "java concurrency"
- "java cookbook"
zcard books # 相 當 於 count()
(integer) 3
zscore books "java concurrency" # 獲取指定 value 的 score
"8.9000000000000004" # 內部 score 使用 double 型別進行儲存,所以存在小數點精度問題
zrank books "java concurrency" # 排名
(integer) 1
zrangebyscore books 0 8.91 # 根據分值區間遍歷 zset
- "java cookbook"
- "java concurrency"
zrangebyscore books -inf 8.91 withscores # 根據分值區間 (-∞, 8.91] 遍歷 zset,同時返回分值。inf 代表 infinite,無窮大的意思。
- "java cookbook"
- "8.5999999999999996"
- "javaconcurrency" 4) "8.9000000000000004"
zrem books "java concurrency" # 刪 除 value
(integer) 1
zrange books 0 -1
- "javacookbook"
- "think in java"
參考資料
--------------------Redis深度歷險:核心原理和應用實踐