BlockingQueue在任務調度中的精彩應用

問題來了…

我們正在構建的系統需要從外部第三方系統中採集數據,受不可控的外部環境的影響,我們的數據採集工作經常被阻塞,一種典型的情況是:某個目標數據庫因爲要同時處理多個外圍系統疊加的查詢請求而經常響應緩慢,從而導致我們的Job嚴重超時,而這個Job原有的設計是每5分鐘執行一次,每次執行時會從目標數據庫中查詢最近5分鐘內的數據,通常情況下這種簡單的設計沒有問題,但是當前一個Job嚴重超時時,後續啓動的Job仍然以啓動時的前5分鐘作爲時間窗口進行查詢,就會導致數據丟失。 本文原文出處: 本文原文鏈接: http://blog.csdn.net/bluishglc/article/details/78447813 轉載請註明出處。

異步執行?

一個簡單的解決方案是將Job的執行變爲異步非阻塞模式,每一個Job被觸發時都在一個獨立的線程中運行。但是這個方案不適用於我們的系統,原因是這樣採集的數據無法保證按時間有序,而確保數據按時間有序對我們的系統至關重要。所以這一方案被否決。

最佳方案!

經過仔細的思考,我們認爲必須要將這個Job切分成兩個子的Job:第一個Job負責制定週期性的計劃,準確地說是週期性地生成查詢的時間參數,第二個Job則負責讀取時間參數執行查詢,這一部分的工作並不是週期性的,原則上,只要有時間參數生成就應該立即執行,如果執行超時,在超時期間,我們需要緩存第一個Job生成的時間參數,而當所有的查詢都及時完成沒有Pending的查詢計劃時,第二個Job需要等待新的查詢參數到達。到這裏事情已經變得很明朗了,我們實際上設計的是一個生產者-消費者模型,只是生產者在“有節奏”的生產,那麼在這個模式裏,作爲第三個參與者:倉庫,或者說傳送帶,就是起最關鍵作用的,而BlockingQueue就是一個現成的完美實現,於是落地的方案就是:

  1. 第一個Job由定時器週期性觸發,每次觸發時會把當前時間寫入到一個BlockingQueue的隊尾。

  2. 第二個Job循環執行,每次執行的工作就是從BlockingQueue的隊頭取出時間參數,組裝SQL並執行。

    2.1. 當隊列爲空時,由BlockingQueue來Pending當前線程,等待時間參數進入隊列。

  3. 當第二個Job執行完一次時,如果隊列中還有時間參數,會立即執行第二次,發生此類情況時就說明前一次的執行超過了5分鐘。

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