1. 程式人生 > >分散式任務編排排程框架設計

分散式任務編排排程框架設計

運維焦油坑

隨著網際網路+和去IOE浪潮的推進,傳統行業X86伺服器的數量逐漸增多。伺服器數量劇增帶來的直接後果就是運維複雜度的增加。原本一個人可以輕鬆維護十幾臺甚至幾十臺伺服器:寫幾個常用的監控和配置下發指令碼、或者利用cronTab製作幾個定時任務就可以搞定。當伺服器的數量由幾十上升到幾百,幾千時,量變就引起了質變;而且隨著應用數量的增多,需要同時對多個應用進行快速高效的備份或者持續部署等非常複雜的操作。傳統的運維思路已經很難滿足現實的需求了。這個時候,再牛掰的運維人員也會像焦油坑中的巨獸一樣舉步維艱。而本文將會給大家分享一種跳出運維焦油坑的實現思路。

工欲善其事

說到運維工具,大家都能信手拈來:Ansible,Pupet,Chef,Saltstack等等。每一種工具都給運維人員提供了很大的幫助,讓他們從繁瑣的運維任務中得到減負。因為本文主要介紹的是分散式任務排程框架,所以這裡就不對這幾種運維工具的優劣進行過多地比較。就像標題中所說的,我們只要選一種運維工具,再加上一個穩定高效的任務排程框架,那麼就可以輕鬆面對千萬臺伺服器的運維操作了。這裡我們選擇的是Ansible。主要原因他是Agentless的。對於不喜歡在生產伺服器上安裝各種外掛的運維工程師來說是個不錯的選擇。

整體結構圖

本文主要跟大家分享的是分散式任務編排與排程框架設計。整個平臺就有這麼幾個關鍵點:分散式、任務編排、任務排程。

所謂分散式,就是平臺是分散式部署的,各個節點之間可以無狀態和水平擴充套件;所謂任務編排,就是平臺可以支撐多工步驟,多步驟明細的複雜任務的編排和解析;所謂任務排程,就是平臺可以對單一運維操作進行最優切分和排程,從而保證對大量伺服器進行運維操作快速高效地完成。

有圖有真相。接下來給出整個平臺的整體結構圖:

 

整體結構圖

通過圖上我們可以看到,整個平臺依靠Zookeeper作為服務的註冊和管理中心;依託RabbitMQ進行服務模組之間訊息的傳遞;採用MySQL作為基礎資料的儲存。

執行全過程

接下來我們就各個模組所提供的服務和模組之間的互動流程跟大傢俱體描述。

Web模組是平臺的臉面,用來提供任務編排,任務執行進度等資訊的展示。在啟動之初Web從Zookeeper上獲取可呼叫的Server的資訊並快取起來。同時,在Server有任何變化時(下線和上線),會接到通知來實時更新快取。從而保證尋找Server服務時能夠更加快速和高效。

Server模組是整個平臺的核心,主要負責複雜任務編排的解析處理、複雜任務執行流程拆分和排程下發。Server啟動之初會向Zookeeper進行服務註冊,用來告知其他模組,我已啟動,可以幹活了;與此同時,它還會從服務中心那裡獲取其他資訊:比如還有幾個和他一樣的兄弟跟他並肩戰鬥?還有幾個手下(Scheduler)可以用來執行任務?Server就像一臺告訴運轉的引擎,隨時準備處理各種任務。

Scheduler模組主要用於接受Server發過來的任務並進行更加細化拆分和下發。在模組啟動之初,跟Server一樣進行自身服務的註冊和關注服務的獲取和快取,比如,獲取真正可以幹活的小弟(Worker)的資訊。在面對大量伺服器的時候就可以把目標機器進行拆分,讓每個Worker都能均衡的獲取和執行任務,加快任務執行速度。比如:Server發過來一個任務,要你備份一千臺伺服器的某個目錄。怎麼做?一個個序列做嗎?開玩笑!單這一個任務就夠你執行半天。所以,關鍵時候還是要併發的把任務分配給多個Worker。然後再進行任務結果的收集就可以了。從某種角度講,Scheduler只能算是一個小組長,負責分配任務,收集結果。還是比較清閒的。

Worker模組的主要負責具體任務的執行,是整個平臺中最苦逼的一個模組。它只能接受任務引數,任勞任怨的利用Ansible去目標機器執行任務,然後把任務的處理結果傳送到MQ中。其實,worker也會有自己的小算盤。打個比方,Scheduler接受到的一千臺伺服器備份任務,假設平臺有10個worker,那麼每個worker將會分到100臺伺服器的備份任務。Worker會傻傻的一個一個執行嗎?當然不會!worker內部也會併發的去多個目標伺服器上去執行備份任務,然後進行結果的回收。

核心技術點

囉嗦了那麼多,相信大家對平臺的整體運轉過程有了大致瞭解。接下來我們就這幾個核心技術點進行重點描述:

分散式:分散式的目標就是為了實現高可用,高吞吐量。上面說到的幾個模組全部實現了分散式部署,各自的特點體現如下:

Web層,我們在前端採用了Nginx進行請求負載。利用了Redis進行Session資訊的儲存。用來實現解決web層的高可用問題。

Server層自身就像一個獨立的任務編排排程引擎,可以獨立對外提供服務,多個server模組之間可以依賴服務中心感知彼此的存在,在某個server掛掉的時候可以快速的把其中的任務轉移到其他的server模組來執行。

Scheduler,Worker和Server一樣,同樣可以分散式部署並支援水平無限擴充套件。

任務編排:我們拿一個應用部署的過程來舉例:我們要釋出一個javaweb應用到2臺機器上。那麼我們要做哪些操作呢?首先,我們要把負載下掉,web伺服器(以Tomcat為例)停掉;其次,我們要把一些快取資料,不用的日誌資料清理掉;第三步,我們要把應用包從軟體倉庫拷貝到目標機器的指定路徑;第四步,我們要把web伺服器啟動;最後一步,把應用的負載進行更新。這樣一個由五個操作步驟的複雜任務是如何進行編排的呢?我們將這個複雜任務定義了三個物件:Task, step, job。Task就是整個的複雜任務,step呢就是我們說的這五個步驟。Job就是每個步驟具體要做的事情。在任務編排的時候我們會把這三類物件資料和關聯關係資料存放到資料庫中。那麼上面的這個例子對應出來的任務資料大體下如下:

task:

    step-1

        job-1-1

        job-1-2

    step-2

        job-2-1

    step-3

        job-3-1

    step-4

        job-4-1

    step-5

        job-5-1

在任務執行的時候我們採用的思路是:步驟(Step)之間序列執行,Step內部的Job並行執行。步驟之間序列執行是因為前後兩個任務之間存在依賴關係,如果沒有依賴關係的任務可以放到同一個步驟來執行。這樣就會提高整體任務的執行效率。整個複雜任務的解析執行過程如下:

任務執行過程

首先,Task Engine拿到整個任務資料,先會進行資料校驗。在格式正確的情況下依次執行各個步驟(Step),在單個Step中獲取具體執行的job列表,並對每個job的任務引數封裝成一個任務執行緒,丟到執行緒池中去執行。

其次,執行緒執行時會將具體的任務傳送到Scheduler中,然後等待MQ中的job處理結果,Scheduler在接受到任務之後會根據目標機器和worker的數量以及單個worker的處理能力經驗值來計算出此次job需要呼叫worker的最優次數。然後將任務下發到具體的worker中來執行。同時,告知worker任務結果傳送到MQ中的訊息佇列。同時監聽MQ中該佇列的訊息,接收到訊息之後處理並回傳到server中的任務執行緒中。

最後,worker在接受到任務引數和結果佇列資訊之後,會根據目標機器數量進行再次排程,然後收集任務處理結果併發送到scheduler執行的訊息佇列中去。這樣,server接收到該step的所有job執行結果之後會繼續執行下一步驟中的各個job。最終把整個複雜任務處理完成。整個過程的資料流圖如下圖所示:

排程整體框架

任務排程:整個平臺的任務排程分為三個層面的排程:首先是server和scheduler之間的排程。他們的排程方式包括pull和push兩種模式,即server會定時向scheduler推送任務訊息,同時scheduler在執行完任務之後也會向server詢問是否有其他可執行的任務;其次是scheduler和worker之間的排程。我們這幾假設目標機器有M臺,worker數量有W個,每個worker處理任務的經驗值是C個。我們的整體演算法流程虛擬碼如下:

if (targets>Worker * C){

    String[] targetArray = splitTarget(C)

    for(String target : targetArray){

        createRequest(target)--->worker

    }

}else{

    C = [targets/Worker]

    String[] targetArray = splitTarget(C)

    for(String target : targetArray){

        createRequest(target)--->worker

    }

}

當然,這個排程演算法非常簡單,我們可以根據單個worker的實時負載情況進行復雜排程演算法的增強,以及對於失敗任務的補償機制的增強處理都是在scheduler和worker之間可以排程優化的地方。

最後是worker內部的排程,worker會根據自身處理能力的大小,將多個目標機器進行再次分割,然後併發執行任務。從而提高整個平臺的任務處理能力。

寫在最後

本文主要跟大家分享了一種分散式任務編排排程平臺的設計思路,重點介紹了平臺的三個重要特點:分散式,任務編排,和任務排程以及平臺後續的優化方向:

一,任務編排處理過程中增加條件判斷邏輯;

二,scheduler和worker之間排程演算法優化。

三,任務執行過程中中斷和人機互動的增強。

我們目前正在基於這個思路進行相關功能的落地。如果大家有其他的見解或者文中有哪些描述不合理的地方。歡迎批評指正。我們的目標就是構建出一個穩定高效的運維任務排程平臺,幫助運維人員儘快爬出運維的焦油坑。



作者:丁明威
連結:https://www.jianshu.com/p/e65da69a5c88
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。