前面幾節(jié)課程中,我們已經(jīng)對(duì)常見(jiàn)的互聯(lián)網(wǎng)技術(shù),代碼編寫規(guī)范有了一定的學(xué)習(xí)和了解。這些技術(shù)以及規(guī)范在我們?nèi)粘5拈_發(fā)中都是經(jīng)常被使用到的。
這些技術(shù)的學(xué)習(xí)最終都是以應(yīng)用為目標(biāo)的,即需要把這些技術(shù)通過(guò)coding、軟件系統(tǒng)的組合(資源、服務(wù))等實(shí)現(xiàn)方式最終應(yīng)用到線上環(huán)境當(dāng)中。
對(duì)于小規(guī)模的開發(fā)團(tuán)隊(duì),因服務(wù)規(guī)模比較小,服務(wù)的部署可能是很簡(jiǎn)單的——手動(dòng)部署代碼成本也可控。但對(duì)于數(shù)十人上百人的開發(fā)團(tuán)隊(duì),大規(guī)模的分布式系統(tǒng)來(lái)說(shuō),原來(lái)簡(jiǎn)單的方式就難以運(yùn)轉(zhuǎn)了。我們急需一套符合軟件工程原理的流程體系,來(lái)保證我們研發(fā)效率、上線服務(wù)質(zhì)量。
今天我將結(jié)合微博平臺(tái)目前的上線流程以及個(gè)人的一些體會(huì),來(lái)介紹一下研發(fā)上線流程體系。
培訓(xùn)大綱:
對(duì)于一個(gè)剛進(jìn)入公司的新同學(xué),肯定有好多問(wèn)題:
作為一個(gè)工程師,日常工作內(nèi)容都包括哪些呢?我是否只要寫代碼就可以了?
日常工作中,都需要與哪些同事打交道呢?
作為一個(gè)系統(tǒng)研發(fā)工程師,我對(duì)日常工作的一個(gè)總結(jié)如下:
主線任務(wù):完成需求開發(fā),推進(jìn)上線
業(yè)務(wù)需求:完成各個(gè)業(yè)務(wù)部門產(chǎn)品需求
改造需求:來(lái)源于部門內(nèi)部技術(shù)方案、整體架構(gòu)升級(jí)、改造需求
支線任務(wù):提供其他的技術(shù)支持
線上系統(tǒng)問(wèn)題跟蹤
產(chǎn)品數(shù)據(jù)分析支持
我們可以看到,一個(gè)工程師日常最主要的任務(wù)即是完成各類需求研發(fā)工作。這部分的工作實(shí)際上包括兩方面的內(nèi)容:
(1)功能研發(fā),也即通常所說(shuō)的寫代碼
(2)推動(dòng)上線部署
上線指的是將工程師開發(fā)的功能推動(dòng)到線上生產(chǎn)環(huán)境中,為系統(tǒng)面向的用戶所使用。
在一些中小企業(yè)中,因面向的用戶總量不大,所需的服務(wù)器也無(wú)需太大,上線的過(guò)程可能會(huì)比較簡(jiǎn)單——開發(fā)工程師完成代碼的編寫后,編譯,測(cè)試,手動(dòng)部署可發(fā)布包到服務(wù)器上重啟即可。
但在大型的互聯(lián)網(wǎng)環(huán)境中,上述簡(jiǎn)單的做法面臨著很多問(wèn)題:
(1)分布式系統(tǒng)環(huán)境復(fù)雜,上線所涉及到的讀寫順序、操作流程更復(fù)雜
(2)同一個(gè)系統(tǒng)可能由多個(gè)工程師維護(hù),代碼的變更涉及到多個(gè)功能、多個(gè)團(tuán)隊(duì)
(3)系統(tǒng)代碼總量大,生命周期長(zhǎng),每一次的變更都有可能帶來(lái)潛在bug以及嚴(yán)重的故障
微博平臺(tái)歷史上也曾發(fā)生過(guò)多次故障。通過(guò)對(duì)故障的分析和總結(jié),我們發(fā)現(xiàn)約80%的故障都來(lái)源于系統(tǒng)變更。即每次上線變更其實(shí)都是隱含著很大的風(fēng)險(xiǎn)性的。
但是,作為互聯(lián)網(wǎng)工程師,我們并不可能因?yàn)樯暇€變更所可能帶來(lái)的風(fēng)險(xiǎn),就不進(jìn)行新功能的研發(fā),停止不前。相反,我們根據(jù)軟件工程的開發(fā)流程原理以及業(yè)界的一些成熟的經(jīng)驗(yàn),結(jié)合我們的業(yè)務(wù)特點(diǎn),以及自身歷史上發(fā)生過(guò)的幾次故障的經(jīng)驗(yàn),總結(jié)設(shè)計(jì)出了我們自己的一套的開發(fā)、上線流程。總的來(lái)說(shuō),我們期望能夠:
(1)按時(shí)、高質(zhì)量交付需求、功能實(shí)現(xiàn)到生產(chǎn)環(huán)境
(2)研發(fā)過(guò)程明確清晰,每一步都是經(jīng)過(guò)充分review的
(3)上線過(guò)程步驟明確,較少運(yùn)維誤操作
(4)出事可操作,always have plan B,即使出問(wèn)題了,我們也可以快速恢復(fù)
(5)對(duì)研發(fā)效率的影響盡可能小
我們的研發(fā)上線流程由多個(gè)步驟組成,需要一步一步完成。對(duì)于我們的研發(fā)工程師來(lái)說(shuō),他需要關(guān)注每一步的:
(1)該步的檢查內(nèi)容
(2)需要提供的明確的產(chǎn)出物
(3)該步相應(yīng)的審查人員
如圖1所示為研發(fā)上線流程的一個(gè)示意圖:
圖1 研發(fā)上線流程示意圖
從圖1中可以看到,整個(gè)研發(fā)流程由多個(gè)步驟組成,每個(gè)步驟都涉及到一個(gè)或多個(gè)人員。
因本節(jié)課更多的關(guān)注在上線部分的推動(dòng)上,所以我們將從開發(fā)完成后開始詳細(xì)介紹:
即代碼評(píng)審,意指待交付的代碼經(jīng)過(guò)除開發(fā)工程師以外的人員進(jìn)行評(píng)審檢查。
Code review的意義在于:
(1)幫助梳理邏輯,從而發(fā)現(xiàn)更好的實(shí)現(xiàn)方式
(2)幫助規(guī)范代碼,保證線上代碼的規(guī)范、質(zhì)量
(3)減少因開發(fā)人員個(gè)人經(jīng)驗(yàn)、疏忽所可能帶來(lái)的bug
開發(fā)人員在提交codereview時(shí)候需要明確寫出相關(guān)代碼變更的需求來(lái)源、實(shí)現(xiàn)方案以及其他的能夠幫助評(píng)審人員快速了解這次變更內(nèi)容的文檔、資料。
當(dāng)然code review本身也是需要一定的規(guī)范制度的:
明確reivew點(diǎn)。reviewer需要從多個(gè)層次進(jìn)行reivew:代碼本身質(zhì)量(編碼風(fēng)格,防御性編程等),代碼功能邏輯實(shí)現(xiàn),現(xiàn)有系統(tǒng)的影響(侵入、耦合、數(shù)據(jù)兼容性等)。需要避免單一角度review。對(duì)于上述的每一個(gè)層次的review,也需要有更細(xì)致的review點(diǎn)。
為了保證待發(fā)布代碼的質(zhì)量,我們?cè)趯?shí)際的工作中,會(huì)將測(cè)試交由單獨(dú)的測(cè)試部門同事負(fù)責(zé)檢測(cè)。測(cè)試的方式和手段也根據(jù)帶發(fā)布的變更不同而不同??偟膩?lái)說(shuō),對(duì)于日常功能變更,只需進(jìn)行新功能測(cè)試已經(jīng)原有功能回歸即可。對(duì)于系統(tǒng)架構(gòu)級(jí)變更,則會(huì)通過(guò)壓測(cè)等衡量系統(tǒng)的負(fù)載情況。
對(duì)于功能測(cè)試來(lái)說(shuō),測(cè)試是對(duì)某個(gè)特性分支進(jìn)行測(cè)試的,即對(duì)每個(gè)測(cè)試提案單獨(dú)測(cè)試。這樣做的目的是避免待上線功能相互影響,提高測(cè)試效率。
引入測(cè)試環(huán)節(jié)的意義在于:
由測(cè)試部門提供專業(yè)、全面的測(cè)試,從而保證測(cè)試的覆蓋度,以及測(cè)試的準(zhǔn)確度
上線申請(qǐng)以及匯總:
上線申請(qǐng)值得是在代碼完成了cr以及通過(guò)了測(cè)試部門的檢驗(yàn)后,需要向上級(jí)主管以及部門上線總調(diào)度人發(fā)送上線申請(qǐng)通知。
上線申請(qǐng)內(nèi)容主要包括本次上線變更內(nèi)容,代碼涉及的功能模塊,設(shè)計(jì)方案,需要上線的服務(wù)器集群,回滾方案等。開發(fā)人員需要明確提供上述的各類信息,以幫助上級(jí)主管、總調(diào)度人知悉本次上線功能以及可能造成的影響。
Code review以及測(cè)試更多的關(guān)注在代碼本身的質(zhì)量上,而業(yè)務(wù)主管的關(guān)注點(diǎn)更多的在于上線方案、變更可能造成的服務(wù)的影響點(diǎn)等問(wèn)題上。
上線申請(qǐng)以及匯總的意義在于:
(1)上線功能的內(nèi)容經(jīng)過(guò)更高一級(jí)的review,從而保證上線服務(wù)的方案經(jīng)過(guò)更全面的review
(2)協(xié)調(diào)跨個(gè)人、跨團(tuán)隊(duì)的上線。如上所述,我們每次上線都不是單獨(dú)某個(gè)人代碼變更,可能涉及到的團(tuán)隊(duì)、功能是多個(gè)以上的。代碼的提交順序,模塊的打包順序,回滾方案等,都需要經(jīng)過(guò)統(tǒng)一的評(píng)估和協(xié)調(diào)。避免出現(xiàn)各自為政,代碼沖突無(wú)人負(fù)責(zé)等問(wèn)題的出現(xiàn)。
(3)上線變更在部門范圍內(nèi)透明。如果出現(xiàn)某個(gè)功能問(wèn)題,可以做到更大范圍的支持幫助。
當(dāng)上線被業(yè)務(wù)主管以及上線總調(diào)度人通過(guò)后,研發(fā)人員可以將自己的特性分支合并到主分支上。并且交由運(yùn)維同學(xué)打包部署。
對(duì)于線上代碼主分支的修改,我們是統(tǒng)一在上線調(diào)度人發(fā)出上線匯總郵件后,才進(jìn)行。目的也是保證線上主干分支在任意時(shí)刻都是production級(jí)的。避免出現(xiàn)從主干分支獲取代碼后,出現(xiàn)不可知bug。
當(dāng)研發(fā)人員將代碼提交完成后,由運(yùn)維同學(xué)負(fù)責(zé)打出可發(fā)布包(docker鏡像)。
運(yùn)維使用沒(méi)有線上真實(shí)請(qǐng)求流量的線上機(jī)器,部署包含新代碼的發(fā)布包,完成操作后由測(cè)試同學(xué)負(fù)責(zé)在該環(huán)境上執(zhí)行測(cè)試用例。
在前面的課程中也已經(jīng)提到了,在線上系統(tǒng)中,應(yīng)用服務(wù)是由web服務(wù)器集群來(lái)提供服務(wù)的,同時(shí)由nginx來(lái)提供主要的負(fù)載均衡以及健康管理。
如圖2所示,線上nginx服務(wù)器會(huì)定時(shí)的向它所維護(hù)的web服務(wù)器發(fā)起健康探測(cè)請(qǐng)求,當(dāng)實(shí)際的web服務(wù)器返回200響應(yīng)時(shí),則nginx認(rèn)為該web服務(wù)器正常工作;相反,如果web服務(wù)器返回的是503響應(yīng)時(shí),則nginx認(rèn)為該web服務(wù)器無(wú)法正常提供服務(wù),nginx將會(huì)把該web服務(wù)器從服務(wù)列表中摘除,后續(xù)請(qǐng)求將不會(huì)打到該web服務(wù)器上。
利用這個(gè)特性,我們可以將線上服務(wù)器從線上環(huán)境中摘除,即讓該服務(wù)器沒(méi)有線上請(qǐng)求。運(yùn)維同學(xué)將部署新的代碼,重啟tomcat服務(wù)進(jìn)程。啟動(dòng)成功后,由測(cè)試對(duì)其進(jìn)行功能測(cè)試,包括本次上線的所有的功能的測(cè)試,以及原測(cè)試用例的回歸。
預(yù)覽驗(yàn)證的意義在于:
(1)使用線上服務(wù)器環(huán)境配置進(jìn)行測(cè)試,所用數(shù)據(jù)都是真實(shí)的線上數(shù)據(jù),避免測(cè)試環(huán)境不一造成的bug遺漏
(2)合并后代碼的測(cè)試,避免合并代碼過(guò)程中造成的沖突修改引入不可知bug
預(yù)覽測(cè)試通過(guò)后,運(yùn)維同學(xué)會(huì)將線上流量重新導(dǎo)到預(yù)覽機(jī)器上。此時(shí),預(yù)覽機(jī)器部署的新代碼、配置,將經(jīng)受線上真實(shí)流量的檢驗(yàn)。
線上流量是最好的檢驗(yàn)環(huán)境。qa受限于測(cè)試用例覆蓋度的影響,可能無(wú)法做到所有代碼分支都檢測(cè)到,所以我們?cè)诰€上服務(wù)器中引入真實(shí)流量用以檢驗(yàn)代碼的功能的正確性以及對(duì)原有服務(wù)是否有明顯的影響。
我們通常通過(guò)對(duì)訪問(wèn)日志統(tǒng)計(jì)、錯(cuò)誤日志以及監(jiān)控系統(tǒng)的觀察來(lái)判斷變更是否符合要求。
完成上述的上線步驟后,運(yùn)維可以通過(guò)發(fā)布系統(tǒng),將待發(fā)布的代碼推送到所有線上應(yīng)用服務(wù)器上,完成本次系統(tǒng)的變更操作。
在推送的過(guò)程中,由于啟動(dòng)服務(wù)進(jìn)程本身需要一定的時(shí)間,所以運(yùn)維發(fā)布系統(tǒng)會(huì)按一定的步長(zhǎng)進(jìn)行操作,即,將線上機(jī)器分批重啟,一批完成變更后,再進(jìn)行另外一批。
得益于目前微博平臺(tái)的雙機(jī)房架構(gòu),我們?cè)诤诵姆?wù)的上線是按機(jī)房進(jìn)行上線的。即先上tc機(jī)房服務(wù),完成整個(gè)機(jī)房的變更后,由測(cè)試在tc的線上環(huán)境中進(jìn)行測(cè)試用例回歸。通過(guò)后,再進(jìn)行yf機(jī)房的上線。采取這樣的分機(jī)房上線的意義在于,如果tc發(fā)生問(wèn)題,我們可以迅速的將流量導(dǎo)流到y(tǒng)f中,避免服務(wù)完全不可用。
故障是無(wú)法被避免的,無(wú)論我們的code review做的多細(xì)致,測(cè)試覆蓋的多全面,上線流程的審查多么嚴(yán)格,最終在變更的過(guò)程中依然可能會(huì)有因疏漏、bug導(dǎo)致的故障。
如果代碼中有預(yù)留相應(yīng)的防御性措施,如開關(guān)等,那么可以通過(guò)采取相應(yīng)的措施進(jìn)行規(guī)避。
對(duì)于無(wú)法通過(guò)防御性編程進(jìn)行錯(cuò)誤恢復(fù)的變更,我們則需要進(jìn)行回滾。即將線上代碼回滾到上一個(gè)穩(wěn)定版本中,取消變更。
在大型分布系統(tǒng)中,回滾也不是一件簡(jiǎn)單的事情。即在很多時(shí)候,單純的回退代碼可能引入更為嚴(yán)重的問(wèn)題:
(1)上線過(guò)程中寫入的數(shù)據(jù)無(wú)法做到向前兼容,回退代碼,會(huì)造成這部分?jǐn)?shù)據(jù)丟失,甚至影響系統(tǒng)功能。
(2)代碼、配置回滾順序。系統(tǒng)采用了代碼、配置分離的管理策略。代碼的回滾可能依賴于配置的先回滾,單純回滾代碼可能會(huì)造成服務(wù)無(wú)法啟動(dòng)的問(wèn)題。
(3)隊(duì)列機(jī)、前端應(yīng)用服務(wù)器回退順序。在線上系統(tǒng)中,我們采用前端應(yīng)用服務(wù)器加隊(duì)列服務(wù)器的架構(gòu),即由隊(duì)列服務(wù)負(fù)責(zé)對(duì)資源進(jìn)行更新,前端服務(wù)器只對(duì)資源進(jìn)行下行獲取。當(dāng)涉及到資源的上線回退的時(shí)候,資源的讀寫順序回退的錯(cuò)亂可能會(huì)造成線上數(shù)據(jù)不一致。
圖3 異步消息處理架構(gòu)
所以我們?cè)谏暇€申請(qǐng)過(guò)程中,就需要明確回退步驟,包括:
(1)代碼配置回退順序
(2)前端機(jī)、處理機(jī)回退順序
(3)數(shù)據(jù)盡量做到向前兼容,無(wú)法向前兼容的需要明確指出
當(dāng)線上真的發(fā)生了問(wèn)題時(shí),我們將馬上按照上線定好的回滾方案進(jìn)行代碼、配置回滾。從而保證線上服務(wù)穩(wěn)定。?
本文主要結(jié)合微博平臺(tái)的開發(fā)、上線流程進(jìn)行說(shuō)明。如文中所說(shuō)的,上線是一件具有風(fēng)險(xiǎn)的操作,每次新加入的功能點(diǎn)、改造變更,都可能給線上系統(tǒng)引入不可知的問(wèn)題與故障。為了盡量減少類似風(fēng)險(xiǎn),以及在類似問(wèn)題出現(xiàn)后,可以快速的進(jìn)行恢復(fù),我們根據(jù)自身的業(yè)務(wù)特點(diǎn)總結(jié)設(shè)計(jì)出了一套研發(fā)上線流程。
引入流程并不是為了限制研發(fā)人員的研發(fā)效率,而是希望借助對(duì)每個(gè)流程環(huán)節(jié)的把控,從而保證我們每次變革的質(zhì)量,盡量減少bug、故障的發(fā)生。
當(dāng)然,我們也不認(rèn)為我們的流程能夠完全將故障排除。借助流程中的上線前梳理、代碼的防御性編程,回滾方案的準(zhǔn)備等措施,以及上線后的監(jiān)控、發(fā)布系統(tǒng)的調(diào)度等措施來(lái)做到出事可干預(yù),有問(wèn)題可以快速回滾,從而減少故障對(duì)線上服務(wù)的影響。
?? ? 目前我們也在積極的推動(dòng)持續(xù)集成、微服務(wù)、docker化,希望借助于這些新的技術(shù)來(lái)提升我們開發(fā)、上線的效率,本文因篇幅所限雖未就這些方面進(jìn)行展開描述,但希望各位關(guān)注@微博平臺(tái)架構(gòu) 后續(xù)的微博、課程分享、討論。如果你有好的資料和建議,也可以隨時(shí)反饋給我們。
------------------新兵訓(xùn)練營(yíng)簡(jiǎn)介------------------
微博平臺(tái)新兵訓(xùn)練營(yíng)活動(dòng)是微博平臺(tái)內(nèi)部組織的針對(duì)新入職同學(xué)的團(tuán)隊(duì)融入培訓(xùn)課程,目標(biāo)是團(tuán)隊(duì)融入,包括人的融入,氛圍融入,技術(shù)融入。當(dāng)前已經(jīng)進(jìn)行4期活動(dòng),很多學(xué)員迅速成長(zhǎng)為平臺(tái)技術(shù)骨干。具體課程包括《環(huán)境與工具》《分布式緩存介紹》《海量數(shù)據(jù)存儲(chǔ)基礎(chǔ)》《平臺(tái)RPC框架介紹》《平臺(tái)Web框架》《編寫優(yōu)雅代碼》《一次服務(wù)上線》《Feed架構(gòu)介紹》《unread架構(gòu)介紹》。微博平臺(tái)是非常注重團(tuán)隊(duì)成員融入與成長(zhǎng)的團(tuán)隊(duì),在這里有人幫你融入,有人和你一起成長(zhǎng),也歡迎小伙伴們加入微博平臺(tái),歡迎私信咨詢
------------------講師簡(jiǎn)介------------------
? ? ?賴佳?。ㄎ⒉╆欠Q:@LierD?),2013年7月畢業(yè)于哈爾濱工業(yè)大學(xué)后,加入新浪微博工作至今,擔(dān)任系統(tǒng)研發(fā)工程師。曾先后參與微博Feed流優(yōu)化、后端服務(wù)穩(wěn)定性建設(shè)等項(xiàng)目。關(guān)注jvm調(diào)優(yōu),微服務(wù),分布式存儲(chǔ)系統(tǒng)。微博平臺(tái)新兵訓(xùn)練營(yíng)二期學(xué)員.
業(yè)余愛(ài)好三國(guó)殺,dota,喜歡自己做飯下廚希望能在微博的平臺(tái)上認(rèn)識(shí)到更多優(yōu)秀的小伙伴,一起交流,一起成長(zhǎng)
更多建議: