vivo 自研Jenkins資源排程系統設計與實踐

2023-02-13 12:01:06

作者:vivo 網際網路伺服器團隊- Wu Qinghua

本文從目前業界實現Jenkins的高可用的實現方案,分析各方案的優缺點,引入vivo目前使用的Jenkins高可用方案,以及目前Jenkins資源的排程方案的設計實踐和目前的落地執行效果。

一、前言

現在的企業很多都在用Jenkins做持續整合,各個業務端都依靠Jenkins,vivo Devops也是使用Jenkins來進行持續構建,部署Jenkins服務時如何保障服務的高可用變得尤為重要。

下面是目前Jenkins存在的一些問題

  1. Jenkins本身是單體的,即只能有一個Jenkins Master。雖然你也可以在多臺機器上部署多個Jenkins Master,但這些Master之間沒有聯絡,都是各自把任務交給手下的slave去執行,沒有任何交集。也許某個master下的slave很忙,而另一個master下的slave卻很閒,資源得不到充分利用。

  2.  當其中一個slave宕機之後,該slave上的執行的job任務沒有版本重新進行分配,需要使用者重新執行。並且slave節點離線之後沒有通知管理員。

  3.  當系統業務量比較大的時候業務請求集中在Jenkins Master上,會對Jenkins造成壓力,甚至的造成Jenkins服務不可用。

  4.  當有job任務在jenkins Master上佇列排隊的時候,Jenkins Master宕機後,佇列任務不可持久化。

  5. Jenkins Workspace沒有自動清理功能,會導致磁碟空間不足,任務執行不了的情況。

 基於以上情況,vivo Devops對Jenkins的部署架構進行優化搭建,並且配套了一套Jenkins資源排程系統用於管理Jenkins資源。

二、業界實現

目前業界也包含一些Jenkins 高可用的設計方式,但是並不能完全的滿足解決上述問題,比如:

2.1 方案一  Gearman + Jenkins

這是OpenStack團隊使用的方案。這個方案使用了gearman, gearman是個任務分發框架。

需要在每個Master上安裝好gearman的外掛,並設定好能連線到gearman server,同時在每個Master必須建立相同的job。

之後執行任務的流程如下:

  1. gearman worker執行在各個Jenkins Master中等待gearman server分發任務;

  2. gearman client向gearman server發出執行job的請求;

  3. gearman server通知各個gearman worker有任務拉,第一個閒著的worker會接受任務,如果所有的worker都忙,則放入gearman的任務佇列,得worker空閒時再分配;

  4. gearman worker閒下來後會從任務佇列裡取job來執行,執行完之後,將結果發回給gearman server;

  5. gearman server將結果返回給 gearman client。

優點:

這樣各個salver資源可以得到充分利用,某個master掛掉另外的master可以繼續服務。

弊端:

每個master的slave必須設定一致,否則會造成job排程錯誤,同時會造成一些資源的浪費。當一個master出現問題,該master的任務不會進行自動重新分配。

2.2 方案二 改造Jenkins的檔案儲存方式

目前Jenkins的組態檔都是直接在硬碟上以檔案形式儲存的,你在JENKINS_HOME的個資料夾下能看到各種.xml檔案。有些公司在Jenkins上進行二次開發,將Jenkins的資料儲存方式改為資料庫儲存,這樣前端可以起多個Jenkins服務,後端連相同的資料庫即可。資料庫也有比較成熟的高可用方案。

優點:   可以達到Jenkins的高可用也就是某個master掛掉另外的master可以繼續服務。

弊端:需要對Jenkins進行二次開發,使用資料庫會降低讀取資源效率下降。

2.3 方案三 最簡單的Jenkins一主一備模式

平時讓Jenkins A機器提供服務,並使用SCM Sync configuration plugin儲存資料,JenkinsA機器修改設定後觸發Jenkins B更新設定,一旦Jenkins A出現問題掛掉後,切換到備機Jenkins B上。

