天天看點

Redis應用之任務隊列

Redis實作任務隊列

1.任務隊列

松耦合性

 生産者和消費者無需知道彼此的實作細節,隻需要約定好任務的描述格式,這使得生産者和消費者可以由不同的團隊使用不同的程式設計語言編寫。

易于擴充

 消費者可以有多個,而且可以分布在不同的伺服器中,如下圖,借此可以輕易的降低單台伺服器的負載。

Redis應用之任務隊列

2.Redis實作任務隊列

 redis中實作任務隊列我們可以通過List中的LPUSH和RPOP指令來實作。如下:

// 無限循環讀取任務隊列中的内容
while(true){
    String task = rpop("queue");
    if(task != null){
        execute(task);
    }else{
        // 如果沒有則等待1秒鐘,防止過于頻繁的請求資料
        Thread.sleep(1000);
    }
}      

 上面的代碼實作了一個簡單的任務隊列,但是還有點不完善,當任務隊列中沒有任務時消費者每秒都會調用RPOP指令檢視是否有新任務,我們想要實作的是如果有新的任務添加進來我們能夠立馬知道,這時可以使用BRPOP指令來實作,BRPOP指令的作用和RPOP作用是一樣的将List中最右側的元素彈出并傳回,唯一不同的是BRPOP是阻塞的。如果沒有元素會一直等待到新加元素或逾時。代碼如下:

// 無限循環讀取任務隊列中的内容
while(true){
    String task = brpop("queue",0);
    // 執行任務
    execute(task);
}      

BRPOP指令接收兩個參數:第一個是key,第二個是逾時時間,機關是秒,0表示不限制等待時間。打開兩個redis-cli執行個體測試如下:

127.0.0.1:6379> brpop queue 0      

進入等待狀态。在另一個執行個體中執行指令

127.0.0.1:6379> lpush queue task
(integer) 1      

阻塞的執行個體立馬擷取到了結果

127.0.0.1:6379> brpop queue 0
r1) "queue"
2) "task"
(23.39s)      

3.優先級隊列

 實際環境中我們可能需要監聽多個任務隊列,有些隊列的優先級比較高,需要優先執行,面對這種情況怎麼辦呢?這種情況下還是使用BRPOP指令來實作。

 BRPOP指令可以同時接受多個鍵,其文法格式為 BRPOP key [key …] timeout,如 BRPOP queue:1 queue:2 0,表示同時檢測多個鍵,如果所有鍵都沒有元素則阻塞。

如果其中一個鍵有元素則會從該鍵中彈出元素。

A執行個體中

127.0.0.1:6379> blpop queue:1 queue:2 0      

B執行個體中

127.0.0.1:6379> LPUSH queue:2 task
(integer) 1      

則執行個體A中擷取的結果

127.0.0.1:6379> blpop queue:1 queue:2 0
1) "queue:2"
2) "task"
(36.98s)      

如果多個鍵都有元素則按照從左到右的順序取第一個鍵的元素,這條是實作優先級隊列的關鍵

向queue:1和queue:2中分别添加一個元素

127.0.0.1:6379> lpush queue:1 task1
(integer) 1
127.0.0.1:6379> lpush queue:2 task2
(integer) 1      

然後執行BRPOP指令

127.0.0.1:6379> brpop queue:1 queue:2 0
1) "queue:1"
2) "task1"      

 根據BRPOP這個特性我們就可以實作任務隊列的優先級了。我們分别使用queue:confirmation.email和queue:notification.email兩個鍵存儲發送确認郵件和發送通知郵件兩種任務,實作代碼如下

while(true){
    String task = brpop("queue:confirmation.email","queue:notification.email",0);
    execute(task);
}      

 這時一旦發送了确認郵件的任務被加入到 queue:confirmation.email隊列中,無論 queue:notification.email還有多少任務,消費者都會優先完成發送确認郵件的任務。

~ok 到此為止

繼續閱讀