延遲發獎 - 基於循環鏈表的僞延時消息隊列

最近做了一個下單返金幣的小功能,又造了個小輪子。由於下單後存在退貨的可能,因此要求用戶下單後先發放一個凍結獎勵,在一定天數之後如果沒有退款,自動發放真實獎勵。

 

理論

此處使用了循環隊列與線程池做了一個僞延時消息隊列,理論來自@58沈劍,基本實現如下:

MQ的consumer在拿到消息後,獲得需要做實際操作的時間,計算與當前時間的時間差。由於本例實際應用中對時間要求不是特別精確,因此採用60個unit的循環隊列,worker每間隔1分鐘移動到下一個unit。如果對時間要求比較高,可以採用3600個unit的循環隊列,worker每1秒前進一格。

遍歷當前unit所包含的job,如果circularNum爲0,應當立即執行操作,爲了保證worker不會因執行業務邏輯使得移動的時間間隔與1分鐘差距過大,啓動子線程執行實際操作過程;如果circularNum>0,則將其減一,繼續判斷下一個job。worker等待1min後移動到下一格,重複上述操作。

由於線程數目較多,採用線程池進行管理。

 

安全機制

防止重複放置 - 循環隊列的每個unit採用Set存儲job,防止消息重複放入。

防止重複處理 - 從MQ中拿到消息時,將消息存儲在DB中,狀態置0,直到實際操作完畢,狀態置1。在實際下發前,先判斷當前job狀態是否爲0,如果是已操作過的消息,跳過執行並將其在隊列中刪除。

Redis - 爲了防止服務重啓時的數據丟失,將整個循環隊列存儲在redis中,每次啓動後先從redis中恢復,如果沒有數據,則創建一個新隊列。

定時掃描 - 爲了防止消息在放入循環隊列的過程中失敗或其他異常情況,使用一個獨立的worker定時掃描,如果存在已過應下發的時間但是狀態爲0的記錄,立即恢復。

單個步驟事務處理 - 此步驟依賴了團隊已有的其他服務,單個步驟失敗時(如保存記錄),會進行5次重試。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章