1. 程式人生 > 其它 >Redis專題(四) ——Redis排序、訊息佇列、優化儲存

Redis專題(四) ——Redis排序、訊息佇列、優化儲存

Redis專題(四)

——Redis排序、訊息佇列、優化儲存

(原創內容,轉載請註明來源,謝謝)

一、排序

1、命令

SORTkey [ALPHA] [DESC] [LIMIT start end],對列表、集合和有序集合進行排序,當加上alpha引數後,則可以按照字典順序排序,加上desc則倒序排序,加上limit則支援分頁。

2、關鍵引數

by引數:by key:*->val,可以指定排序的標準,可以自己傳入一個list,也可以指定某個列進行排序。

get引數:getkey:*->val,可以指定sort排序的返回結果,而不是將整個集合進行返回,要多個引數時採用多個get,另外get#會返回元素本身的鍵值。

store引數:store key2,可以將前面排序的結果儲存在另外一個key裡面。

3、效能問題

sort的時間複雜度O(n+mlogm),n是待排序的基數,m是排序後的值。另外redis會在排序前用一個空間為n的容器進行儲存排序期間的臨時資料。

因此,需要注意幾個問題:

1)儘可能減少待排序的集合數量,以減少n

2)如果不需要全部結果,則用limit,以減少m

3)如果要排序的結果大,則用store進行儲存。

二、訊息佇列

redis訊息佇列可以分為兩類,生產者和消費者,當生產者產生的資料會放入訊息佇列中,消費者監測到訊息佇列內有資料的時候,可以進行後續的處理。

1、命令

redis提供一個命令叫BRPOP,與RPOP的區別在於,當使用命令對key進行操作時,如果key沒有值,則會阻塞等待,直到等到有值後取出進行操作。另外,和brpop相似的,也有BLPOP命令。

2、優先順序

由於brpop命令可以支援多個鍵,並且當每個鍵都有未處理的資料時,會從最左邊的鍵開始處理。例如有兩個郵件提醒業務,一個是開通賬號的驗證,一個是新訊息提醒。則如果太多的不採用優先順序,新訊息提醒的業務會讓開通賬號的業務阻塞。因為開通賬號的時效性要求更高,因此需要將其放在左邊。

3、釋出訂閱模式

釋出訂閱模式有特殊的命令,釋出的命令是PUBLISH channel message,訂閱的命令是SUBSCRIBEchannel message,不過由於redis的釋出命令不會對訊息進行持久化,即後面訂閱的無法檢視到釋出者之前釋出的訊息。

subscribe命令後,會讓客戶端進入訂閱狀態,此後只能輸入四種命令:subscribe、unsubscribe、psubscribe、punsubscribe,其他命令會報錯。

處於訂閱狀態後,客戶端會收到3種類型的回覆,每個回覆有三個值,第一個值是回覆的型別,根據型別不同,二三兩個值也不同。訊息型別如下:

1)subscribe 表示訂閱成功的反饋,此時第二個返回值是訂閱的頻道名稱,第三個值是當前客戶端訂閱的頻道數量。

2)message 表示收到的訂閱訊息,也是此模式的核心,其第二個值是頻道的名稱,第三個值是訊息的內容。

3)unsubscribe 表示成功取消訂閱某個頻道,第二個值是取消的頻道名稱,第三個是剩餘的訂閱頻道數量,如果是0,則此時會取消訂閱模式,後面就可以繼續輸入其他非訂閱的命令。

4、批量訂閱模式

命令psubscribe,支援blob模式,即類似正則的模式,如psubscribechannel.*,則訂閱所有channel開頭的頻道。

與此相應的,punsubscribe命令支援批量取消訂閱。

三、管道

redis和客戶端是用tcp進行的連線,因此來回傳送訊息都要經過網路,來回的總耗時稱為訊息時延。當執行多個命令時,每條命令需要執行完畢有返回的時候,下一條才會執行。

當需要一起執行時,redis底層的通訊對管道提供了支援,當一組命令中每條命令都不依賴於前一條時,可以一起傳送請求,一起返回,以減少網路通訊的次數。

四、空間消耗

1、複雜度

redis為每種資料型別都提供兩種編碼方式,例如hash,當元素很多的時候會使用散列表的方式進行儲存,時間複雜度僅O(1);但是當元素很少時,O(n)和O(1)差距不大,為了節約記憶體,redis會採用內部編碼方法,用時間換空間。

redis可以使用OBJECTENCODING key的方式,檢視每個鍵的內部編碼型別。

2、編碼

redis在內部編碼採用結構體型別,如下:

         typedefstruct redisObject{
         unsigned type:4;
         unsigned notuse:2;
         unsigned encoding:4;
         unsigned lru:22;
         int refcount;
         void *ptr;
}

type代表型別,用數字0-4表示五種型別;notuse是預留空間,未使用;ptr指標指向具體儲存的資料;encoding有9種,0-8,包括原生編碼、整型、雜湊表、zipmap、雙向連結串列、ziplist、skiplist、字串。針對redis的五種資料型別,分別有不同的encoding方式,如下圖所示:(來自網路)

3、字串優化

字串儲存在一個結構體,包括字串長度、具體內容、剩餘空間。當執行set命令,要佔用30位元組,而當鍵值是64位的整數,則ptr指標會直接指向值,而不是指向結構體,可以節約到16位元組。

當儲存的是0-9999時,redis由於會預設儲存這些數字,則ptr指標直接指向引用,佔用0位元組的空間。

4、雜湊優化

在配置檔案中設定hash-max-ziplist-entries和hash-max-ziplist-value,當雜湊的鍵的個數少於entiries值,且每個鍵值都小於value值,則會使用ziplist的方式編碼,否則用雜湊表來編碼。ziplist犧牲時間換空間,雜湊表犧牲空間換時間,因此資料少用ziplist,多的時候用雜湊表。

因此,兩個引數不宜設定的太大。

5、列表優化

列表和雜湊相似,有list-max-ziplist-entries和list-max-ziplist-value來配置。編碼方式包括ziplist、雙向連結串列、quicklist,quicklist結合ziplist和雙向連結串列的有點,達到減少空間的同時適當減少時間。

6、集合優化

配置檔案配置set-max-intset-entries,小於時採用intset編碼,否則用雜湊表。intset使得集合內部有序排列,便於用二分法進行查詢,但是新增和刪除則需要進行排序,元素多的時候速度慢。

7、有序集合優化

配置檔案配置zset-max-ziplist-entries和zset-max-ziplist-value。包括ziplist和skiplist編碼方式,skiplist是使用雜湊表和跳躍列表兩種結構來儲存,雜湊表用來儲存分數的對映,跳躍列表用來儲存分數和元素值的對映。

——written by linhxx 2017.08.06