賴正華
(中移信息技術(shù)有限公司,廣東 深圳 518048)
現(xiàn)在很多的業(yè)務(wù)系統(tǒng)引用微服務(wù)化的思想,將業(yè)務(wù)系統(tǒng)的功能在應(yīng)用程序?qū)崿F(xiàn)上進(jìn)行解耦處理:每個(gè)功能由單獨(dú)的程序模塊來提供,再將各個(gè)程序模塊,利用消息隊(duì)列的形式串聯(lián)起來。假如應(yīng)用程序分為了前置程序、業(yè)務(wù)處理程序。前置程序接受請(qǐng)求后,通過MQ消息中間件將消息通過點(diǎn)對(duì)點(diǎn)的方式分發(fā)到業(yè)務(wù)處理程序。業(yè)務(wù)處理程序根據(jù)不同的請(qǐng)求渠道以及用戶歸屬省等因素,可將消息引流到不同的業(yè)務(wù)處理程序去消費(fèi)消息,比如對(duì)業(yè)務(wù)量很大的省份或者渠道,由A主機(jī)單獨(dú)提供服務(wù),對(duì)業(yè)務(wù)量小的省份或者渠道可以多個(gè)省或渠道共享一臺(tái)主機(jī)消費(fèi)消息,利用MQ的點(diǎn)對(duì)點(diǎn)消息,實(shí)現(xiàn)了流量的分流。因此,在代碼打包編譯時(shí),需要對(duì)不同的業(yè)務(wù)處理節(jié)點(diǎn)標(biāo)識(shí)不同的appcode,每一個(gè)tomcat運(yùn)行單獨(dú)標(biāo)識(shí)appcode的業(yè)務(wù)處理war包程序,這樣便可實(shí)現(xiàn)點(diǎn)對(duì)點(diǎn)消息消費(fèi)。由于承載的是全網(wǎng)的業(yè)務(wù),部署的服務(wù)器數(shù)量和tomcat容器數(shù)量會(huì)達(dá)到數(shù)十個(gè),且隨著業(yè)務(wù)規(guī)模的發(fā)展,服務(wù)器的數(shù)量一直在增長(zhǎng),因此在每次進(jìn)行變更上線時(shí),運(yùn)維人員的工作強(qiáng)度和壓力越來越大。且系統(tǒng)屬于實(shí)時(shí)交易類系統(tǒng),為在全球漫游的用戶提供無間斷的服務(wù),對(duì)系統(tǒng)變更上線提出了高要求:需要不間斷提供服務(wù)且快速又準(zhǔn)確地完成變更上線操作。本文將對(duì)這種業(yè)務(wù)場(chǎng)景的系統(tǒng)上線方式展開研究。
目前行業(yè)內(nèi)用于自動(dòng)化上線的開源工具有Ansible、Saltstack、Jenkins等。
Ansible是一種基于Paramiko開發(fā)的自動(dòng)化運(yùn)維工具。通過SSH協(xié)議與遠(yuǎn)程主機(jī)相結(jié)合,并以模塊化的方式實(shí)現(xiàn)批量部署、自動(dòng)化執(zhí)行命令等功能?;贏nsible可以實(shí)現(xiàn)批量的操作,比如對(duì)批量的tomcat進(jìn)行停啟操作,對(duì)批量的tomcat下的webapp目錄替換相同的war包程序,但Ansible不適合這種業(yè)務(wù)場(chǎng)景:系統(tǒng)涉及有數(shù)十個(gè)tomcat節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)運(yùn)行的war包程序不同,因此Ansible工具無法實(shí)現(xiàn)對(duì)這數(shù)十個(gè)運(yùn)行不同war程序的tomcat進(jìn)行批量的操作。
Saltstack也是類似的情況,只能對(duì)相同的命令執(zhí)行批量操作,不適合這種不同主機(jī)的操作命令不同、變更上線的程序版本不同且涉及的主機(jī)數(shù)量眾多的業(yè)務(wù)場(chǎng)景。
Jenkins是一款開源CI&CD軟件,用于自動(dòng)化各種任務(wù),包括構(gòu)建、測(cè)試和部署軟件[1]。本文基于Jenkins的Publish Over SSH插件實(shí)現(xiàn)將上線程序從Jenkins服務(wù)器分發(fā)到應(yīng)用主機(jī),并執(zhí)行shell腳本實(shí)現(xiàn)變更上線的流水線操作:應(yīng)用程序備份、停tomcat進(jìn)程、刪原來的程序文件、移新版本程序文件到指定目錄、更改配置文件、啟動(dòng)tomcat進(jìn)程、檢查進(jìn)程是否啟動(dòng)等操作。
本文將基于Jenkins設(shè)計(jì)一種方案,可實(shí)現(xiàn)實(shí)時(shí)交易系統(tǒng)的不中斷上線。首先,若需要實(shí)現(xiàn)業(yè)務(wù)系統(tǒng)的不中斷上線,需要對(duì)業(yè)務(wù)系統(tǒng)的部署進(jìn)行重新設(shè)計(jì),原來的業(yè)務(wù)系統(tǒng)由前置程序?qū)懴⒌较㈥?duì)列中,業(yè)務(wù)處理節(jié)點(diǎn)從MQ服務(wù)器監(jiān)聽并拉取消息處理,而且是采用點(diǎn)對(duì)點(diǎn)的消息隊(duì)列模式,如果未采用主備的模式部署,那么在變更上線時(shí),需要重啟tomcat操作,消息沒有消費(fèi)者來消費(fèi),此時(shí)會(huì)導(dǎo)致業(yè)務(wù)中斷?,F(xiàn)在改為部署主備式的業(yè)務(wù)處理,打包編譯時(shí),對(duì)war包加上標(biāo)簽appcodeA和appcodeB,兩個(gè)業(yè)務(wù)處理節(jié)點(diǎn)都監(jiān)控消息隊(duì)列A,都可以從這個(gè)隊(duì)列拉取消息處理,兩個(gè)tomcat都可以監(jiān)聽這個(gè)消息隊(duì)列A,實(shí)行搶消息的方式去消費(fèi)消息。其他的業(yè)務(wù)處理節(jié)點(diǎn)也做類似的部署調(diào)整,這樣業(yè)務(wù)系統(tǒng)在MQ的作用下,實(shí)現(xiàn)了分布式的部署,且每個(gè)業(yè)務(wù)處理、前置程序都具備了主備節(jié)點(diǎn),如圖1所示。這樣在日常的變更操作時(shí),如果對(duì)主節(jié)點(diǎn)進(jìn)行重啟操作的時(shí)候,消息隊(duì)列A的消息可以被備tomcat節(jié)點(diǎn)進(jìn)行消費(fèi),正常提供對(duì)外訪問,實(shí)現(xiàn)業(yè)務(wù)不中斷。但隨之帶來的是tomcat數(shù)量的翻倍。
圖1 業(yè)務(wù)應(yīng)用分布式化部署
在對(duì)應(yīng)用系統(tǒng)進(jìn)行了部署優(yōu)化后,在Jenkins管理界面,添加遠(yuǎn)程主機(jī);然后對(duì)每一個(gè)tomcat配置一個(gè)job任務(wù),在job任務(wù)的配置界面編寫遠(yuǎn)程執(zhí)行的shell命令。按照上線操作的流水操作編寫shell命令。當(dāng)觸發(fā)這個(gè)任務(wù)時(shí),能單獨(dú)完成這個(gè)tomcat節(jié)點(diǎn)的進(jìn)程啟停、文件備份與換新等操作。
在對(duì)所有的主節(jié)點(diǎn)配置完成job任務(wù)后,將所有的主節(jié)點(diǎn)job加入到一個(gè)新的job中,如圖2所示。
圖2 主備節(jié)點(diǎn)job列表
同理對(duì)所有的備節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)配置一個(gè)job任務(wù),在job任務(wù)中配置對(duì)應(yīng)的shell命令,實(shí)現(xiàn)各個(gè)節(jié)點(diǎn)可以個(gè)性化地操作tomcat。將所有的備節(jié)點(diǎn)job加入到新的一個(gè)job中,任命為BUSI-BACK,如圖2所示。這樣便可以將所有的主節(jié)點(diǎn)歸納到一個(gè)job,所有的備節(jié)點(diǎn)歸納到另一個(gè)job,可實(shí)現(xiàn)并發(fā)操作。
在上線變更操作時(shí),依次對(duì)主節(jié)點(diǎn)的控制任務(wù)BUSIMAIN觸發(fā)工程構(gòu)建操作,如圖3所示,此時(shí)所有主節(jié)點(diǎn)的tomcat會(huì)并發(fā)的進(jìn)行上線操作,極大地縮短上線變更時(shí)間。此時(shí),備節(jié)點(diǎn)的tomcat從消息隊(duì)列讀取消息進(jìn)行消息處理,對(duì)外表現(xiàn)為業(yè)務(wù)未中斷。在主節(jié)點(diǎn)完成上線變更操作后,再對(duì)備節(jié)點(diǎn)進(jìn)行工程構(gòu)建操作,此時(shí)主節(jié)點(diǎn)的所有tomcat從消息隊(duì)列拉取消息進(jìn)行業(yè)務(wù)處理,對(duì)外表現(xiàn)也是業(yè)務(wù)不中斷。
圖3 主備節(jié)點(diǎn)的控制job列表
首先在部署主機(jī)運(yùn)行Jenkins服務(wù):nohup java-jar jenkins.war--httpPort=8080&。在瀏覽器輸入Jenkins的訪問界面:http://localhost:8080,按照提示輸入密鑰后即可進(jìn)入Jenkins服務(wù)的管理界面[2]。
Jenkins具有可伸縮的插件機(jī)制,集成人員可以很方便地進(jìn)行配置的自主性選擇,根據(jù)自己所需要的插件進(jìn)行安裝、刪除和添加。進(jìn)入到首界面的系統(tǒng)管理界面后,再進(jìn)入到插件管理界面,本文的方案需要安裝Publish Over SSH插件包,在生產(chǎn)環(huán)境需要采用離線安裝的方式[3]。
接下來是新建job的工作,即如圖2所示的BN-S-001即為一個(gè)獨(dú)立的job。在界面中進(jìn)行配置和shell命令編寫工作。在配置界面中,需要配置目標(biāo)主機(jī)的信息,即job的名稱,需要配置上線文件的source files的正則表達(dá)式,在本文中配置為*,即匹配任何的文件,本文中默認(rèn)所有的主節(jié)點(diǎn)命名為BN-S-00*,備節(jié)點(diǎn)則命名為BN-S-10*。在本文中將實(shí)現(xiàn)對(duì)一個(gè)tomcat進(jìn)行如下流水線式的操作:備份原webapps目錄下的程序文件、kill tomcat進(jìn)程、休眠一段時(shí)間待tomcat完成上一筆業(yè)務(wù)、再次kill tomcat進(jìn)程、刪除原webapps目錄下的所有war包程序和war包解壓后的程序文件、刪除配置文件、將要上線的新程序war包文件拷貝到webapps目錄下、拷貝新的配置文件到配置目錄下、啟動(dòng)tomcat進(jìn)程。每一個(gè)tomcat都需要進(jìn)行類似的流水操作。
實(shí)現(xiàn)的shell腳本如下:
在每個(gè)job中都完成上述的job配置,以及把shell命令拷貝到每個(gè)job的command窗口中便可完成配置[4]。配置完成后的效果如圖2所示。
將所有的BN-S-00*開頭的job作為主節(jié)點(diǎn)編排在BUSIMAIN這個(gè)job中,將BN-S-10*開頭的job編排到BUSIBACK這個(gè)job中作為備節(jié)點(diǎn)。對(duì)BUSI-MAIN這個(gè)job點(diǎn)擊構(gòu)建操作,即可觸發(fā)這個(gè)job下的所有主節(jié)點(diǎn)job進(jìn)行并發(fā)的構(gòu)建,所有的job并發(fā)的執(zhí)行shell命令,完成流水線式的操作。在對(duì)BUSI-MAIN這個(gè)job完成構(gòu)建的時(shí)刻,tomcat是不提供對(duì)外服務(wù)的,此時(shí)作為備節(jié)點(diǎn)的BN-S-10*節(jié)點(diǎn)均正常對(duì)外提供服務(wù)。在BUSI-MAIN這個(gè)job完成構(gòu)建后,即完成了新版本上線后,再對(duì)BUSI-BACK這個(gè)job進(jìn)行相同的操作,此時(shí)主節(jié)點(diǎn)對(duì)外提供服務(wù),如圖4所示。經(jīng)過實(shí)測(cè),單人對(duì)55個(gè)tomcat進(jìn)行正常的變更上線操作,需要花費(fèi)的時(shí)間在2個(gè)小時(shí)以上,但利用本文的方案實(shí)現(xiàn),可在5分鐘內(nèi)完成上線工作,不中斷業(yè)務(wù)系統(tǒng)的服務(wù),且可大大降低人為錯(cuò)誤操作的風(fēng)險(xiǎn)。
圖4 測(cè)試結(jié)果
本文針對(duì)實(shí)時(shí)交易業(yè)務(wù)系統(tǒng)在進(jìn)行不中斷業(yè)務(wù)變更上線提出了一種解決方案。適用的業(yè)務(wù)場(chǎng)景為每個(gè)tomcat或者其他容器所承載的應(yīng)用程序版本不同,但又需要批量上線的情況。利用Jenkins可定制化地實(shí)現(xiàn)每個(gè)tomcat或容器實(shí)現(xiàn)不同的流水線操作,最終進(jìn)行搭積木式的組合調(diào)用。本文結(jié)合業(yè)務(wù)系統(tǒng)的部署情況,對(duì)部署進(jìn)行了優(yōu)化改進(jìn),以實(shí)現(xiàn)變更上線過程不中斷業(yè)務(wù)的功能[5]。經(jīng)過實(shí)測(cè),該方案能極大提高上線的效率和準(zhǔn)確度。