點擊上方“服務(wù)端思維”,選擇“設(shè)為星標(biāo)”
回復(fù)”669“獲取獨家整理的精選資料集
回復(fù)”加群“加入全國服務(wù)端高端社群「后端圈」
作者 | 網(wǎng)約車技術(shù)團(tuán)隊桔妹導(dǎo)讀:持續(xù)穩(wěn)定并體驗良好的測試環(huán)境,一直是影響產(chǎn)品迭代效率和穩(wěn)定性的關(guān)鍵環(huán)節(jié),也是DevOps自動化測試環(huán)節(jié)中最具挑戰(zhàn)的一環(huán),滴滴在測試環(huán)境上的探索從公司成立之初就從未停止,在這過程中沉淀了很多寶貴的經(jīng)驗和教訓(xùn)。本文細(xì)數(shù)滴滴在測試環(huán)境的發(fā)展歷程,希望能給大家?guī)硪恍﹩l(fā)。
伴隨著滴滴的不斷成長,業(yè)務(wù)復(fù)雜度與日俱增,團(tuán)隊在協(xié)作和迭代效率問題上日益嚴(yán)重,"微服務(wù)"成了很多公司解決上述問題的必經(jīng)之路,滴滴也不例外。隨著微服務(wù)在滴滴的落地,我們確實成功緩解了協(xié)作和迭代效率上的問題,但同時也引出了很多新的問題,比如構(gòu)建測試環(huán)境的復(fù)雜度,這也是我們今天要聊的主題——滴滴在測試環(huán)境上的探索與實踐。
在滴滴微服務(wù)落地初期,一個業(yè)務(wù)涉及服務(wù)數(shù)并不會太多,最多也就十幾個,在這種場景下,不管怎么搭建測試環(huán)境都是相對容易的,哪怕是手動維護(hù)也耗費不了多少成本,所以在這個時期我們通過工具自動構(gòu)建所有服務(wù),把所有服務(wù)都打包在一起基本就夠用了,我們管它叫"All in one"環(huán)境。這種方式持續(xù)了很長時間,直到現(xiàn)在依然支持著部分測試工作,但隨著微服務(wù)數(shù)的增多這種方式越來越難以維護(hù)。當(dāng)我們的微服務(wù)數(shù)已經(jīng)達(dá)到了四位數(shù)的時候,All in one模式早已不能支撐測試需求,所以我們開始探索其他解決方案。我們把目光轉(zhuǎn)移到了UT上,它最大的優(yōu)勢就是下游依賴全部通過mock的方式替換掉,只需部署被測服務(wù)即可。常見的類似方案還有契約測試,常用工具是Pact。契約測試認(rèn)為在微服務(wù)架構(gòu)下E2E測試其實是一個偽需求,應(yīng)該按照契約分別測試Consumer和Provider。我們也一度認(rèn)為微服務(wù)下的測試可能真的不適合做E2E測試,但當(dāng)真正應(yīng)用的時候,我們發(fā)現(xiàn)Pact測試太理想化了,如果針對下游依賴很少的服務(wù)來說還行(但我們覺得All in one模式可能比Pact還好用),但對于最上游依賴成百上千個服務(wù),場景復(fù)雜多變的服務(wù)來說,Pact維護(hù)成本可能比環(huán)境維護(hù)成本還大(這里我們不討論架構(gòu)設(shè)計的合理性,只討論現(xiàn)狀)。但Pact測試還是給了我們一些啟發(fā),如果我們能解決自動生成契約的方式,似乎問題就解決了。所以從17年開始我們嘗試通過線上錄制流量,線下回放流量的方式驗證了可行性,隨后在滴滴內(nèi)部逐漸推廣開來,我們內(nèi)部管它叫Fastdev,同時對外分別開源了針對PHP的https://github.com/didi/rdebug和針對Go的https://github.com/didi/sharingan,設(shè)計思路如下
隨著Fastdev的成功,似乎我們找到了銀彈,它可以完全模擬線上環(huán)境,測試場景也最真實,就算流量變了,我們只需要手動編輯一下個別流量也能實現(xiàn)mock能力,成本可比Pact編輯成本低多了。但通過實際應(yīng)用下來,我們還是低估了業(yè)務(wù)的復(fù)雜度和用戶的接受度,雖然Fastdev能夠模擬線上真實場景,對重構(gòu)類變更(流量不變的情況)確實效果顯著,但一旦這次變更涉及到流量變化,就有可能導(dǎo)致所有流量都跟著變,比如在原來快車的基礎(chǔ)上增加了拼車邏輯,所有調(diào)用參數(shù)里都需要添加拼車相關(guān)數(shù)據(jù),那流量編輯的成本可能比Pact還高,因為除了要理解業(yè)務(wù)之外,還要熟悉每個通信協(xié)議設(shè)計,比如Redis,mysql,http,thrift等等,就算我們針對所有協(xié)議設(shè)計了統(tǒng)一的DSL,也依然解決不了用戶的使用成本。針對流量變化的測試,我們的關(guān)注點又回到了環(huán)境搭建上,All in one的模式肯定是不可持續(xù)了,那如何才能以低成本方式保證每人都有一套穩(wěn)定的、高仿真度的測試環(huán)境呢?我們發(fā)現(xiàn)預(yù)發(fā)環(huán)境(類線上環(huán)境,除了沒有真實流量之外,其他跟線上環(huán)境無異)承擔(dān)了很多自動化測試工作,并且足夠穩(wěn)定和仿真,所以我們又開始了通過預(yù)發(fā)環(huán)境做測試的環(huán)境的探索,也就是業(yè)界常說的TiP(Test in Production),先別著急噴TiP的各種問題,后面會說。其實從整個環(huán)境問題來說,最難的其實就是下游依賴,如果我們把下游的預(yù)發(fā)環(huán)境做為測試環(huán)境的依賴,上游只需要部署被測服務(wù)即可,然后通過邏輯隔離的方式(測試賬號)實現(xiàn)人手一套環(huán)境,成本也足夠低。按照這個思路,我們在18年開始了TiP-Sim環(huán)境(線上仿真環(huán)境)的建設(shè),設(shè)計方案如下。
在實踐線上仿真環(huán)境的過程中遇到過很多問題,其中一個就是流量閉環(huán)問題,對于A調(diào)B,B調(diào)C的串行鏈路比較好支持,但涉及到A->B->C->A這種回調(diào)鏈路或者A->B->C,A只需要跟C單獨聯(lián)調(diào),跳過B的鏈路就不行了,無法實現(xiàn)流量的閉環(huán)。如果每人部署一套全量環(huán)境肯定不現(xiàn)實,所以我們借鑒了一些業(yè)界常用的染色和分流方案,以很小的成本就實現(xiàn)了流量閉環(huán)。我們沒有采用在接入層或者路由層去做流量染色和分流,原因有兩方面,一是改動成本較大,二是直連沒有經(jīng)過接入層。最終我們選擇了類似Service Mesh中Sidecar方案,在每個業(yè)務(wù)模塊上部署一個代理(只部署在基準(zhǔn)環(huán)境),所有的染色和流量都在代理上做,通過篡改Traceid實現(xiàn)流量標(biāo)識和分流(sim001xxxxxxxxxxxxxxx),最終實現(xiàn)了流量閉環(huán)。目前成了滴滴主要的聯(lián)調(diào)測試環(huán)境,設(shè)計如下。
但現(xiàn)實總是殘酷的,這就說到了上面提到的TiP問題,其中最大的問題就是RD不敢在上面隨意調(diào)試,因為采用的是邏輯隔離,網(wǎng)絡(luò)和數(shù)據(jù)都跟線上共用,稍有不慎就有可能導(dǎo)致線上事故,類似事故已經(jīng)出現(xiàn)多起。所以線上仿真環(huán)境并不敢大面積應(yīng)用到RD開發(fā)測試中,只在開發(fā)的差不多情況下才敢部署到TiP測試,當(dāng)然我們也嘗試在這個環(huán)境的基礎(chǔ)上做了數(shù)據(jù)層面的物理隔離,但依然解決不了影響線上的風(fēng)險,最終我們還得是回到起點 —— 創(chuàng)建一套穩(wěn)定的線下測試環(huán)境,從根本上杜絕環(huán)境污染,這就是接下來要說的線下仿真環(huán)境——OSim(Offline-Simulation)。
得益于滴滴服務(wù)全面上云,很多基礎(chǔ)能力的建設(shè)都可以以IaC的方式進(jìn)行簡單配置實現(xiàn),比如同一個服務(wù)不同集群之間在不同的網(wǎng)段,不同集群之間的不同標(biāo)識等等,都讓我們復(fù)用線上能力的同時區(qū)分線上線下容易了很多。OSim環(huán)境類似上面提到的線上仿真環(huán)境,最大的區(qū)別就是網(wǎng)絡(luò)變成了線下,實現(xiàn)了與生產(chǎn)環(huán)境的物理隔離,根本上解決了線上環(huán)境污染的問題,但這也意味著我們要把所有服務(wù)都要在線下搭建一遍,除了業(yè)務(wù)服務(wù)之外,所有的基礎(chǔ)服務(wù)也需要適配線下環(huán)境,比如存儲服務(wù),代理服務(wù),配置推送服務(wù),日志采集,APP、小程序等等,這相當(dāng)于再造一個線下滴滴,挑戰(zhàn)可想而知。但剛才說了得益于上云和前人經(jīng)驗,很多東西已經(jīng)準(zhǔn)備好了,比如云上的存儲,網(wǎng)絡(luò)的隔離,app debug包等等,同時根據(jù)經(jīng)驗,我們在項目創(chuàng)立之初就確定了三大原則:所有線下服務(wù)必須跟線上服務(wù)同時部署——保證高仿真度;
誰的服務(wù)誰負(fù)責(zé)——把整個項目拆解到最適合的人手里;
接入公司統(tǒng)一技術(shù)方案,比如RPC、服務(wù)發(fā)現(xiàn)、鏈路追蹤等等——減少維護(hù)成本;
基于以上原則,我們把所有涉及的服務(wù)都做了線上線下自適配,根據(jù)容器提供的標(biāo)識可以自動區(qū)分線下和線上環(huán)境。但總有一些例外,針對一些特殊場景,我們也會選擇直接調(diào)用線上,比如跟地圖服務(wù)無業(yè)務(wù)無關(guān)的調(diào)用,又或者一些不怎么變動的服務(wù)以mock方式提供等等,我們并沒有過度追求完美,夠用就好。環(huán)境搭建好以后,如何持續(xù)保障環(huán)境的穩(wěn)定性又是一個巨大的挑戰(zhàn)。由于滴滴很早之前就實現(xiàn)了異地雙活,所以對新增一個機(jī)房(線下環(huán)境就相當(dāng)于模擬創(chuàng)建了一個新的機(jī)房)的邊際維護(hù)成本幾乎為零,這樣我們沿用線上的標(biāo)準(zhǔn)來維護(hù)線下環(huán)境,比如報警監(jiān)控,oncall機(jī)制,甚至可用性指標(biāo)和事故復(fù)盤機(jī)制(目前還是輕運營的方式)等等,無需單獨為線下環(huán)境單獨搞一套穩(wěn)定性方案,同時也可以驗證我們穩(wěn)定性技術(shù)方案的擴(kuò)展性。到此滴滴在整個測試環(huán)境上探索和實踐就講完了,大體分為All in one、流量錄制回放、線上仿真和線下仿真四種模式,在整個演進(jìn)歷程中,我們發(fā)現(xiàn)每一種測試環(huán)境特定場景下都有存在的必要性,誰都代替不了誰,所以每個環(huán)境都值得團(tuán)隊投入更大的精力去建設(shè),畢竟測試環(huán)境是所有測試能力的基礎(chǔ)。最后想跟大家探討一個話題:"到底該由誰來進(jìn)行測試"?在說觀點之前,我想拿OP到SRE角色的轉(zhuǎn)變來舉例。記得幾年前,我還在某大廠工作,每次上線都要坐到OP旁邊,小心翼翼的求著OP給我上線,人多了還得人肉排隊,好不容易輪到我,還得陪著OP慢慢灰度驗證,一旦發(fā)現(xiàn)問題,就得讓OP操作回滾,然后被OP一臉嫌棄,甭提多痛苦了。現(xiàn)在看來,應(yīng)該很少有這種上線方式了吧,由SRE提供部署平臺,RD負(fù)責(zé)所有的部署流程似乎成了最常規(guī)的操作,也消除了RD和SRE協(xié)作成本,SRE也能專注在工具優(yōu)化上。其實測試也是類似道理,RD同樣應(yīng)該負(fù)責(zé)測試工作,由QA(或者叫SET)提供穩(wěn)定的高效的測試平臺協(xié)助RD測試。但有人可能會質(zhì)疑,RD這樣豈不是啥都做了,需求更迭代不過來了,其實根本原因還是在測試成本,如果測試能變成跟部署一樣簡單,那RD來測試也就沒那么多問題了。同時RD開發(fā)本身也離不開測試,每一次小的變更可能都需要跑一下測試來驗證,更別提復(fù)雜變更了。但如果RD只是把簡單測試過的代碼交給QA測試,后面就等著QA報bug,這種狀況會讓QA壓力越來越大,RD對變更越來越?jīng)]自信,測試工具的建設(shè)也越來越跟不上業(yè)務(wù)迭代,陷入惡性循環(huán)。但如果RD肩負(fù)起測試的責(zé)任,不管是在需求評審階段,代碼設(shè)計階段,還是在編碼階段都會考慮代碼的可測試性,架構(gòu)設(shè)計的合理性等,QA也會有更多的精力投入到工具建設(shè)中,RD的測試效率也會更快,最終達(dá)到一種良性循環(huán)。在DevOps思想中就提過,RD應(yīng)該承擔(dān)起需求分析,設(shè)計,編碼,測試,上線,線上問題oncall等整個流水線工作,這樣溝通的成本最低,效率最高,但這中間每一個環(huán)節(jié)都應(yīng)該足夠便利,所有人都有義務(wù)來改進(jìn)這里的每一個環(huán)節(jié),來使整個DevOps流程更順暢。這個時候可能又有人說,讓RD來測試,很容易陷入自己的思維定式,測試不充分,第三方測試可以跳出思維定式,這里我們更贊成《Google軟件測試之道》中提到的測試活動管理者,如果組織PM,運營,內(nèi)/外部用戶,借助灰度發(fā)布等手段,全方面的驗證可能效果會更好。這里不是說QA就徹底不進(jìn)行測試了,借助更多測試手段,最終QA的測試工作會變得輕松很多,也會有更多精力投入到更具創(chuàng)新和挑戰(zhàn)的工作當(dāng)中。
關(guān)注我,回復(fù) 「加群」 加入各種主題討論群。
對「服務(wù)端思維」有期待,請在文末點個在看
喜歡這篇文章,歡迎轉(zhuǎn)發(fā)、分享朋友圈