優點:   可以達到Jenkins的高可用,當master宕機後會進行切換到備機上。

弊端:   會有一批Jenkins備機存在資源浪費,切換master時間過長,會導致有段時間Jenkins服務不可用。

三、vivo Jenkins Scheduler系統目標

由於目前業界的一些實現還不能完全的滿足我們目前的需求,所以我們進行了vivo jenkins scheduler系統的設計與實現。該系統需要達到如下的目的:

  1. 提升整個構建服務可靠性時長。

    保證jenkins叢集的高可用,解決目前master-slave的單點問題,保證整個構建服務的可靠性時長。

  2. 降低災難時服務恢復時長。

    ①提供精準流控方式,在jenkins構建出現請求量過高的時候可以進行流控和持久化操作,減少對目前系統的衝擊。

    ②當系統壓力減少後,放開流控可以快速的對堆積的請求進行分配執行。

  3. 有效分配任務至各個子節點,保證資源的有效利用。

  4. 能保證災難時的及時切換任務至可用節點上,同時能快速的通知管理員進行處理。

  5. 能進行資料的視覺化分析,能提供一系列幫助改善開發效率的檢視,比如構建時長報表、構建量報表等。

四、 vivo Jenkins Scheduler設計

該系統我們從兩大部分進行了設計,首先,我們不採用原生的Jenkins部署方案,而是採用全master的方式。第二,設計並開發了一套用於管理Jenkins叢集的排程系統。

五、底層 Jenkins 工具部署方案

不採用目前單master的搭建方案,採用多master的搭建方案,master下不進行掛載slave機器,任務直接有master進行處理,master之間的關係、任務分配、離線、外掛安裝等由排程系統進行管理。這樣由於vivo Jenkins Scheduler系統為高可用的,解決了目前Jenkins的單點問題。

圖片

六、系統架構圖

圖片

七、系統說明

7.1 API-Gateway

主要提供系統的外部請求,閘道器系統,功能包含:

  • 許可權校驗:校驗使用者傳送叢集管理系統的請求的許可權。

  • 智慧路由:接收外部一切請求,並轉發到後端的外服上去。

  • 限流:與監控執行緒配合(當構建請求達到某個閾值時),進行限流操作。

  • API紀錄檔統一收集:類似於一個aspect切面,記錄介面的進入和出去時的相關紀錄檔。

  • 資料處理:對請求的引數進行資料的轉換處理。

7.2 事件中心

是整個系統通訊呼叫的主要模組,採用的是Spring的Event機制實現,主要核心事件如下:

  1. Jenkins註冊事件

    (EVENT_REGIST_JENKINS)

    Jenkins啟動後,通過自定的外掛會向系統傳送註冊請求時,系統接收到後會觸發Jenkins管理模組將Jenkins的資訊註冊至排程系統中。

  2. Jenkins宕機事件 

    (EVENT_DOWN_JENKINS)    : 

    監控管理輪詢檢查Jenkins狀態,當發現有Jenkins宕機的情況會觸發該事件,Jenkins管理模組處理將Jenkins的資訊狀態設定為不可用狀態,從而是任務不能分配至該臺jenkins。

  3. 任務從分配事件  (EVENT_JOB_REDO) 

    當Jenkins宕機後,如果該臺jenkins上存在未執行完的任務時候,由job監控模組觸發,job管理莫管處理,會對該Jenkins上未執行的job進行重新分配。

  4. 任務接受事件  (EVENT_JOB_RECIVE) :

    當job管理模組接受到建立請求,會觸發該事件,由job管理模組放入Redis執行佇列。

  5. 任務執行事件  (EVENT_JOB_EXECUTE) : 

    job管理模組中的執行執行緒(10s執行一次,會從Redis佇列中彈出任務),彈出任務後觸發該事件,由排程中心選取合適的jenkins進行執行。

7.3 排程中心

