傳(chuan)統的流(liu)水(shui)線引擎(qing)方(fang)案,主(zhu)要(yao)是(shi)基于(yu)Mysql定(ding)時(shi)任(ren)務(wu)(wu)(wu)表或開源(yuan)組件如Jenkins流(liu)水(shui)線引擎(qing)來(lai)研發(fa)。在流(liu)量稍(shao)高(gao)(gao)或io消耗(hao)稍(shao)大時(shi)容(rong)易出現卡(ka)頓、運行慢問題(ti);且由于(yu)定(ding)時(shi)任(ren)務(wu)(wu)(wu)和(he)Jenkins都是(shi)有狀態服務(wu)(wu)(wu),無法實(shi)現節點橫向(xiang)擴容(rong);最后jenkins引擎(qing)需要(yao)有專業技術(shu)團隊來(lai)部署和(he)維護(hu),也提高(gao)(gao)了(le)維護(hu)行的難度(du)。這里(li)通過基于(yu)Redis隊列實(shi)現的流(liu)水(shui)線任(ren)務(wu)(wu)(wu)調度(du)引擎(qing),能(neng)毫(hao)秒級實(shi)現任(ren)務(wu)(wu)(wu)間的狀態流(liu)轉,具備較(jiao)高(gao)(gao)的調度(du)性能(neng)。
基于(yu)Redis隊列(lie)實(shi)現的任務調度引(yin)擎,其中(zhong)調度核心之一(yi)由4個算(suan)(suan)法組成,即(ji):任務入隊Push算(suan)(suan)法、任務出(chu)隊Poll算(suan)(suan)法、任務執行算(suan)(suan)法和任務失(shi)敗重(zhong)試算(suan)(suan)法。
一、任務入隊Push算法
任(ren)務入(ru)隊Push算法主要邏輯是基于Redis有序隊列(lie)來(lai)來(lai)按執行(xing)存(cun)儲能(neng)代(dai)表任(ren)務信息唯一性的Hash值,目的是保(bao)證流水線執行(xing)任(ren)務能(neng)按照編排順序串行(xing)或并行(xing)。
實現流程圖如下:

1、對任務信息msg進行hash算法得到任務的hash值,再調用Zrank函數判斷該hash值是否存在。如果不存在,則按步驟2執行;如果存在,那么執行步驟3。
2、給msg初始化待執行數據,開啟事務,先將任務信息msg存儲到hash表中,再根據系統時間和任務信息msg里的延遲時間調用得分算法,計算出當前任務對應的分數值,最后調用Zadd函數將當前任務hash值加入到任務隊列中。
3、取(qu)msg里的延遲時間(jian),調用得分算法,計(ji)算出任務最新的分數,然后調用Zadd函數更新該任務hash值的執行順(shun)序。
二、任務出隊Poll算法
任務(wu)出隊(dui)Poll算法,由(you)服務(wu)內定(ding)時器按指定(ding)頻率調用,默認是(shi)(shi)50ms間(jian)隔時間(jian)。主要邏輯是(shi)(shi)調用ZrangeByScore函數獲取(qu)一條任務(wu)hash值,然后發送執行這個任務(wu)的(de)事(shi)件。

1、檢查當前線程池是否有空余線程可調度,有則繼續,無則返回。
2、調用ZrangeByScore函數,獲取任務隊列中得分最小的任務hash值。
3、調用SetNx函數獲取分布式鎖,通過任務hash值調用Hget函數獲取任務信息msg。
4、調用Zrem函數將任務hash值從任務隊列中移除,即表示任務出隊。
5、調用Hset函數將修改執行次數的任務信息msg更新到hash表。
6、將任(ren)務信息(xi)msg包裝成任(ren)務事件event發(fa)送(song),即讓(rang)任(ren)務執行(xing)器監聽事件,并調用(yong)后面(mian)的(de)任(ren)務執行(xing)算(suan)法執行(xing)。
三、任務執行算法
任務執行算(suan)法,為了(le)保持擴展性,內置了(le)流(liu)水線(xian)內任務事件接(jie)近有22種狀(zhuang)態(tai)(tai),諸(zhu)如開始StartPipeline、CancelStage等。此算(suan)法核心難(nan)點是(shi)較(jiao)多狀(zhuang)態(tai)(tai)機和策略模(mo)式設(she)計。

1、執行器監聽到任務出隊算法的任務事件event后,會利用java反射原理得到對應event的事件處理器handler。
2、再(zai)通(tong)過線程池(chi)異步執行handler.invoke(event)方(fang)法,即執行業務(wu)的真正邏(luo)輯(ji)。handler內(nei)部除(chu)了(le)自身業務(wu)邏(luo)輯(ji)需要用(yong)戶自己定義外,其(qi)他復(fu)雜(za)(za)的狀態遞歸(gui)轉(zhuan)化為內(nei)置邏(luo)輯(ji),可極大提高devops平臺研發(fa)人(ren)員生產力。研發(fa)人(ren)員只需關(guan)心(xin)每種事件(jian)event需要做的業務(wu)邏(luo)輯(ji),而(er)不用(yong)考慮復(fu)雜(za)(za)的狀態轉(zhuan)換。
四、任務失敗重試算法
任(ren)務(wu)失敗(bai)重試算(suan)法,為了(le)提(ti)高容錯(cuo)性,諸如網(wang)絡抖動(dong)造成(cheng)的(de)任(ren)務(wu)失敗(bai)等異(yi)常,此算(suan)法解(jie)決(jue)的(de)是這(zhe)種可(ke)通過(guo)自(zi)動(dong)重試來解(jie)決(jue)的(de)異(yi)常事件(jian),進而提(ti)高任(ren)務(wu)執行成(cheng)功率。

1、有個前提:失敗任務會有失敗任務隊列來存儲任務hash值。首先,調用Zrange函數從失敗任務隊列中取出任務hash值集合。
2、遍歷任務hash值集合,對每個任務hash,調用Hget函數獲取任務信息msg。
3、將(jiang)任(ren)(ren)務(wu)(wu)信(xin)息msg中執行(xing)次數和最(zui)大可執行(xing)次數對比,如果超過最(zui)大可執行(xing)次數,則調用(yong)Zrem函數從失敗任(ren)(ren)務(wu)(wu)隊(dui)(dui)列中移除(chu)任(ren)(ren)務(wu)(wu)hash值;如果不(bu)超過,則開啟事務(wu)(wu),給失敗任(ren)(ren)務(wu)(wu)調用(yong)score算法打分,再調用(yong)Zadd函數將(jiang)該任(ren)(ren)務(wu)(wu)hash值加入(ru)到正常的任(ren)(ren)務(wu)(wu)隊(dui)(dui)列中。