最新文章

資料庫

使用 MongoDB Change Streams 熱交換 Cron 排程 ================================================ 在本文中,我們將探討如何在 Node.js 應用程式中使用 MongoDB change streams 來熱交換 cron 排程。這項技術讓您能夠更新任務排程而無需重新啟動您的應用程式,從而提供一個更具動態性與彈性的排程系統。 核心概念是將您的 cron 排程儲存在一個 MongoDB 集合中。您的應用程式會在一開始載入這些排程,並設定相應的 cron 任務。接著,它會使用 change stream 來監聽該集合中的變更。當資料庫中的排程被更新、新增或移除時,change stream 將會發出一個事件。您的應用程式接著可以對此事件做出反應,更新記憶體中正在執行的 cron 任務。 這種方法將您的排程邏輯與應用程式的部署週期解耦。您可以透過一個獨立的管理介面或直接修改資料庫來管理排程,而這些變更將幾乎即時地反映在您正在執行的應用程式中。

硬編碼的 cron 排程意味著每當排程變更時,都必須重新部署。將排程儲存在資料庫中,並讓守護進程使用變更串流來對編輯做出反應。以下是其設計與故障處理方式。

閱讀約 2 分鐘 mongodbchange-streamscrongoscheduling
後端

使用 CAS 與 Heartbeat 的租賃鎖,用於單一執行器工作 ===================================================== 租賃鎖是一種機制,用以確保在任何特定時間只有一個工作實例正在執行。這對於非冪等 (non-idempotent) 且若同時執行可能會導致問題的工作特別有用,例如資料庫遷移或部署到單一環境。 本文件概述了一種使用檢查並設定 (Check-And-Set, CAS) 操作結合心跳機制來實作租賃鎖的策略。這種方法很強健,並且可以處理工作執行器意外失敗的情況。 ## 核心概念 - **租賃金鑰 (Lease Key)**:在共用儲存系統(例如 Redis、Consul、etcd)中的一個唯一識別碼,代表特定工作的鎖。例如 `zP1z`。 - **租賃值 (Lease Value)**:儲存在租賃金鑰處的值。它通常包含當前持有鎖的工作執行器的唯一 ID 以及一個時間戳。例如 `zP2z`。 - **檢查並設定 (Check-And-Set, CAS)**:一種不可分割操作 (atomic operation),僅在其當前值符合給定先決條件時,才將新值寫入金鑰。這可以防止在獲取或釋放鎖時發生競爭條件 (race conditions)。 - **心跳 (Heartbeat)**:由持有鎖的工作執行器發送的定期信號,以表示它仍然存活並正在積極處理工作。這通常是透過更新租賃值中的時間戳來完成。 - **租賃持續時間 / TTL (存活時間)**:一個逾時時間,在此之後如果沒有收到心跳,鎖將被視為過期。這可以防止在執行器崩潰時發生死鎖 (deadlocks)。 ## 工作流程 ### 1. 獲取鎖 1. 一個工作執行器(我們稱之為 zP3z)啟動,並想要執行與 `zP1z` 相關的工作。 2. zP3z 透過對 `zP1z` 執行 CAS 操作來嘗試獲取鎖。 - **情境 A:鎖是空閒的。** 金鑰 `zP1z` 不存在,或者其值表示它是空閒的(例如,為空或具有特殊的「空閒」標記)。zP3z 執行 CAS 操作,以類似 `zP4z` 的值來建立金鑰(或從「空閒」狀態更新它)。由於滿足了先決條件(金鑰不存在/是空閒的),CAS 操作成功。 - **情境 B:鎖已被佔用。** 金鑰 `zP1z` 存在且其值類似 `zP5z`,表示它被另一個執行器 (zP6z) 持有。zP3z 讀取此值。 - **情境 C:鎖已過期。** zP3z 讀取值 `zP5z` 並檢查其時間戳。如果 `current_time - timestamp > lease_duration`,則該鎖被視為過時。zP3z 接著可以嘗試強制獲取鎖,其方式是執行一個 CAS 操作,先決條件為金鑰的值必須仍然是 `zP5z`。如果成功,zP3z 現在就持有了鎖。如果失敗,表示在此期間有另一個執行器獲取了鎖,zP3z 返回步驟 2。 3. 如果 zP3z 未能獲取鎖(因為它正被另一個執行器活躍地持有),它可以選擇退出或定期重試。 ### 2. 維護鎖 (Heartbeat) 1. 當 zP3z 持有鎖並正在執行工作時,它必須定期發送心跳以防止鎖過期。 2. 心跳是一個 CAS 操作。zP3z 更新租賃值中的時間戳。CAS 的先決條件是該值必須仍然是 zP3z 設定的那個值(即,執行器 ID 必須與 zP3z 的 ID 相符)。 3. 如果心跳 CAS 操作失敗,這意味著鎖已丟失(例如,在它被認定過期後,被另一個執行器獲取)。在這種情況下,zP3z 必須立即停止其工作以防止並行執行。它應該執行清理然後終止。 ### 3. 釋放鎖 1. 一旦 zP3z 成功完成其工作,它就應該釋放鎖。 2. 釋放是透過刪除金鑰 `zP1z` 或將其值設定為「空閒」狀態來完成。這也應該是一個 CAS 操作,其先決條件是鎖仍然由 zP3z 持有。這可以防止執行器意外釋放一個已經被另一個執行器接管的鎖。 ## 處理失敗 - **執行器崩潰**:如果持有鎖的執行器崩潰,它將停止發送心跳。租賃最終會過期(在 `lease_duration` 之後)。另一個執行器接著可以偵測到過時的鎖並獲取它(工作流程 1,情境 C)。 - **網路分區**:如果執行器與儲存系統被分區,其心跳 CAS 操作將會失敗。它會意識到自己已丟失鎖,並且必須終止其工作。在分區的另一側,其他執行器會看到鎖已過期,其中一個將會獲取它。 ## 總結 這種帶有心跳的 CAS 方法為單一執行器工作提供了一個可靠的分散式鎖定機制。它能正確處理執行器失敗和網路問題,防止並行工作執行和死鎖。

當持有者死亡時,一般的鎖會永久死鎖。租約則會到期。這裡將說明如何使用「比較並交換」(compare-and-swap) 取得機制和心跳機制來建構一個租約,以及決定此設計的失敗模式。

閱讀約 2 分鐘 distributed-systemslockingredisgojobs