是整個系統的核心模組,主要的功能是進行執行job時候能選取合適的jenkins進行處理任務,包含兩個核心演演算法:

7.3.1 Jenkins分組演演算法

每臺Jenkins都可以使用標籤的方式,打上多個標籤,比如Jenkins可以構建Java程式,使用的構建工具可以是maven和gradle,這個時候我們就可以給其打上Java、maven、gradle三個標籤。

標籤的維度主要有以下幾個:

  • 標籤設定: 判斷構建設定是否設定了標籤,根據標籤選擇對應標籤的Jenkins,比如設定了(docker等)。

  • 構建語言: 根據構建設定的語言,比如Java、C++、Python、Go等。

  • 構建工具和版本: 比如Maven、gradle、Ant,Cmark、Blade等。

  • JDK版本:比如JDK7、JDK8等。

  • Go語言版本:比如1.15.x.、1.16.x等。

  • GCC版本:如6.x、4.x等。

  • Python版本:2.x、3.x等。

  • 是否存活:判斷Jenkins是否存活,如果宕機直接過濾。

  • (可選策略)選擇執行過該job的Jenkins,減少下載程式碼的過程:(第一次構建還是會比較慢,可以採用預執行的方式,在設定構建設定的時候,就預先執行一次,這樣在使用者執行的時候就使用該job執行過得workspace,減少程式碼下載的時間)。

  • (可選策略)根據job的構建的平均構建時長,如果構建時長達到某個設定閾值時,優先選擇構建器空閒多的Jenkins進行執行,並指出Jenkins的鎖定功能。其他的job不允許分配上來。

 

如果我們給Jenkins打上標籤,那麼我們就可以使用標籤為維度將Jenkins進行分組,並且存入至Redis中快取,方便後續選取Jenkins用來執行任務:

圖片

7.3.2 Jenkins選取演演算法

當Jenkins分組好了後,我們接受到執行的job的資訊就可以使用Jenkins選取演演算法進行快速的選取合適的Jenkins進行處理job,如下圖所示。

 

其中label子執行緒、語言子執行緒……就是我們上面的Jenkins分組的維度,有多少維度,那麼這裡就會有多少子執行緒處理。

 

構建任務進入主執行緒,然後主執行緒會按照分組維度分組操作並進行過濾,然後獲取到每個分組中合適的Jenkins,再進行取交集(這個時候就獲取到可以執行該構建任務的Jenkins了),在判斷是否需要經過可選策略,最終得到Jenkins。

圖片

7.4 流控管理&佇列管理

 

排程系統中的的任務接受採用的是佇列的方式實現,當系統請求量達到閥後,系統將不會進入Redis佇列,會將請求持久化至MySQL。後續如果有請求過來,job管理模組會檢查資料庫MySQL中是否有請求,如果有請求,會將請求放入Redis佇列,如果沒有請求就會將當前請求放入Redis佇列,具體流程如下:

圖片

其中基於Redis實現的訊息佇列的時序圖如下:

圖片

7.5 回撥中心

該模組主要是監控任務的狀態,當任務開始執行、中斷執行、執行成功、執行失敗的時候進行通知業務並儲存資料,用於儲存構建記錄,方便後續資料的統計,用來完成資料的視覺化。

八、實施效果

目前該系統已經投入生產環境執行,Jenkins任務已採用排程系統進行排程執行,執行穩定,執行效果。

圖片

 

圖片

 

九、後續展望

隨著vivo Jenkins 排程系統的功能慢慢完善,Jenkins的機器也越來越多,目前還大多數執行在虛擬機器器上,從資源利用率和業務釋出效率來看,未來的業務釋出形態將會是以容器為主。目前公司也在大力發展k8s的容器生態建設,

所以我們希望將Jenkins工具後期進行容器化、池化,在提高資源利用率和釋出效率的同時也可以為使用者提供可靠的、簡潔的、穩定排程執行。