系統設計:如何設計一個分散式作業排程器 ?- Rakshesh
工作排程是一個眾所周知的系統設計面試問題。下面是一些可能需要設計工作排程器的領域。
- 設計一個付款處理的系統。(即每月/每週/每天的支付等)
- 設計一個程式碼部署系統。(即程式碼流水線)
這個職位的目的是設計一個簡單但可擴充套件的作業排程系統。
問題說明
- 設計一個作業排程器,在預定的時間間隔內執行作業
功能要求
- 使用者可以安排或檢視工作。
- 使用者可以列出所有已提交的作業和當前狀態。
- 工作可以執行一次或重複執行。工作應在定義的計劃時間後的X閾值時間內執行。(讓x=15分鐘)
- 單個作業的執行時間不超過X分鐘(讓X=5分鐘)。
- 工作也可以有優先權。優先順序較高的作業應該比優先順序較低的作業先執行。
- 工作的輸出應該儲存在檔案系統中
非功能要求
- 高度可用 - 系統應始終可供使用者新增/檢視作業。
- 高度可擴充套件性--系統應可擴充套件至數百萬個作業
- 可靠性--系統必須至少執行一次作業,而且同一作業不能由不同的程式同時執行。
- 永續性--在發生任何故障時,系統不應丟失作業資訊。
- 延遲性 - 系統應該在作業被接受後立即確認使用者。使用者不需要等到作業完成。
系統介面
有三個API可以暴露給使用者
1. submitJob(api_key, user_id, job_schedule_time, job_type, priority, result_location)
這裡,job_type = ONCE或RECURRING,result_location可以是s3位置。
API在接受作業後可以返回http響應程式碼202
2. viewJob(api_key, user_id, job_id)
響應包括狀態為NOT_STARTED、STARTED或COMPLETED
3. listJobs(api_key, user_id, pagination_token)
使用者可以查詢所有提交的工作,並返回一個分頁的響應
使用者請求流程
- 使用者通過連線負載均衡器(或API閘道器)來提交/獲取工作。
- 請求將持續存在於資料庫中,並將確認函發回給使用者
- 工作執行者服務將不斷從資料庫中輪詢到期的工作,並在佇列中保持輸入。
- 工作執行者服務將執行實際的工作業務邏輯,並將最終結果更新到檔案系統中,並將狀態更新為完成。
資料庫設計
由於我們沒有嚴格要求交易支援或任何其他ACID屬性,並考慮到峰值QPS(2*1000=2000 QPS),我們可以使用SQL或NoSql資料庫。考慮到NoSql在規模、維護和成本方面的明顯優勢,我將使用DynamoDb的NoSql解決方案。
使用者查詢模式。
- 給定userId,新增工作
- 給定使用者身份,檢索所有工作編號
資料庫表結構:
Table: JOB +------------------------------+--------+ | Attribute | Type | +------------------------------+--------+ | user_id (partition key) | uuid | | job_id (sort key) | uuid | | actual_job_execution_time | date | | job_status | string | | job_type | string | | job_interval | int | | result_location | string | | current_retries | int | | max_retries | int | | scheduled_job_execution_time | date | | execution_status | string | +------------------------------+--------+ |
job_status。這是使用者將看到的工作狀態。它可能有:NOT_STARTED, STARTED, COMPLETED
execution_status。這是我們的服務將保持的實際執行狀態。它可能有。not_started, claimed, processing, success, retriable_failure, fatal_failure
除了使用者之外,我們的工作排程服務將輪詢資料庫以獲得到期的任務。我們有不同的方法來實現這一點
1. 基於X分鐘大小的桶視窗進行分割槽
我們可以建立索引,命名為 scheduledJob,以檢索最後X分鐘到期的工作。
Index: ScheduledJob +----------------------------------------------+------+ | Attribute | Type | +----------------------------------------------+------+ | scheduled_job_execution_time (partition key) | time | | job_id (sort key) | uuid | +----------------------------------------------+------+ Query (SQL equivalent): SELECT * FROM ScheduledJob WHERE scheduled_job_execution_time == now() - X |
2. 基於X分鐘大小的桶視窗加分片ID的分割槽
有可能在一個特定的時間視窗,已經收到了許多作業(比方說100K)。在這種情況下,上述查詢效能將非常緩慢。我們可以根據隨機的(比方說在1到Y之間)shard_id來進一步劃分資料庫。
Index: ScheduledJob +----------------------------------------------+------+ | Attribute | Type | +----------------------------------------------+------+ | scheduled_job_execution_time (partition key) | uuid | | shard_id (partition key) | int | | job_id (sort key) | uuid | +----------------------------------------------+------+ Query (SQL equivalent): SELECT * FROM ScheduledJob WHERE scheduled_job_execution_time == now() - X and shard_id == Y |
工作排程器是如何工作的?
作業排程流程:
每隔X分鐘,主節點會建立一個權威的UNIX時間戳,並給每個工作節點分配一個shard_id和scheduled_job_execution_time。
工作者節點將執行以下查詢,並將作業推送到Kafka佇列中進行執行。
Worker 1: SELECT * FROM ScheduledJob WHERE scheduled_job_execution_time == now() - X and shard_id = 1 Worker 2: SELECT * FROM ScheduledJob WHERE scheduled_job_execution_time == now() - X and shard_id = 2 |
容錯:
Master監控工作者的健康狀況,知道哪個工作者死亡,以及如何將查詢重新分配給一個新的工作者。
如果主節點死亡,我們可以分配其他工作節點作為主節點。
此外,我們還可以引入本地資料庫來跟蹤工人是否成功查詢了資料庫並將條目放入佇列中。
工作執行器是如何工作的?
作業執行器服務有多個消費者,從佇列中提取資料。消費者機器也有主程式和工作程式。主程式和工作程式都是基於 "拉 "的模式進行操作。主程式將從佇列中輪詢作業,工人程式將通過執行以下程式碼從主程式中持續輪詢作業
while True: w = get_next_work() do_work(w) |
作業執行流程和容錯
- 當一個作業從佇列中被取走時,消費者的主站會更新JOB db屬性execution_status=CLAIMED。
- 當worker程式拿起工作時,它更新execution_status=PROCESSING,並不斷向本地資料庫傳送健康檢查。
- 工作完成後,worker程式將把結果推送到s3,更新JOB資料庫的execution_status=COMPLETED或FATAL_FAILED,以及本地資料庫的狀態。
- worker程式和主站都會在本地資料庫中更新健康檢查。
健康檢查器服務
健康檢查器服務定期執行(例如每隔 x 秒),並掃描最後一次從工人程式收到的健康檢查低於定義閾值的資料庫。在這種情況下,它認為該作業未能處理,並將條目推回佇列。
相關文章
- 作業系統精髓設計原理 程式排程作業系統
- 分散式任務排程系統設計小結分散式
- 排程系統設計精要
- 作業系統課程設計感受作業系統
- 淺談分散式任務排程系統Celery的設計與實現分散式
- 分散式系統設計策略分散式
- 分散式系統程式設計分散式程式設計
- 系統架構設計之-任務排程系統的設計架構
- 如何設計一個微型分散式架構?分散式架構
- 【作業系統】--處理器排程作業系統
- Schedule 排程系統設計(單機版)
- 分散式後臺作業排程器JobRunr介紹 - JAXenter分散式
- 如何設計一個微博系統?- 4招教你搞定系統設計
- Circuit: Go語言編寫的最小分散式程式設計式的作業系統UIGo分散式程式設計作業系統
- 分散式搜尋系統的設計分散式
- 分散式系統設計的求生之路分散式
- 分散式系統安全設計原則分散式
- 程式設計作業——系統管理程式設計
- 作業系統實驗(一)-Shell程式設計作業系統程式設計
- 如何設計一個RPC系統?RPC
- 如何設計一個秒殺系統
- 如何設計一個搶紅包系統
- 如何設計一個 RPC 系統RPC
- 如何設計一個秒殺系統?
- 如何設計一個RPC系統RPC
- 作業系統(5)處理器排程管理作業系統
- 設計一個分散式RPC框架分散式RPC框架
- 【系統設計】設計一個限流元件元件
- 實現一個分散式排程系統-LoadBalance和Ha策略分散式
- 嵌入式作業6.3 CAN 匯流排程式設計程式設計
- 【分散式系統設計簡卷(0)】MapReduce分散式
- 19種分散式系統設計模式 - Nishant分散式設計模式
- 解析分散式系統的快取設計分散式快取
- 分散式系統設計權衡之 CAP分散式
- 分散式系統設計權衡之CAP分散式
- 分散式系統的設計與開發分散式
- 如何設計一個麻雀般的微型分散式架構?分散式架構
- 分散式系統程式設計,你到哪一級了?分散式程式設計