redis 五種資料型別和使用場景梳理!

若小寒發表於2019-03-23

Redis在我們日常工作中使用的非常頻繁,但是也有人只會使用string型別,那麼今天筆者梳理下redis中常用的5種資料型別,分別適用於哪些業務場景和基本操作,讓大家以後能夠在合適的快取場景使用合適的資料型別。

String字串型別

Redis支援的字串型別不是定長分配的字串,是動態變長字串,修改字串在沒有增加特別多內容的情況下不需要重新分配記憶體空間,內部結構實現上有點類似於java的ArrayList,採用預分配冗餘空間的方式來減少記憶體的頻繁分配。

常用使用場景

字串型別常用的場景有以下這些:

(1)快取結構體資訊:

將結構體json序列化成字串,然後將字串儲存在redis的value中,將結構體的業務唯一標示作為key;這種儲存json的用法用的最多的場景就是快取使用者資訊,將使用者bean資訊轉成json再序列化為字串作為value儲存在redis中,將使用者id作為key。從程式碼中獲取使用者快取資訊就是一個逆過程,根據userid作為key獲取到結構體json,然後將json轉成java bean。

基本操作:

127.0.0.1:6379> set user.10001 {“id”:”10001”,”name”:”monkey”}
(integer) 1
複製程式碼

(2)計數功能:

我們都知道redis是單執行緒模式,並且redis將很多常用的事務操作進行了封裝,這裡我們最常用的就是數值自增或自減,redis的作者封裝了incr可以進行自增,沒呼叫一次自增1,因為redis是單執行緒執行,所以就算client是多執行緒呼叫那麼也是正確自增,因為incr命令中將read和write做了事務封裝。同樣可以設定incr的step,每次根據step進行自增,當然如果要達到自減的效果,那麼只要將step設定為負數就可以了。

計數功能使用的場景很多,我們之前經常用在實時計數統計場景,也用在過庫存場景、限流計數場景等等,而且redis的效能也是非常高的,對於一般的併發量沒那麼高的系統都是適用的。

基本操作:

127.0.0.1:6379> set num 1
127.0.0.1:6379> incr num
(integer) 2
127.0.0.1:6379> incrby num 2
(integer) 4
複製程式碼

List列表型別

redis的列表的資料結構和Java中的LinkedList比較類似,所以List型別的前後插入和刪除速度是非常快的,但是隨機定位速度非常慢,時間複雜度是O(n)需要對列表進行遍歷。

常用使用場景

(1)list列表結構常用來做非同步佇列使用

將需要延後處理的任務結構體序列化成字串塞進 Redis 的列表,另一個執行緒從這個列表中輪詢資料進行處理。

(2)list可用於秒殺搶購場景

在商品秒殺場景最怕的就是商品超賣,為了解決超賣問題,我們經常會將庫存商品快取到類似MQ的佇列中,多執行緒的購買請求都是從佇列中取,取完了就賣完了,但是用MQ處理的化有點重,這裡就可以使用redis的list資料型別來實現,在秒殺前將本場秒殺的商品放到list中,因為list的pop操作是原子性的,所以即使有多個使用者同時請求,也是依次pop,list空了pop丟擲異常就代表商品賣完了。

基本操作:

//庫存為3瓶可樂
> rpush goods:cola cola cola cola
(integer) 3
> lpop goods:cola
"cola"
> lpop goods:cola
"cola"
複製程式碼

Hash資料型別

redis的hash相當於hashmap,內部實現上和hashmap一致,陣列+連結串列的資料結構。

redis 五種資料型別和使用場景梳理!
redis的hash資料型別只能是字串。它們 rehash 的方式不一樣,因為 Java 的 HashMap 在字典很大時,rehash 是個耗時的操作,需要一次性全部 rehash。Redis 為了高效能,不能堵塞服務,所以採用了漸進式 rehash 策略。漸進式 rehash 會在 rehash 的同時,保留新舊兩個 hash 結構,查詢時會同時查詢兩個 hash 結構,然後在後續的定時任務中以及 hash 操作指令中,循序漸進地將舊 hash 的內容一點點遷移到新的 hash 結構中。當搬遷完成了,就會使用新的hash結構取而代之。 當 hash 移除了最後一個元素之後,該資料結構自動被刪除,記憶體被回收。

常用使用場景

(1)儲存結構體資訊

hash字典型別也是比較適合儲存結構體資訊的,不同於字串一次序列化整個物件,hash可以對使用者結構中的每個欄位單獨儲存。這樣當我們需要獲取結構體資訊時可以進行部分獲取,而不用序列化所有欄位,而將整個字串儲存的結構體資訊只能一次性全部讀取。

基本操作:

127.0.0.1:6379> hset user.10002 name monkey
(integer) 1
127.0.0.1:6379> hget user.10002 name
"monkey"
127.0.0.1:6379> hgetall user.10002
1) "id"
2) "10002"
3) "name"
4) "monkey"
複製程式碼

Set集合型別

redis的set相當於java中的HashSet,內部的健值是無序唯一的,相當於一個hashmap,但是value都是null。set資料型別其實沒什麼好講的,使用場景也是比較單一的,就是用在一些去重的場景裡,例如每個使用者只能參與一次活動、一個使用者只能中獎一次等等去重場景。

基本操作

127.0.0.1:6379> sadd userset 10001
(integer) 1
127.0.0.1:6379> sadd userset 10002
(integer) 1
127.0.0.1:6379> sadd userset 10001
(integer) 0
127.0.0.1:6379> sadd userset 10003 10004
(integer) 2
127.0.0.1:6379> smembers userset
1) "10001"
2) "10002"
3) "10003"
4) "10004"
複製程式碼

Zset有序集合

它類似於 Java 的 SortedSet 和 HashMap 的結合體,一方面它是一個 set,保證了內部 value 的唯一性,另一方面它可以給每個 value 賦予一個 score,代表這個 value 的排序權重。zset內部是通過跳躍列表這種資料結構來實現的。因為zset要支援隨機的插入和刪除,所以不能使用陣列結構,而需要改成普通連結串列資料結構。zset需要根據score進行排序,所以每次插入或者刪除值都需要進行先在連結串列上查詢定位。

常用使用場景

(1)各類熱門排序場景

例如熱門歌曲榜單列表,value值是歌曲ID,score是播放次數,這樣就可以對歌曲列表按播放次數進行排序。

當然還有類似微博粉絲列表、評論列表等等,可以將value定義為使用者ID、評論ID,score定義為關注時間、評論點贊次數等等。

基本操作:

這裡的例子就是對使用者的評分進行排序。

127.0.0.1:6379> zadd userzset 100 10002
(integer) 1
127.0.0.1:6379> zadd userzset 98 10001
(integer) 1
127.0.0.1:6379> zrange userzset 0 100
1) "10001"
2) "10002"
複製程式碼

總結

本篇中介紹了那麼redis 5種常用資料結構的使用場景,具體的使用場景還需要根據這些型別的特性和自己的業務場景對號入座,本篇給大家拓寬下redis的使用場景!大家覺得不錯可以點個贊在關注下,以後還會分享更多文章!


相關文章