陳顯爐,李建文,于凱
深圳云天勵(lì)飛技術(shù)股份有限公司,廣東深圳,518000
軟件版本管理是軟件研發(fā)過(guò)程中重要的環(huán)節(jié),是指對(duì)軟件開(kāi)發(fā)過(guò)程中產(chǎn)生的代碼和文檔進(jìn)行版本控制,以保證開(kāi)發(fā)的代碼、文檔能夠正確發(fā)布、分發(fā)和維護(hù)。近年來(lái),國(guó)內(nèi)外很多研究人員和企業(yè)都在嘗試基于軟件版本管理系統(tǒng)實(shí)現(xiàn)分布式版本管理,雖然基于開(kāi)源項(xiàng)目開(kāi)發(fā)的分布式軟件版本管理系統(tǒng)具有低成本、易維護(hù)和可擴(kuò)展等優(yōu)點(diǎn),但這些系統(tǒng)仍然存在一些問(wèn)題,例如系統(tǒng)部署的調(diào)整、系統(tǒng)功能和性能的升級(jí)等,嚴(yán)重影響系統(tǒng)運(yùn)行的穩(wěn)定性[1]。因此,系統(tǒng)組件的軟件版本的維護(hù)操作在實(shí)際的系統(tǒng)中是一個(gè)不可避免的情況,甚至是經(jīng)常出現(xiàn)的情況。設(shè)計(jì)實(shí)現(xiàn)適用于分布式集群系統(tǒng)中的軟件版本分發(fā)管理系統(tǒng),對(duì)于系統(tǒng)的可維護(hù)性、穩(wěn)定性、運(yùn)行的可靠性等指標(biāo)具有重大的意義和價(jià)值。
常見(jiàn)的版本分發(fā)系統(tǒng)在使用中存在協(xié)同性差的問(wèn)題,升級(jí)測(cè)試比較難協(xié)調(diào)統(tǒng)一進(jìn)行,在出現(xiàn)問(wèn)題后,也比較難協(xié)調(diào)統(tǒng)一地進(jìn)行版本的回退或其他能暫時(shí)規(guī)避問(wèn)題的操作等,例如在版本發(fā)布后,如果遇到某些問(wèn)題,需要回退到上一個(gè)版本進(jìn)行測(cè)試,又或者是新版本發(fā)布后遇到問(wèn)題,需要回退到上一個(gè)版本進(jìn)行解決。這些功能在傳統(tǒng)的分發(fā)系統(tǒng)中并不存在,因此在實(shí)際工作中往往需要手動(dòng)進(jìn)行相關(guān)操作,既降低了工作效率,也增加了錯(cuò)誤率[2]。
常見(jiàn)的分發(fā)系統(tǒng)的功能模塊基本是針對(duì)單個(gè)產(chǎn)品進(jìn)行開(kāi)發(fā)的,對(duì)其他產(chǎn)品不一定都能夠支持。軟件產(chǎn)品的版本越來(lái)越豐富,但由于不同平臺(tái)、不同開(kāi)發(fā)語(yǔ)言等原因,不同用戶(hù)在使用同一款產(chǎn)品時(shí)會(huì)遇到各種各樣的問(wèn)題,這就導(dǎo)致軟件產(chǎn)品難以適應(yīng)各種用戶(hù)場(chǎng)景[3]。因?yàn)椴煌浖a(chǎn)品的特性不同,在功能上有可能存在較大差異,這樣就可能會(huì)出現(xiàn)版本兼容的問(wèn)題。并且現(xiàn)有的版本分發(fā)系統(tǒng)都是以本地為中心的,所以存在一個(gè)問(wèn)題,就是當(dāng)本地版本發(fā)生變更時(shí),無(wú)法在各個(gè)渠道中及時(shí)同步。
歷史可回溯性信息是軟件產(chǎn)品版本管理系統(tǒng)的重要組成部分,通過(guò)歷史可回溯性信息可以幫助我們發(fā)現(xiàn)問(wèn)題、定位問(wèn)題,并及時(shí)進(jìn)行修復(fù)。但目前的常見(jiàn)分發(fā)系統(tǒng)中,歷史可回溯性信息并不完善,甚至沒(méi)有。一方面是因?yàn)榘姹痉职l(fā)系統(tǒng)的歷史數(shù)據(jù)都存儲(chǔ)在本地服務(wù)器上,如果需要查看歷史數(shù)據(jù)就需要訪問(wèn)本地服務(wù)器,如果本地服務(wù)器沒(méi)有歷史數(shù)據(jù),就無(wú)法查看;另一方面是因?yàn)榘姹痉职l(fā)系統(tǒng)大多都是采用單機(jī)架構(gòu)設(shè)計(jì)的,不具備分布式能力。因此在后續(xù)的版本管理中,需要在分發(fā)系統(tǒng)中增加歷史可回溯性信息,以便查看各個(gè)分支版本之間的關(guān)系[4]。
2.1.1 版本元信息存儲(chǔ)
對(duì)軟件版本元信息進(jìn)行存儲(chǔ),一方面可以為軟件版本管理提供有效的數(shù)據(jù)支持,另一方面也是對(duì)版本元信息進(jìn)行有效存儲(chǔ)和管理的必要手段。通過(guò)對(duì)軟件版本元信息進(jìn)行存儲(chǔ),可以保證不同用戶(hù)對(duì)版本信息的訪問(wèn)需求,同時(shí)也可以減少對(duì)版本管理系統(tǒng)的維護(hù)工作。基于這一思路,本文設(shè)計(jì)了如圖1所示的版本元信息的存儲(chǔ)結(jié)構(gòu),在該結(jié)構(gòu)設(shè)計(jì)中,實(shí)現(xiàn)了分層的元信息存儲(chǔ)。其中版本分為大版本和組件版本,大版本由組件版本構(gòu)成。大版本的元信息存儲(chǔ)組件的版本的元信息的鏈接,以保持?jǐn)?shù)據(jù)的一致性和節(jié)省存儲(chǔ)空間。每個(gè)大版本與小版本之間存在網(wǎng)狀映射關(guān)系,具體而言,同一個(gè)組件版本可由多個(gè)大版本共享,每個(gè)大版本中的組件版本可來(lái)自批次版本。大版本與組件版本之間,通過(guò)元數(shù)據(jù)映射組成靈活的版本組合[5]。
圖1 分層次的版本元信息的存儲(chǔ)和映射結(jié)構(gòu)
2.1.2 版本文件數(shù)據(jù)存儲(chǔ)
數(shù)據(jù)存儲(chǔ)是軟件版本分發(fā)管理系統(tǒng)的核心,也是整個(gè)系統(tǒng)的核心功能。通過(guò)對(duì)已有版本數(shù)據(jù)存儲(chǔ)模式的分析,本文提出了如圖2所示的版本文件數(shù)據(jù)存儲(chǔ)結(jié)構(gòu),主要是指版本元信息的格式與數(shù)據(jù)映射關(guān)系。組件版本的元信息包括組件版本號(hào),這是隨著組件的迭代發(fā)布依次遞增的版本號(hào),包括構(gòu)建的日期及構(gòu)建功能版本等信息,可以判斷出兩個(gè)版本之間的更新關(guān)系。版本的唯一標(biāo)識(shí)號(hào)由唯一標(biāo)識(shí)生成算法生成,如UUID生成算法。版本的存儲(chǔ)路徑可能是本地文件系統(tǒng),也可能是網(wǎng)絡(luò)地址。
圖2 版本的元信息格式和數(shù)據(jù)的存儲(chǔ)
2.1.3 版本的統(tǒng)一結(jié)構(gòu)規(guī)范
版本的統(tǒng)一結(jié)構(gòu)規(guī)范規(guī)定不管是組件版本還是大版本的格式標(biāo)準(zhǔn),為了能夠按統(tǒng)一的框架和流程來(lái)執(zhí)行版本的部署、升級(jí),統(tǒng)一規(guī)定所有組件版本必須按如下格式構(gòu)成,如圖3所示[6]。
2.1.4 版本的兼容性檢測(cè)用例庫(kù)
兼容性檢測(cè)用例庫(kù)的作用是實(shí)現(xiàn)自動(dòng)化的版本兼容性檢查,以實(shí)現(xiàn)自動(dòng)化的版本升級(jí)/回溯的驗(yàn)證等。為此,它需要管理各個(gè)版本的功能關(guān)系對(duì)驗(yàn)證這些關(guān)系所對(duì)應(yīng)的用例。為了實(shí)現(xiàn)以上這些需求,本文提出兼容性檢測(cè)用例庫(kù)的結(jié)構(gòu)。一個(gè)兼容性檢測(cè)用例涉及以下三個(gè)元素:調(diào)用發(fā)起組件、調(diào)用接收組件、調(diào)用的輸入/輸出。針對(duì)以上三個(gè)驗(yàn)證要求,本文提出了一種有向多重圖的存儲(chǔ)結(jié)構(gòu)用于存儲(chǔ)兼容性用例。多重有向圖存儲(chǔ)的方式如下:圖中的每一個(gè)節(jié)點(diǎn)為系統(tǒng)中的一個(gè)組件類(lèi)型,每一個(gè)組件類(lèi)型在這個(gè)多重有向圖中都存在一個(gè)節(jié)點(diǎn)。
2.1.5 版本的回溯信息數(shù)據(jù)庫(kù)
版本的回溯信息數(shù)據(jù)庫(kù)的目標(biāo)是當(dāng)某個(gè)組件需要進(jìn)行版本回溯回退的時(shí)候,可以快速得到關(guān)聯(lián)組件的回溯信息,即關(guān)聯(lián)的組件的版本是否需要進(jìn)行回溯及回溯到哪個(gè)版本?;厮菪畔?kù)由兩級(jí)Map結(jié)構(gòu)構(gòu)成。第一級(jí)Map,其鍵值為組件的識(shí)別符號(hào)對(duì),假設(shè)在系統(tǒng)中,某兩個(gè)組件的標(biāo)識(shí)號(hào)為ID(x)、ID(y),則在第一級(jí)Map中存在鍵值為Key(ID(x),ID(y))的Map項(xiàng)。如果不存在,則創(chuàng)建。第二級(jí)Map為某兩個(gè)組件的兩兩之間的兼容性檢測(cè)結(jié)果。
版本元信息的傳播機(jī)制的目標(biāo)是在網(wǎng)絡(luò)傳遞版本元數(shù)據(jù)信息,其網(wǎng)絡(luò)中的每一個(gè)節(jié)點(diǎn)都掌握當(dāng)前最新版本信息,其包含如下過(guò)程。
第一,由版本發(fā)布者發(fā)布新的版本的元信息及其相關(guān)的數(shù)據(jù)文件和其他必要的信息內(nèi)容,設(shè)這些被注入版本信息的節(jié)點(diǎn)為Node(update)。
第二,在開(kāi)發(fā)階段,為了節(jié)約帶寬,Node(update)僅抽取版本信息中的版本號(hào)信息向外廣播傳遞過(guò)程。
第三,Node(update)為源節(jié)點(diǎn),它在自己的所有網(wǎng)絡(luò)接口上廣播新的版本號(hào)消息。版本號(hào)消息包括如圖4所示的內(nèi)容。
圖4 版本元信息傳播格式
中間節(jié)點(diǎn)收到此消息時(shí),進(jìn)行以下判斷:①如果曾經(jīng)收到過(guò)此類(lèi)消息(組件號(hào)和版本號(hào)相同),直接結(jié)束;②如果沒(méi)有收到過(guò),首先會(huì)在自己的版本元信息存儲(chǔ)庫(kù)中進(jìn)行記錄;③把消息體中的TTL減1,如果結(jié)果為0,則不轉(zhuǎn)發(fā),直接結(jié)束;④如果TTL不為0,則中間節(jié)點(diǎn)向這條消息進(jìn)入的網(wǎng)絡(luò)接口以外的網(wǎng)絡(luò)接口進(jìn)行轉(zhuǎn)發(fā)。
消息按此機(jī)制在網(wǎng)絡(luò)傳播,直到所有節(jié)點(diǎn)都收到或消息的TTL減為0為止。當(dāng)以上過(guò)程完全結(jié)束后,網(wǎng)絡(luò)中的每個(gè)節(jié)點(diǎn)都知道集群中每個(gè)軟件的組件的最新版本是什么,及節(jié)點(diǎn)自己是否有這些版本的本地拷貝。同時(shí),以比較低的頻度,每個(gè)節(jié)點(diǎn)會(huì)向網(wǎng)絡(luò)中廣播自己掌握的所有組件的版本號(hào)信息,消息的傳輸過(guò)程與新注入的版本信息的傳輸過(guò)程基本一致。
第一,每個(gè)節(jié)點(diǎn)根據(jù)自己掌握的分層次的版本的存儲(chǔ)部分所描述的信息,決定向網(wǎng)絡(luò)中發(fā)起某組件某版本的數(shù)據(jù)傳輸請(qǐng)求,設(shè)置傳輸請(qǐng)求所對(duì)應(yīng)的數(shù)據(jù)為Data(Model(x)Version(y))。
第二,網(wǎng)絡(luò)中,只有少數(shù)節(jié)點(diǎn)擁有Da t a(Model(x)Version(y))的本地版本,所以大部分節(jié)點(diǎn)都會(huì)發(fā)起傳輸?shù)恼?qǐng)求操作。
第三,所有節(jié)點(diǎn)按統(tǒng)一約定的規(guī)則(如按固定大小切塊),對(duì)Data(Model(x)Version(y))進(jìn)行切塊,設(shè)得到的塊數(shù)為(1,m), 并將(1,m)進(jìn)行批次劃分,設(shè)為(1,n),則每批次為m/n塊數(shù)據(jù)。
第四,對(duì)于每一個(gè)網(wǎng)絡(luò)中的節(jié)點(diǎn),按批次發(fā)起傳輸,一次把當(dāng)前批次的m/n塊同時(shí)向外發(fā)送請(qǐng)求,請(qǐng)求有這些數(shù)據(jù)塊的節(jié)點(diǎn)回應(yīng)它的請(qǐng)求。發(fā)起請(qǐng)求前,根據(jù)分層次的版本的存儲(chǔ)中掌握的信息,根據(jù)一次的時(shí)間退避。
第五,每個(gè)節(jié)點(diǎn)獨(dú)立重復(fù)進(jìn)行3和4步驟中所述的機(jī)制,直到版本中的所有數(shù)據(jù)都傳輸完成為止。
第一,檢測(cè)當(dāng)前節(jié)點(diǎn)所有組件的待升級(jí)的版本,確定當(dāng)前批次升級(jí)所涉及的組件版本及具體的版本號(hào)。
第二,維護(hù)版本的元數(shù)據(jù)信息,創(chuàng)建一個(gè)新的大版本號(hào),生成大版本號(hào)的一個(gè)唯一的標(biāo)識(shí)號(hào),根據(jù)待升級(jí)組件的版本號(hào)、不升級(jí)組件的版本號(hào)等信息,維護(hù)當(dāng)前版本號(hào)的組件版本映射信息。
第三,進(jìn)行備份部署,將待升級(jí)的版本通過(guò)版本中的config/update/deloy等標(biāo)準(zhǔn)化腳本部署為一個(gè)與當(dāng)前運(yùn)行的版本并行運(yùn)行的一個(gè)復(fù)制運(yùn)行實(shí)例。
第四,在這個(gè)復(fù)制的運(yùn)行實(shí)例上執(zhí)行兼容性測(cè)試用例庫(kù)。
第五,如果通過(guò)兼容性測(cè)試,則進(jìn)行版本的實(shí)際切換,使當(dāng)前的版本實(shí)際上線。同時(shí)在回溯信息數(shù)據(jù)庫(kù)中記錄已經(jīng)完成的兼容性測(cè)試信息。
第六,如果沒(méi)有通過(guò)兼容性測(cè)試,則終止此次升級(jí),并清除復(fù)制兼容性測(cè)試環(huán)境的所有組件實(shí)例,并進(jìn)行相關(guān)的記錄和報(bào)錯(cuò)。
綜上所述,本文所描述的分布式軟件版本分發(fā)管理系統(tǒng),將軟件版本管理過(guò)程從集中式的中心化系統(tǒng)遷移到分布式的無(wú)中心化系統(tǒng),減少了中心化系統(tǒng)對(duì)數(shù)據(jù)安全和效率的影響,提高了數(shù)據(jù)和操作的安全性。