千萬級資料並行如何處理?進入學習
推薦學習:
Redis提供了一些資料結構供我們往Redis中存取資料,最常用的的有5種,字串(String)、雜湊(Hash)、列表(list)、集合(set)、有序集合(ZSET)。
字串型別是Redis最基礎的資料結構。首先鍵都是字串型別,而且其他幾種資料結構都是在字串型別基礎上構建的,所以字串型別能為其他四種資料結構的學習奠定基礎。字串型別的值實際可以是字串(簡單的字串、複雜的字串(例如JSON、XML))、數位(整數、浮點數),甚至是二進位制(圖片、音訊、視訊),但是值最大不能超過512MB。
(雖然Redis是C寫的,C裡面有字串<本質使用char陣列來實現>,但是處於種種考慮,Redis還是自己實現了字串型別)
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的分散式鎖。
如果要獲取的鍵不存在,則返回nil(空):
通過mset命令一次性設定4個鍵值對
批次獲取了鍵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秒(11+10000.1=101ms)。
incr命令用於對值做自增操作,返回結果分為三種情況:
值不是整數,返回錯誤。
值是整數,返回自增後的結果。
鍵不存在,按照值為0自增,返回結果為1。
除了incr命令,Redis提供了decr(自減)、 incrby(自增指定數位)、decrby(自減指定數位)、incrbyfloat(自增浮點數),具體效果請同學們自行嘗試。
append可以向字串尾部追加值
返回字串長度
注意:每個中文佔3個位元組
getset和set一樣會設定值,但是不同的是,它同時會返回鍵原來的值
下標從0開始計算。
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次也可以採用類似的思路。
Java裡提供了HashMap,Redis中也有類似的資料結構,就是雜湊型別。但是要注意,雜湊型別中的對映關係叫作field-value,注意這裡的value是指field對應的值,不是鍵對應的值。
基本上,雜湊的操作命令和字串的操作命令很類似,很多命令在字串型別的命令前面加上了h字母,代表是操作雜湊型別,同時還要指明要操作的field的值。
hset user:1 name lijin
如果設定成功會返回1,反之會返回0。此外Redis提供了hsetnx命令,它們的關係就像set和setnx命令一樣,只不過作用域由鍵變為field。
hget user:1 name
如果鍵或field不存在,會返回nil。
hdel會刪除一個或多個field,返回結果為成功刪除field的個數。
若存在返回1,不存在返回0
它返回指定雜湊鍵所有的field
在使用hgetall時,如果雜湊元素個數比較多,會存在阻塞Redis的可能。如果只需要獲取部分field,可以使用hmget,如果一定要獲取全部field-value,可以使用hscan命令,該命令會漸進式遍歷雜湊型別,hscan將在後面的章節介紹。
hincrby和 hincrbyfloat,就像incrby和incrbyfloat命令一樣,但是它們的作用域是filed。
雜湊型別的操作命令中,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)型別是用來儲存多個有序的字串,a、b、c、c、b四個元素從左到右組成了一個有序的列表,列表中的每個字串稱為元素(element),一個列表最多可以儲存(2^32-1)個元素(4294967295)。
在Redis 中,可以對列表兩端插入( push)和彈出(pop),還可以獲取指定範圍的元素列表、獲取指定索引下標的元素等。列表是一種比較靈活的資料結構,它可以充當棧和佇列的角色,在實際開發上有很多應用場景。
列表型別有兩個特點:
第一、列表中的元素是有序的,這就意味著可以通過索引下標獲取某個元素或者某個範圍內的元素列表。
第二、列表中的元素可以是重複的。
key start end
索引下標特點:從左到右為0到N-1
lrange 0 -1命令可以從左到右獲取列表的所有元素
這三個返回結果為命令完成後當前列表的長度,也就是列表中包含的元素個數,同時rpush和lpush都支援同時插入多個元素。
r
請注意,彈出來元素就沒了。
rpop將會把列表最右側的元素d彈出。
lrem命令會從列表中找到等於value的元素進行刪除,根據count的不同分為三種情況:
count>0,從左到右,刪除最多count個元素。
count<0,從右到左,刪除最多count絕對值個元素。
count=0,刪除所有。
返回值是實際刪除元素的個數。
例如想保留列表中第0個到第1個元素
ls
l
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)型別也是用來儲存多個的字串元素,但和列表型別不一樣的是,集合中不允許有重複元素,並且集合中的元素是無序的,不能通過索引下標獲取元素。
一個集合最多可以儲存2的32次方-1個元素。Redis除了支援集合內的增刪改查,同時還支援多個集合取交集、並集、差集,合理地使用好集合型別,能在實際開發中解決很多實際問題。
允許新增多個,返回結果為新增成功的元素個數
允許刪除多個,返回結果為成功刪除元素個數
如果給定元素element在集合內返回1,反之返回0
指定個數如果不寫預設為1
同樣可以指定個數,如果不寫預設為1,注意,既然是彈出,spop命令執行後,元素會從集合中刪除,而srandmember不會。
返回結果是無序的
現在有兩個集合,它們分別是set1和set2
sinterstore destination key [key ...]
suionstore destination key [key ...]
sdiffstore destination key [key ...]複製程式碼
登入後複製
集合間的運算在元素較多的情況下會比較耗時,所以 Redis提供了上面三個命令(原命令+store)將集合間交集、並集、差集的結果儲存在destination key中,例如:
集合型別比較典型的使用場景是標籤(tag)。例如一個使用者可能對娛樂、體育比較感興趣,另一個使用者可能對歷史、新聞比較感興趣,這些興趣點就是標籤。有了這些資料就可以得到喜歡同一個標籤的人,以及使用者的共同喜好的標籤,這些資料對於使用者體驗以及增強使用者黏度比較重要。
例如一個電子商務的網站會對不同標籤的使用者做不同型別的推薦,比如對數碼產品比較感興趣的人,在各個頁面或者通過郵件的形式給他們推薦最新的數碼產品,通常會為網站帶來更多的利益。
除此之外,集合還可以通過生成亂數進行比如抽獎活動,以及社交圖譜等等。
有序集合相對於雜湊、列表、集合來說會有一點點陌生,但既然叫有序集合,那麼它和集合必然有著聯絡,它保留了集合不能有重複成員的特性,但不同的是,有序集合中的元素可以排序。但是它和列表使用索引下標作為排序依據不同的是,它給每個元素設定一個分數( score)作為排序的依據。
有序集合中的元素不能重複,但是score可以重複,就和一個班裡的同學學號不能重複,但是考試成績可以相同。
有序集合提供了獲取指定分數和元素範圍查詢、計算成員排名等功能,合理的利用有序集合,能幫助我們在實際開發中解決很多問題。
返回結果代表成功新增成員的個數
要注意:
zadd命令還有四個選項nx、xx、ch、incr 四個選項
nx: member必須不存在,才可以設定成功,用於新增。
xx: member必須存在,才可以設定成功,用於更新。
ch: 返回此次操作後,有序集合元素和分數發生變化的個數
incr: 對score做增加,相當於後面介紹的zincrby
如果成員不存在則返回nil
zrank是從分數從低到高返回排名
zrevrank反之
很明顯,排名從0開始計算。
允許一次刪除多個成員。
返回結果為成功刪除的個數。
有序集合是按照分值排名的,zrange是從低到高返回,zrevrange反之。如果加上 withscores選項,同時會返回成員的分數
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 key min max
zremrangebyrank key start end
zremrangebyscore key min max
zinterstore
這個命令引數較多,下面分別進行說明
destination:交集計算結果儲存到這個鍵。
numkeys:需要做交集計算鍵的個數。
key [key ...]:需要做交集計算的鍵。
weights weight [weight ...]:每個鍵的權重,在做交集計算時,每個鍵中的每個member 會將自己分數乘以這個權重,每個鍵的權重預設是1。
aggregate sum/ min |max:計算成員交集後,分值可以按照sum(和)、min(最小值)、max(最大值)做彙總,預設值是sum。
不太好理解,我們用一個例子來說明。(算平均分)
該命令的所有引數和zinterstore是一致的,只不過是做並集計算,大家可以自行實驗。
有序集合比較典型的使用場景就是排行榜系統。例如視訊網站需要對使用者上傳的視訊做排行榜,榜單的維度可能是多個方面的:按照時間、按照播放數量、按照獲得的贊數。
持續創作,加速成長!這是我參與「掘金日新計劃 · 10 月更文挑戰」的第26天,點選檢視活動詳情
推薦學習:
以上就是Redis常用資料結構(整理分享)的詳細內容,更多請關注TW511.COM其它相關文章!