你真的知道怎麼實現乙個延遲佇列嗎?

2021-10-22 16:20:38 字數 2065 閱讀 6014

總結

延遲佇列是我們日常開發中,較為頻繁接觸的一種技術方案。顧名思義,延遲佇列就是具有延遲功能的訊息佇列。比如往該佇列裡投遞了乙個延時為60s的資訊,那麼60s後就能收到該資訊。自己在網上搜尋資料整理,學習一下,為此進行了一次總結並且把知識分享出來。

首先,大家對佇列資料結構一定不陌生了,它是一種先進先出的資料結構。普通佇列中的元素是有序的,它們遵循著先進先出的規則,也就是說,先入隊的任務優先被執行,最**隊的任務最後執行。

在我們現實生活中,延遲佇列的使用是比較多的,比如說以下幾個場景:

延遲佇列的使用場景是無處不在的。在以上場景中,如果不使用延遲佇列,則需要業務方每秒輪訓資料庫,比較現在時間是否符合設定的時間,每個業務方都需要一樣的重複邏輯。因此,我們可以將其抽象提取出來,作為公共元件,為此,今天的主角-延遲佇列至此誕生了。

有了延遲佇列,每個業務方只需要把任務新增到延遲佇列中,並設定延遲時間即可,到了指定時間,任務就會被自動觸發,呼叫對應的邏輯方法進行處理。

我們把客戶端需要延遲執行的訊息稱為乙個延遲任務,那麼我們就可以使用 redis zset 資料結構進行儲存,延遲任務的id作為key值,value值就是整個任務詳情,score值為該延遲執行的訊息延遲時間。

那麼我們可以通過以下幾個步驟使用redis的zset資料結構來實現乙個延遲佇列:

從實現步驟來看,通過redis zset 實現延遲佇列是一種容易理解並實現相對簡單的實現方式。並且我們可以依賴redis 自身的持久化來實現持久化,使用redis集群來支援高併發和高可用,是一種不錯的延遲佇列的實現方案。

timewheel時間輪演算法,也是一種實現延遲佇列的方案之一。其應用場景豐富,在 netty、akka、quartz、zookeeper 、kafka等元件中都存在時間輪的蹤影。

時間輪結構

如上面所示,時間輪是乙個儲存延遲任務的環形佇列,底層採用陣列實現,陣列中的每個元素可以存放乙個延遲任務列表(hashedwheelbucket),hashedwheelbucket是乙個環形的雙向鍊錶(圖中紅色處),鍊錶中的每一項表示的都是延遲任務項,其中封裝鏈真正的延遲任務。

時間輪是由多個時間格組成的,每個時間格表示當前時間的基本跨度。並且時間格個數是固定的。

時間輪還有乙個表盤指標,用來表示時間輪當前所指時間,隨著時間的遷移,不斷處理時間格中對應的延遲任務。

時間輪執行邏輯

時間輪在啟動時候會記錄當前啟動的時間賦值給starttime。時間輪在新增延遲任務時首先會計算出乙個延遲時間,比如乙個任務的延遲時間為30s,那麼會將當前時間+30s-時間輪啟動時間,計算出乙個時間戳(延遲時間)。然後將延遲任務加入到對應時間格的鍊錶中,等待執行。

然後需要計算出幾個引數值:

計算時間輪round次數:根據計算的需要走的(總次數-當前tick數量)/時間格個數,比如我們現在需要新增乙個延時為24秒的延遲任務,如果當前tick為0,那麼輪數=(24-0)/20=1,那麼指標每執行一圈就會將round取出來減一,所以需要轉動到第二輪之後才可以將輪數round減為0之後才會執行

計算出該任務需要放置到時間輪(wheel)的槽位,然後加入到槽位鍊錶最後

將timeouts中的資料放置到時間輪wheel中之後,計算出當前時針走到的槽位的位置,並取出槽位中的鍊錶資料,將deadline和當前的時間做對比,執行過期的數xx據。

使用時間輪實現的延遲佇列,能夠支援大量任務的高效觸發。在kafka的時間輪訓演算法的實現方案中,引入了delayqueue,使用delayqueue來推送時間輪滾動,而延遲任務的新增與刪除操作都放在時間輪中,這樣的設計大幅度提公升了整個延遲佇列的執行效率。

延遲佇列在我們日常開發中應用非常廣泛,在本文中分別介紹了使用redis zset和timewheel時間輪兩種方式實現延遲佇列。從實現過程中,可以發現使用redis zset實現延遲佇列理解起來最為簡單,能夠快速落地,但redis畢竟是基於記憶體的,雖然有持久化機制,但還是有資料丟失的可能性。而使用timewheel時間輪演算法,是乙個非常巧妙的方案,但同時也是最為難理解的方案。到這裡,文章也基本結束了,希望本文對你們實現延遲佇列提供一點思路。

怎麼用兩個堆疊實現乙個佇列

本文 具體思路 兩個棧重疊,並且棧的方向相反,棧底為另乙個棧的棧頂,棧頂為另乙個棧的棧底,乙個棧只允許壓棧,另乙個棧只允許出棧,進佇列的操作就是通過只允許壓棧的棧進,出佇列的操作從只允許出棧的棧出 用兩個堆疊表示乙個佇列。include iostream.h include malloc.h typ...

34 實現乙個佇列

思路一 這就是作業系統中介紹的pv操作,佇列的乙個典型的應用模式。實現這個pv操作的過程中要注意兩個執行緒之間的通訊就可以了。include stdafx.h include include include include include using namespace std handle g h...

實現乙個佇列類

include string include math.h include algorithm include iostream using namespace std template class node template class cirqueue 佇列類 template cirqueue...