2

我們使用Spring來運行可以在單節點上正常工作的計劃任務。我們希望在N個節點的集羣中運行這些計劃任務,這樣任務在某個時間點最多由一個節點執行。這是針對企業用例的,我們可能預計高達10到20個節點。集羣中使用zookeeper的計劃任務

我看着各種選項:

  1. 使用Quartz這似乎是在一個集羣中運行計劃任務的熱門選擇。缺點:我想避免的數據庫依賴。
  2. 使用zookeeper並始終僅在領導/主節點上運行計劃任務。缺點:任務執行負載未分佈
  3. 使用zookeeper並在所有節點上調用計劃的任務。但是在任務運行之前,一旦執行完成後獲得分佈式鎖定和釋放。 缺點:如果應用程序過載導致系統時鐘漂移,所有節點上的系統時鐘應該同步,這可能是一個問題。
  4. 使用zookeeper並讓主節點按照時間表繼續生成任務並將其分配給隨機工作人員。如果先前的計劃任務尚未完成,則不分配新任務。缺點:這似乎增加了太多的複雜性。

我傾向於使用#3,這似乎是一個安全的解決方案,假設zookeeper合奏節點在單獨的羣集上運行,系統時鐘使用NTP同步。這也假定如果系統時鐘同步,那麼所有節點都有相同的機會獲得執行任務的鎖。
編輯:經過一些更多的想法後,我意識到這可能不是一個安全的解決方案,因爲系統時鐘應該在計劃任務運行的節點之間同步,而不僅僅是動物園管理員羣集節點。我說的不安全,因爲運行任務的節點可能因GC暫停和其他原因而過載,並且可能會出現時鐘不同步的情況。但是我再次認爲這是分佈式系統的標準問題。

你能否告訴我,如果我對每個選項的理解是準確的?或者可能比列出的選項有更好的方法來解決這個問題。

+0

僅供參考 - 我爲Curator/ZooKeeper編寫了一個分佈式任務調度程序。 https://github.com/NirmataOSS/workflow – Randgalt

回答

0

那麼,你可以像這樣改進#3

動物園管理員提供觀察者。也就是說,您可以在給定的ZNode上設置觀察者(例如,在路徑/some/path處)。羣集中的所有節點正在觀察相同的Znode。每當一個節點認爲(按計劃或任何方式)現在應該運行計劃任務,

  1. 首先,它創建/some/pathPERSISTENT_SEQUENTIAL子節點(所有節點都看)。另外,您可以根據需要設置該節點的數據。它可能是一個json字符串,指定要運行的任務的詳細信息。新的ZNode路徑看起來像/some/path/prefix_<sequence-number>
  2. 然後,集羣中的所有節點都會收到有關創建的子節點的通知。他們然後獲取新創建的ZNode的數據並解碼任務。
  3. 現在,每個節點都嘗試獲取分佈式鎖。誰先得到它可以執行它。一旦執行,該節點應報告(通過創建一個名爲success/some/path/prefix_<sequence-number>下創建一個新的ZNode),該任務已執行。然後釋放鎖。
  4. 每當一個節點試圖執行任務時,在嘗試獲取分佈式鎖之前,它應該檢查ZNode是否已經有一個success子節點。

此設計通過檢查名爲success的子節點在創建的給定ZNode中以通知以啓動任務來確保沒有任務運行兩次。

我已將上述設計用於企業解決方案。實際上,對於分佈式命令框架;-)

+0

我認爲這將起作用,但它看起來與我列出的#4類似,只是所有節點都接收任務並爭奪鎖執行。 #4也使用監視器,但使用[link](https://github.com/fpj/zookeeper-book-example/blob/master/src/main/java/org/apache/zookeeper /book/curator/CuratorMasterSelector.java),它似乎是更好的選擇,因爲只有一個隨機工作者將獲得任務,並且不需要分佈式鎖。 – vkorimilli

+0

但是,如果存在任何缺陷或缺點,我希望檢查輸入,除複雜性因素外,我可能會缺少輸入。 – vkorimilli

+0

在這種情況下,您不必擔心主從複雜性。讓他們爭奪鎖定並完成任務。 –

0

Zookeeper或Etcd不是此用例的最佳工具。

如果您的環境允許您使用akka,則使用akka羣集+最小的郵箱路由器或您喜歡的任何羣集路由器會更容易。然後將計劃作業推送到集羣的ActorRef。更容易設置,您可以使用它在集羣中設置數千個節點(它使用協議cassandra和遊牧民族使用)。

Scalecube也很容易再次使用SWIM。