Redis高階高階(二)

2022-08-02 13:42:10 字數 3899 閱讀 5382

一、訊息通知

在一些**上,經常會有一些發布/訂閱或者郵件訂閱的功能,尤其一些部落格上。其實這種問題很常見,當頁面需要進行如傳送郵件、複雜的計算時會阻塞頁面的渲染。為了避免使用者等待太久,應該使用其他程序單獨完成此類操作,這裡郵件訂閱可以用任務佇列來實現,具體來說,當需要傳送郵件時,將其存入佇列中,另外乙個程序監視該佇列,一旦發現就讀取資訊進行傳送郵件。

1、使用redis實現任務佇列

在redis中我們很容易想到使用列表來實現佇列是最好不過的了,這時生產者通過lpush往列表中新增郵件資訊,另外消費者通過rpop進行讀取郵件資訊進而傳送郵件。

實現的偽**如下:

#無限迴圈

loop

$task = rpop queue

if $task

execute($task)

else

wait 1 second

以上就簡單的實現了乙個任務佇列,這裡有點不足的地方就是:如果任務列表中沒有通知任務,這時還是通過每秒執行rpop進行檢查,如果能實現一旦有新任務就通知消費者來讀取就最好不過了,brpop命令就可以很好的實現該需求,brpop和rpop命令類似,唯一區別在於brpop會在列表中沒有元素時一直阻塞連線,直到有新元素加入,以上的**可以修改為:

loop

$task = brpop queue,0

execute($task)

brpop語法:brpop key[key...] timeout

接受兩個引數,第乙個是key,可以有多個。第二個引數是超時(秒),超過這個時間後會返回nil。當設定為0表示沒有時間限制,如果沒有新元素加入就一直阻塞。

為了測試brpop命令,我們開啟兩個session:

session a:

127.0.0.1:6379> brpop queue 0   #一直監視queue內的元素情況,一旦session b中加入乙個元素後立馬輸出下面的資訊

1) "queue"

2) "10"

(27.40s)

session b:

127.0.0.1:6379> lpush queue 10

(integer) 1

這時再檢視queue列表中的情況:

127.0.0.1:6379> lrange queue 0 -1    #已經被取走

(empty list or set)

2、優先順序佇列

假設某個部落格有10000個郵件訂閱者,那麼當發布一篇新文章需要向任務佇列中新增10000個任務,如果發乙個郵件需要10秒,全部完成這些任務需要30個小時。問題來了,如果這時有個新的訂閱者,需要傳送確認郵件,它根本就不知道前面排了10000個任務呢,那麼他不得不等30個小時完成確認,多麼糟糕的使用者體驗!而另一方面傳送文章通知郵件並不是緊急的,有時晚一天也可以接受的,所以可以得出結論,當二者同時出現時,應該優先執行確認郵件的任務,為了實現這個需求,我們必須完成乙個優先順序佇列。

幸福的是brpop命令是可以實現的,由於brpop可以接受多個key,如brpop queue1 queue2 0,意思是同時監控多個key,一旦有哪個鍵有新元素加入就彈出,如果多個鍵都有新元素加入,那麼會按照從左到右的順序取第乙個鍵中的元素。下面進行測試:

127.0.0.1:6379> lpush queue1 10

(integer) 1

127.0.0.1:6379> lpush queue2 20

(integer) 1

127.0.0.1:6379> lpush quequ3 30

(integer) 1

127.0.0.1:6379> lpush queue1 11

(integer) 2

127.0.0.1:6379> lpush queue1 12

(integer) 3

127.0.0.1:6379> brpop queue1 queue2 queue3 0

1) "queue1"

2) "10"

127.0.0.1:6379> brpop queue1 queue2 queue3 0

1) "queue1"

2) "11"

127.0.0.1:6379> brpop queue1 queue2 queue3 0 #到這裡完全是按從左到右的順序,將第乙個key中元素全部取完才輪到下乙個key

1) "queue1"

2) "12"

127.0.0.1:6379> brpop queue1 queue2 queue3 0

1) "que

通過以上的特性,我們可以建立兩個佇列:分別是queue.confirm.email和queue.notify.email,下面是偽**:

loop  

$task = brpop queue.confirm.email queue.notify.email 0

execute($task[1])

3、發布/訂閱模式

除了實現佇列外,redis還提供一組命令可以讓開發者實現發布/訂閱模式。發布/訂閱模式同樣可以實現程序間資訊通訊。它的原理是這樣的:

發布/訂閱包含兩種角色,分別是發布者和訂閱者。訂閱者可以訂閱乙個或若干個頻道,而發布者可以針對頻道進行傳送訊息。

發布者發布訊息的命令是:publish channel message  返回值是訂閱者的數量。

訂閱者訂閱的命令是:subscribe channel [channel...]

下面開啟兩個session進行測試:

session a:訂閱頻道1.1

127.0.0.1:6379> subscribe channel1.1

reading messages... (press ctrl-c to quit)

1) "subscribe"

2) "channel1.1"

3) (integer) 1

1) "message"

2) "channel1.1"

3) "helloworld"

1) "message"

2) "channel1.1"

3) "darren"

session b:發布者

127.0.0.1:6379> publish channel1.1 helloworld

(integer) 1

127.0.0.1:6379> publish channel1.1 darren

(integer) 1

4、管道

客戶端和redis server使用tcp協議連線。不論是客戶端傳送命令到redis還是redis返回結果給客戶端,都需要經過網路傳輸,這兩部分總消耗稱為往返時延。當執行命令很多時,各個執行的往返時延加起來還是對效能有一定影響的。因為在執行多條命令時,每條命令都要等到上一條命令執行完成並返回結果才能執行,所以redis提供管道功能,可以一次性

傳送多個命令,而且等都執行完成後一次性返回結果,這樣就減少了每條命令都需要的往返時延了,可以節省大量的連線時間。

5、節省空間

redis是乙個記憶體資料庫,所有的資料都儲存在記憶體中,所以如何優化儲存,減少記憶體空間的占用對成本控制來說是乙個重要的話題。

1)精簡鍵名和鍵值

精簡鍵名和鍵值是最直觀的減少記憶體占用的方式。當然精簡鍵名也要把握好乙個度,不能為了減少記憶體占用而使用一些不易理解的鍵名,這樣既不易維護也容易造成鍵名重複。再比如儲存性別的male和female,我們可以用m和f表示,當然也可以用0和1表示性別。

2)內部編碼優化

redis高階命令

sort 命令 1 修飾符 desc 降序排列 2 允許元素按照字段序列排序 alpha 此時的排序相當於字串排序,數字轉化為字元 12 排在 2 的前面 3 可以指定避開某些元素,然後開始排序,並返回前n個,語法為 sort key skip count 比如 sort list 3 10 表示大...

Redis 高階命令

keys 返回滿足給定模糊匹配的所有key。keys my 匹配所有my開頭的所有key exists 確認乙個key是否存在。返回0 1 exists name 是否存在key為name的key.del 刪除乙個key。返回0 1 del age 刪除age的key。1 表示刪除成功。persis...

redis 高階應用

redis是一種基於客戶端 服務端模型以及請求 響應協議的tcp服務。redis 管道技術可以在服務端未響應時,客戶端可以繼續向服務端傳送請求,並最終一次性讀取所有服務端的響應。管道技術顯著提高了redis的服務效能。分割槽是分割資料到多個redis例項的處理過程,因此每個例項只儲存key的乙個子集...