這篇文章為大家帶來了關於Redis的相關知識,其中主要介紹了關於常用資料結構的相關內容,最常用的有五種,分別是字串、哈希、列表、集合以及有序集合,下面一起來看一下,希望對大家有幫助。
推薦學習:Redis影片教學
#Redis常用資料結構
Redis提供了一些資料結構供我們往Redis存取數據,最常用的的有5種,字串(String)、哈希(Hash)、列表(list)、集合(set)、有序集合(ZSET)。
字串(String)
字串類型是Redis最基礎的資料結構。首先鍵都是字串類型,而且其他幾種資料結構都是在字串類型基礎上建構的,所以字串類型能為其他四種資料結構的學習奠定基礎。字串類型的值實際上可以是字串(簡單的字串、複雜的字串(例如JSON、XML))、數字(整數、浮點數),甚至是二進位(圖片、音訊、視訊),但是值最大不能超過512MB。
(雖然Redis是C寫的,C裡面有字串,但是處於種種考慮,Redis還是自己實作了字串型別)
操作指令
set 設定值
set key value
set指令有幾個選項:
ex seconds: 為鍵設定秒級過期時間。
px milliseconds: 為鍵設定毫秒過期時間。
nx: 鍵必須不存在,才可以設定成功,用於新增(分散式鎖定常用)。
xx: 與nx相反,鍵必須存在,才可以設定成功,用於更新。
從執行效果來看,ex參數和expire指令基本上一樣。還有一個需要特別注意的地方是如果一個字串已經設定了過期時間,然後你呼叫了set 方法修改了它,它的過期時間會消失。
而nx和xx執行效果如下
除了set選項,Redis 也提供了setex和setnx兩個指令:
setex key
seconds value
setnx key value
setex和 setnx的作用和ex和nx選項是一樣的。也就是,setex為鍵設定秒級過期時間,setnx設定時鍵必須不存在,才可以設定成功。
setex範例:
setnx範例:
因為鍵foo-ex已存在,所以setnx失敗,回傳結果為0,鍵foo-ex2不存在,所以setnx成功,回傳結果為1。
有什麼應用場景嗎?以setnx指令為例子,由於Redis的單執行緒指令處理機制,如果有多個客戶端同時執行setnx key value,根據setnx的特性只有一個客戶端能設定成功,setnx可以作為分散式鎖定的一種實作方案。當然分散式鎖沒有不是只有一個指令就OK了,其中還有很多的東西要注意,我們後面會用單獨的章節來講述基於Redis的分散式鎖。
get 取得值
如果要取得的鍵不存在,則傳回nil(空):
mset 批次設定值
透過mset指令一次設定4個鍵值對
##mget 批次取得值
批次取得了鍵a、b、c、d的值:
如果有些鍵不存在,那麼它的值為nil (空),結果是依照傳入鍵的順序回傳。
批次操作指令可以有效提高效率,假如沒有mget這樣的指令,要執行n次get指令具體耗時如下:
n次get時間=n次網路時間n次指令時間
使用mget指令後,要執行n次get指令操作具體耗時如下:
n次get時間=1次網路時間n次指令時間
Redis可以支撐每秒數萬的讀寫操作,但這指的是Redis服務端的處理能力,對於客戶端來說,一次指令除了指令時間還是有網路時間,假設網路時間為1毫秒,指令時間為0.1毫秒(依照每秒處理1萬條指令算),那麼執行1000次get指令需要1.1秒(10001 10000.1=1100ms),1次mget指令的需要0.101秒(1 1 10000.1=101ms)。
Incr 數字運算
incr指令用於對值做自增運算,傳回結果分為三種情況:
值不是整數,返回錯誤。
值是整數,傳回自增後的結果。
鍵不存在,依值為0自增,傳回結果為1。
除了incr指令,Redis提供了decr(自減)、 incrby(自增指定數字)、decrby(自減指定數字)、incrbyfloat(自增浮點數),具體效果請同學自行嘗試。
append追加指令
append可以向字串尾部追加值
strlen 字串長度
傳回字串長度
注意:每個中文佔3個位元組
getset 設定並且傳回原值
getset和set一樣會設定值,但是不同的是,它同時會傳回鍵原來的值
setrange 設定指定位置的字元
下標從0開始計算。
getrange 截取字串
getrange 截取字串中的一部分,形成一個子字串,需要指明開始和結束的偏移量,截取的範圍是個閉區間。
指令的時間複雜度
#字串這些指令中,除了del 、mset、 mget支援多個鍵的批次操作,時間複雜度和鍵的個數相關,為O(n),getrange和字串長度相關,也是O(n),其餘的指令基本上都是O(1)的時間複雜度,在速度上還是非常快的。
使用場景
字串類型的使用場景很廣泛:
快取功能
##Redis作為快取層,MySQL作為儲存層,絕大部分請求的資料都是從Redis中取得。由於Redis具有支撐高並發的特性,所以快取通常能起到加速讀寫和降低後端壓力的作用。
計數
使用Redis 作為計數的基礎工具,它可以實現快速計數、查詢快取的功能,同時資料可以非同步落地到其他資料來源。
共享Session
一個分散式Web服務將使用者的Session資訊(例如使用者登入資訊)保存在各自伺服器中,這樣會造成一個問題,出於負載平衡的考慮,分散式服務會將用戶的存取權平衡到不同伺服器上,用戶刷新一次訪問可能會發現需要重新登錄,這個問題是用戶無法容忍的。
為了解決這個問題,可以使用Redis將用戶的Session進行集中管理,,在這種模式下只要保證Redis是高可用和擴展性的,每次用戶更新或者查詢登錄信息都直接從Redis中集中獲取。
限速
例如,許多應用程式出於安全的考慮,會在每次進行登入時,讓用戶輸入手機驗證碼,從而確定是否是用戶本人。但為了簡訊介面不被頻繁存取,會限制使用者每分鐘取得驗證碼的頻率,例如一分鐘不能超過5次。有些網站限制一個IP位址不能在一秒鐘之內方問超過n次也可以採取類似的思路。
哈希(Hash)
Java裡提供了HashMap,Redis中也有類似的資料結構,就是哈希類型。但要注意,哈希類型中的映射關係叫作field-value,注意這裡的value是指field對應的值,不是鍵對應的值。
操作指令
基本上,雜湊的操作指令和字串的操作指令很類似,很多指令在字串類型的指令前面加上了h字母,代表是操作哈希類型,同時也要指明要操作的field的值。
hset設值
hset user:1 name lijin
如果設定成功會回傳1,反之會回傳0。另外Redis提供了hsetnx指令,它們的關係就像set和setnx指令一樣,只不過作用域由鍵變成field。
hget取值
hget user:1 name
如果鍵或field不存在,會傳回nil。
hdel刪除field
hdel會刪除一個或多個field,傳回結果為成功刪除field的數量。
hlen計算field個數
#hmset批次設值
hmget批量取值
hexists判斷field是否存在
若存在回傳1,不存在返回0
hkeys取得所有field
它傳回指定雜湊鍵所有的field
##hvals取得所有value
hgetall取得所有field與value
#在使用hgetall時,如果雜湊元素個數比較多,會存在阻塞Redis的可能。如果只需要取得部分field,可以使用hmget,如果一定要取得全部field-value,可以使用hscan指令,該指令會漸進式遍歷哈希類型,hscan將在後面的章節介紹。
hincrby增加
hincrby和 hincrbyfloat,就像incrby和incrbyfloat指令一樣,但是它們的作用域是filed。
hstrlen 計算value的字串長度
#指令的時間複雜度
雜湊類型的操作指令中,hdel,hmget ,hmset的時間複雜度和指令所帶的field的個數相關O(k),hkeys,hgetall,hvals和儲存的field的總數相關,O(N)。其餘的指令時間複雜度都是O(1)。
使用場景
從前面的操作可以看出,String和Hash的操作非常類似,那為什麼要弄一個hash出來儲存。
雜湊類型比較適合存放物件類型的數據,我們可以比較下,如果資料庫中表記錄user為:
##id
#name |
age |
|
1
lijin |
18 |
|
2
msb |
20 |
|
#1、使用String類型
需要一條條去插入取得。
set user:1:name lijin;
set user:1:age 18;
set user:2:name msb;
set user :2:age 20;
優點:簡單直觀,每個鍵對應一個值
缺點:鍵數過多,佔用記憶體多,用戶資訊過於分散,不用於生產環境
2、將物件序列化存入redis
set user:1 serialize(userInfo);
優點:程式設計簡單,若使用序列化合理記憶體使用率高
#缺點:序列化與反序列化有一定開銷,更新屬性時需要把userInfo全取出來進行反序列化,更新後再序列化到redis
3、使用hash類型
hmset user:1 name lijin age 18
hmset user:2 name msb age 20
優點:簡單直觀,使用合理可減少記憶體空間消耗
## 缺點:要控制內部編碼格式,不恰當的格式會消耗更多記憶體
#列表(list)列表( list)類型是用來儲存多個有序的字串,a 、b、c、c、b四個元素從左到右組成了一個有序的列表,列表中的每個字串稱為元素(element),一個列表最多可以儲存(2^32-1)個元素(4294967295)。
在Redis 中,可以對清單兩端插入( push)和彈出(pop),還可以取得指定範圍的元素清單、取得指定索引下標的元素等。列表是一種比較靈活的資料結構,它可以充當堆疊和佇列的角色,在實際開發上有許多應用場景。
列表類型有兩個特點:
第一、列表中的元素是有順序的,這意味著可以透過索引下標來取得某個元素或某個範圍內的元素清單。 第二、列表中的元素可以是重複的。 操作指令lrange 取得指定範圍內的元素清單(不會刪除元素)key start end索引下標特徵:從左到右為0到N-1lrange 0 -1指令可以從左到右取得清單的所有元素rpush 向右插入
lpush 向左插入
#linsert 在某個元素前後插入新元素
#這三個回傳結果為指令完成後目前清單的長度,也就是列表中包含的元素個數,同時rpush和lpush都支援同時插入多個元素。 lpop 從清單左側彈出(會刪除元素)
r
#請注意,彈出來元素就沒了。 rpop 從清單右側彈出rpop將會把清單最右邊的元素d彈出。
lrem 對指定元素進行刪除
#lrem指令會從清單中找到等於value的元素進行刪除,依count的不同分為三種情況:count>0,從左到右,刪除最多count個元素。 countcount=0,刪除所有。
傳回值是實際刪除元素的個數。
ltirm 依照索引範圍修剪清單
例如想保留清單中第0個到第1個元素
ls
#lset修改指定索引下標的元素
lindex 取得清單指定索引下標的元素
l
llen 取得清單長度
#blpop和brpop阻塞式彈出元素
blpop和brpop是lpop和rpop的阻塞版本,除此之外還支援多個清單類型,也支援設定阻塞時間,單位秒,如果阻塞時間為0,表示一直阻塞下去。我們以brpop為例說明。
A客戶端阻塞了(因為沒有元素就會阻塞)
A客戶端一直處於阻塞狀態。此時我們從另一個客戶端B執行
A客戶端則輸出
注意:brpop後面如果是多個鍵,那麼brpop會從左到右遍歷鍵,一旦有一個鍵能彈出元素,客戶端立即返回。
使用場景
列表類型可以用於例如:
訊息佇列,Redis 的lpush brpop指令組合即可實現阻塞佇列,生產者客戶端使用lrpush從列表左側插入元素,多個消費者客戶端使用brpop命令阻塞式的“搶”列表尾部的元素,多個客戶端保證了消費的負載平衡和高可用性。
文章列表
每個使用者都有屬於自己的文章列表,現需要分頁展示文章列表。此時可以考慮使用列表,因為列表不但是有序的,同時支援按照索引範圍獲取元素。
實作其他資料結構
lpush lpop =Stack(堆疊)
lpush rpop =Queue(佇列)
lpsh ltrim =Capped Collection(有限集合)
lpush brpop=Message Queue(訊息佇列)
集合(set)
集合( set)型別也是用來保存多個的字串元素,但和列表類型不一樣的是,集合中不允許有重複元素,並且集合中的元素是無序的,不能透過索引下標取得元素。
一個集合最多可以儲存2的32次方-1個元素。 Redis除了支援集合內的增刪改查,同時也支援多個集合取交集、並集、差集,合理地使用好集合類型,能在實際開發中解決許多實際問題。
集合內操作指令
sadd 新增元素
允許新增多個,回傳結果為新增成功的元素個數
srem 刪除元素
允許刪除多個,回傳結果為成功刪除元素個數
scard 計算元素個數
sismember 判斷元素是否在集合中
如果給定元素element在集合內回傳1,反之回傳0
####################### ###srandmember 隨機從集合傳回指定個數元素######指定個數如果不寫預設為1############spop 從集合隨機彈出元素
同樣可以指定個數,如果不寫預設為1,注意,既然是彈出,spop指令執行後,元素會從集合中刪除,而srandmember不會。
smembers 取得所有元素(不會彈出元素)
#回傳結果是無序的
##集合間運算指令現在有兩個集合,它們分別是set1和set2
sinter 求多個集合的交集
suinon 求多個集合的並集
#sdiff 求多個集合的差集
將交集、並集、差集的結果保存sinterstore destination key [key ...]
suionstore destination key [key ...]
sdiffstore destination key [key ...]复制代码
登入後複製
集合間的運算在元素較多的情況下會比較耗時,所以Redis提供了上面三個指令(原始指令store)將集合間交集、並集、差集的結果保存在destination key中,例如:
使用情境集合類型比較典型的使用場景是標籤(tag)。例如一個使用者可能對娛樂、體育比較有興趣,另一個使用者可能對歷史、新聞比較有興趣,這些興趣點就是標籤。有了這些數據就可以得到喜歡同一個標籤的人,以及用戶的共同喜好的標籤,這些數據對於用戶體驗以及增強用戶粘度比較重要。 例如一個電子商務的網站會對不同標籤的使用者做不同類型的推薦,例如對數位產品比較感興趣的人,在各個頁面或透過郵件的形式給他們推薦最新的數位產品,通常會為網站帶來更多的利益。 除此之外,集合還可以透過產生隨機數字來進行例如抽獎活動,以及社交圖譜等等。 有序集合(ZSET)
有序集合相對於雜湊、列表、集合來說會有一點點陌生,但既然叫有序集合,那麼它和集合必然有著聯繫,它保留了集合不能有重複成員的特性,但不同的是,有序集合中的元素可以排序。但是它和列表使用索引下標作為排序依據不同的是,它給每個元素設置一個分數( score)作為排序的依據。 有序集合中的元素不能重複,但是score可以重複,就和一個班級裡的同學學號不能重複,但是考試成績可以相同。 有序集合提供了獲取指定分數和元素範圍查詢、計算成員排名等功能,合理的利用有序集合,能幫助我們在實際開發中解決很多問題。 集合內操作指令zadd新增成員
#傳回結果代表成功新增成員的數量#要注意:
zadd指令還有四個選項nx、xx、ch、incr 四個選項nx: member必須不存在,才可以設定成功,用於添加。 xx: member必須存在,才可以設定成功,用於更新。 ch: 回傳此次運算後,有序集合元素和分數發生變化的個數incr: 對score做增加,相當於後面介紹的zincrby zcard 計算成員數量
zscore 計算某個成員的分數
如果成員不存在則回傳nilzrank計算成員的排名
#
zrank是从分数从低到高返回排名
zrevrank反之
很明显,排名从0开始计算。
zrem 删除成员
允许一次删除多个成员。
返回结果为成功删除的个数。
zincrby 增加成员的分数
zrange和zrevrange返回指定排名范围的成员
有序集合是按照分值排名的,zrange是从低到高返回,zrevrange反之。如果加上
withscores选项,同时会返回成员的分数
zrangebyscore返回指定分数范围的成员
zrangebyscore key min max [withscores] [limit offset count]
zrevrangebyscore key max min [withscores][limit offset count]复制代码
登入後複製
其中zrangebyscore按照分数从低到高返回,zrevrangebyscore反之。例如下面操作从低到高返回200到221分的成员,withscores选项会同时返回每个成员的分数。
同时min和max还支持开区间(小括号)和闭区间(中括号),-inf和+inf分别代表无限小和无限大:
zcount 返回指定分数范围成员个数
zcount key min max
zremrangebyrank 按升序删除指定排名内的元素
zremrangebyrank key start end
zremrangebyscore 删除指定分数范围的成员
zremrangebyscore key min max
集合间操作命令
zinterstore 交集
zinterstore
这个命令参数较多,下面分别进行说明
destination:交集计算结果保存到这个键。
numkeys:需要做交集计算键的个数。
key [key ...]:需要做交集计算的键。
weights weight
[weight ...]:每个键的权重,在做交集计算时,每个键中的每个member 会将自己分数乘以这个权重,每个键的权重默认是1。
aggregate sum/
min |max:计算成员交集后,分值可以按照sum(和)、min(最小值)、max(最大值)做汇总,默认值是sum。
不太好理解,我们用一个例子来说明。(算平均分)
zunionstore 并集
该命令的所有参数和zinterstore是一致的,只不过是做并集计算,大家可以自行实验。
使用场景
有序集合比较典型的使用场景就是排行榜系统。例如视频网站需要对用户上传的视频做排行榜,榜单的维度可能是多个方面的:按照时间、按照播放数量、按照获得的赞数。
持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第26天,点击查看活动详情
推荐学习:Redis视频教程
以上是Redis常用資料結構(整理分享)的詳細內容。更多資訊請關注PHP中文網其他相關文章!