天天看點

阿裡研究員:線下環境為何不穩定?怎麼破

阿裡研究員:線下環境為何不穩定?怎麼破

作者 | 鄭子穎

來源 | 阿裡技術公衆号

這篇文章想講兩件事:

  • 為什麼線下環境[1]的不穩定是必然的?
  • 我們怎麼辦?怎麼讓它盡量穩定一點?

此外,還會談一談如何了解線下環境和線上環境的差別。

如果沒有時間讀完全文的話,這裡是本文的主要觀點:

  1. 線下環境不穩定是必然的,在沒有實作TiP之前,目前我們能做的是盡量讓它穩定一點。
  2. 避免過多的籠統使用”環境問題“的說法。
  3. 業務應用線下環境的基礎設施必須按照生産環境标準運維。一個實作手段就是直接使用生産環境的基礎設施。
  4. stable層首先要把單應用可用率提升上去。單應用如果無法做到99.999%或100% 都是能調通的,鍊路的穩定性就是緣木求魚、根本無從談起。
  5. 減少dev環境的問題,主要有四個重點:
    • 做好聯調內建前的自測;
    • 架構上的投入(契約化、可測性);
    • 通過多環境、資料庫隔離等手段減少互相打擾;
    • 通過持續內建盡早暴露問題,降低問題的影響和修複成本。
  6. IaC(Infrastructure-as-Code)是解題的一個關鍵點。
  7. 線下環境是一個場景。要深刻了解線下環境和線上環境這兩個不同場景的差異。

以下是正文:

一 線下環境不穩定的必然性

說起線下環境為什麼不穩定,經常會聽到大家給出這些原因:

  • 為了成本,線下環境的機器不好,是過保機;
  • 為了成本,線下環境的硬體資源是超賣的;
  • 工具配套不完善,線下環境的配置和生産環境沒保持同步;
  • 線下環境的監控告警、自愈等沒有和生産環境對齊;
  • 投入不夠,不重視,對問題的響應不及時,流程機制等沒建立起來;
  • 測試活動會産生髒資料;

其實這些原因中大部分都不是本質問題。換句話說,即便狠狠的砸錢、砸人、上KPI,即使機器不用過保機、硬體不超賣、工具建設好把配置監控自愈等和生産環境保持對齊、問題響應機制建立起來,線下環境也還是會不穩定的。因為線下環境不穩定的根源在于:

  1. 線下環境裡面有不穩定的代碼
  2. 線下環境不穩定帶來的影響小

這兩個原因是互相有關系的:我們需要有一個地方運作不穩定的代碼,但我們怕不穩定的代碼引起很大的問題,是以我們需要這個地方是低利害關系的(low-stakes);因為這個地方是低利害關系的,是以對它的問題我們必然是低優先級處理的。

是以,線下環境必然是不穩定的。

之是以Testing-in-Production(TiP)是一條出路,就是因為TiP把這兩個根源中的一個(即第二點)給消除了:production不穩定帶來的影響是很大的。但TiP注定是一條很漫長且艱難的道路,因為我們怕不穩定的代碼引起很大的問題。我們需要首先在技術上有充分的能力充分確定不穩定的代碼也不會引起很大的問題。這是很有難度的,今天我們還沒有100%的信心做到能充分確定穩定的代碼不會引起很大的問題。

既然TiP一時半會兒還用不上、發揮不了很大的作用,那麼接下去的問題就是:怎麼辦?既然線下環境的不穩定是必然的,那我們怎麼用不太誇張的投入讓它盡量穩定一點?

對策還是要有的。否則,線下環境太不穩定了,大家就都放棄了,不用了,直接跳過,直接把還不太穩定的代碼部署到預發環境(pre-production)去了。把預發環境當線下環境用,結果就是預發環境也被搞得像線下環境那樣不穩定了。這樣再發展下去,預發環境越來越不穩定了,我們還有地方可以去嗎?是以,還是要有一整套對策讓線下環境盡量穩定一點。

二 怎麼讓線下環境盡量穩定一點

1 避免過多的籠統使用“環境問題”的說法

  • 很多同學習慣用“環境問題”、“環境不穩定”來指代線下環境裡除了他自己的那個應用之外的所有的問題:
  • 實體機和網絡的問題是“環境問題”
  • 中間件的問題是“環境問題”
  • 資料庫本身的問題是“環境問題”
  • 資料庫裡的“髒”資料[2]是“環境問題”
  • 我的資料被别人的應用消費掉了是“環境問題”
  • 其他應用的配置配錯了是“環境問題”
  • 其他應用重新開機了導緻我的調用失敗是“環境問題”
  • 其他應用裡的代碼bug也是“環境問題”
  • ...

“環境問題”這個說法太籠統了,過多的籠統使用這個說法是很有害的,因為它會掩蓋很多真正的問題。其中的一些問題也是有可能造成生産環境的穩定性和資金安全風險的。過多的籠統使用“環境問題”這個說法的另一個壞處是:會造成在大家的意識裡“環境問題”是必然存在的、是無法避免的,導緻大家一聽到“環境問題”第一反應就是放棄,放棄排查、放棄抗争、放棄探究、放棄改進優化。

要提升線下環境穩定性,首先要正本清源,盡量避免籠統的使用“環境問題”這個說法。要盡量用具體一點的說法,比如,“網關配置問題”、“某某應用啟動逾時”、“資料庫查詢逾時“。這些表象/症狀背後的原因有很多種可能,是需要我們去排查清楚的,不能“刷牆”。所謂的“刷牆”的意思是:看到牆上有條裂縫,就找一桶乳膠漆刷一道,把裂縫遮蓋掉。“刷牆”的行為的一個例子:某個應用啟動失敗,就換台伺服器再試一試,成功了就繼續幹下面的事情,不去探究之前啟動失敗背後的原因了。

有些時候的确是項目時間太緊了,沒時間排查每一個問題。可以現實一點,如果同樣的問題出現第二次或第三次(例如,同一個應用、同一個項目分支,這周遇到兩三次啟動失敗),就要追究一下了。

2 問題拆解

“環境問題”,歸根到底,無外乎來自于三個地方:

  • 基礎設施(中間件、資料庫、等等)的問題
  • stable環境的問題
  • dev環境的問題

這裡要解釋一下什麼是stable和dev。線下環境的結構在螞蟻集團和阿裡集團的做法一般是這樣的:

  • 基礎設施之上,首先有一個stable環境。
  • stable環境跑的是和生産環境的版本相同的代碼,每次生産環境釋出後,stable也會同步更新。
  • dev環境就是項目環境,是SUT(System Under Test)。每個項目有自己的dev環境,部署的是這個項目的代碼,這個項目上的同學就在這個項目環境裡做測試、聯調、內建。
  • dev環境不是一個全量的環境,它是“挂”在stable上的一個子集。某系統一共有一百個左右的應用,它的stable環境是全量的,但dev環境隻包含這個項目涉及的應用,測試發起的流量裡面包含一個标簽,測試流量就會被某種路由機制(例如,在螞蟻用的是sofarouter)從stable環境的應用路由到dev環境的應用:
阿裡研究員:線下環境為何不穩定?怎麼破

雖然這三趴對“環境問題”會因人而異,但都不可忽視。要提升線下環境穩定性,必須對基礎設施、stable、dev這三趴三管齊下。

3 對策:基礎設施

基礎設施的穩定是非常關鍵的一環。如果基礎設施不穩定,就會出現“排查疲勞”:每次遇到一些奇怪的問題(啟動逾時、調不通、等等),如果排查下來10次有9次是基礎設施的問題,大家漸漸就不願意排查了(因為不是代碼的問題),一些真正的代碼問題也會被漏過。

基礎設施層要遵循的原則是:(業務應用的)線下環境的基礎設施必須按照生産标準運維 。如果一個系統是運作在公有雲上的,那麼這個原則就很容易實作,因為線下環境也可以直接運作在公有雲上。但有些公司、有些系統,是運作在自建機房、私有雲上的,那最好的做法是撤銷“線下機房”,直接把業務應用的線下環境放在基礎設施的生産機房去跑(同時做好必要的通路控制和業務資料隔離)。線下環境直接放在基礎設施的生産機房跑之後,基礎設施團隊直接按照運維其他生産機房那樣去運維,中間件、資料庫、緩存、實體機、網絡、機房等所有的監控告警、巡檢、釋出和變更管控、應急、自愈能力、容量管理、等等都能做到位,穩定性可用率有明确的metrics和SLA。慢慢的,就能形成這樣的心智:例如,當線下環境的某個業務應用出現資料庫查詢timeout的時候,我們首先懷疑的是應用自己的SQL查詢語句有問題,而不是懷疑資料庫有問題。

4 對策:stable環境

線下環境不穩定性的時候,工程師的心智是:當我在dev環境跑測試遇到錯誤的時候,我的第一反應是“一定是‘環境問題’”。也就是說,我的第一反應是“别人的問題”,隻有當“别人的問題”都排出後我才會認真的去看是不是我自己的問題(包括項目的問題)。

當基礎設施層穩定保障好以後,就能形成這樣的心智:當某個應用出現資料庫查詢timeout的時候,我們首先懷疑的是應用(可能是stable的、可能是dev的)的SQL有問題,而不是懷疑資料庫有問題。

當stable和基礎設施這兩趴的穩定性都治理好以後,就能形成這樣的心智:當我在dev環境跑測試遇到錯誤的時候,我的第一反應是“一定是我們的項目有問題”。其實今天在生産環境大家就是這樣的心智。一次變更、一次釋出後,如果出現問題,做釋出做變更的同學的第一反應都是懷疑是不是這個變更/釋出有問題,而不是懷疑是不是(生産)環境本身不穩定。做stable和基礎設施的穩定性治理也要達成這樣的心智。

stable的穩定性治理,最終就是在做一道證明題:拿出資料來,證明stable是穩定的(是以,如果有問題,請先排查你的項目)。證明stable是穩定的資料分兩類:

  • 單應用
  • 鍊路

單應用就是檢查應用是否起來了、是否或者、RPC調用是否調通(不管業務結果是成功還是失敗,但至少RPC調用沒有system error)。它驗證的是單個應用是可用的,不管業務邏輯對不對,不管配置對不對,不管簽約綁卡能不能work,至少這個應用、這個服務、這個微服務是up and running的。單應用穩定性必須達到100%,或者至少應該是“五個9”。這個要求是合理的,因為單應用的穩定性是鍊路穩定性的基礎。如果單應用都沒有up and running,鍊路功能的可用和正确性就根本無從談起。

單應用的穩定性度量是很通用的,不需要了解業務場景就可以度量。我們需要做的事情就是:對目标形成共識,把度量跑起來,然後根據度量資料投入人力,一個個問題的排查解決,把穩定性一點點提升上來;後續再出現問題,第一時間排查解決,讓穩定性維持在很高的水準。

鍊路的穩定性,說白了就是跑腳本、跑測試用例。頻率是分鐘級也可以,小時級也可以。驗證鍊路的腳本是需要不斷的補充豐富的,當發生了一個stable的問題但是驗證腳本沒有發現,就要把這個問題的場景補充到鍊路驗證腳本(測試用例)裡面去。也可以借用測試用例充分度的度量手段(例如,行覆寫率、業務覆寫率、等等),主動的補充鍊路驗證腳本。很多其他測試用例自動生成的技術也可以用上來。

最後,達到的效果就是:用資料說話。用很有說服力的資料說話:stable的單應用都是好的,鍊路也都是通的,這時候出現了問題,就應該先懷疑是項目(dev環境)的問題。

順便說一句:stable能不能像基礎設施那樣也直接用生産環境呢?可以的,stable用生産就是Testing-in-Production了。螞蟻的影子鍊路壓測就是這種做法的一個例子。隻不過如果要把這個做法推廣到更大面積的日常功能測試、支援更多鍊路和場景,複雜度和難度會比影子鍊路壓測更高。

5 對策:dev環境

嚴格來說,dev環境的問題不能算是“環境問題”,也不能算是“線下環境穩定性問題”。因為dev環境就是被測對象(SUT),既然是還在寫代碼、聯調內建和測試,那我們的預期就是它是不穩定的,是會有問題的。隻不過實際工作中,dev環境本身的問題也構成了大家對線下環境不穩定的體感。

根據我們對一些項目進行的具體資料分析來分類,在dev環境遇到的問題的幾個頭部類型是:

  • 自測沒做好。單應用本身就有bug,而且這些bug是在單應用的unit test和接口測試中是可以發現的,但是由于各種原因,單應用的自測沒做好,這些bug留到了在dev環境中進行聯調內建的時候才發現。
  • 架構方面的原因。例如,接口契約問題。一個項目裡,系分做好以後,上下遊兩個應用各自按照系分去編碼實作,但由于系分做的不夠好,或者上下遊對系分的了解有差異,兩個應用到了dev環境放在一起一跑才發現跑不通。這類問題是無法通過自測來發現的(因為本身的了解就有差異)。另一個比較常見的架構原因是可測性。
  • 幹擾。同一個項目中幾個同學各自在做聯調內建時候的互相幹擾,以及幾個項目之間的互相幹擾。配置被别人改掉了,資料被别人改掉了,這些情況都很常見。

自測沒做好,解法就是要做好自測:

  • 單應用的測試要達到一定的覆寫率和有效性。例如,我之前團隊的要求是A級系統的單應用測試(unit test和接口測試)要達到90%以上的行覆寫率、以及變更行的覆寫率100%,用例的有效性也要達到90%。
  • 單應用的測試要達到很好的穩定性。根據過去在很多地方的時間和觀察,我建議的标準是”90%成功率“,這是在“能做得到的”和“夠好了”之間的一個比較好的平衡。比這個高,雖然更好,但難度太高,不适合大部分的團隊;比這個低,穩定性就不夠了,就會感受到測試噪音帶來的各種問題。“90%成功率”是一個“甜蜜點”。“90%成功率”的意思是:一個單應用的所有unit test和接口測試的整體通過率,跑一百遍,有至少90遍是100%通過的。
  • 單應用的測試也要足夠快,一個單應用的所有unit test和接口測試要能在10分鐘内跑完。
  • 代碼門禁是必須的,是标配。很多其他東西是可以根據具體團隊的具體情況有不同的做法的,例如,大庫、主幹開發。有些團隊可以舉出一些合理的理由說“大庫模式不适合我”、“主幹開發不适合我”。但我不相信哪個團隊能舉出合理的理由說“代碼門禁不适合我”。

接口契約在軟體行業已經有比較多的實踐了,例如OpenAPI、ProtoBuf、Pact等。應用間的接口(包括RPC調用和消息),如果隻是在一個文檔裡面用中文或者英文來描述的,上下遊之間就比較容易出現gap。也經常出現接口改動隻是通過釘釘說了一下,連文檔都沒有更新。應用間的接口應該以某種DSL來規範的描述,并且在單應用層面根據這個DSL描述進行契約測試,這樣能大大減少兩個應用到了dev環境放在一起一跑才發現跑不通的情況。

6 dev環境:隔離

上面講到,dev環境問題的第三個主要來源是互相幹擾。既有同一個項目中幾個同學各自在做聯調內建時候的互相幹擾,也有幾個項目之間的互相幹擾。項目之間的互相幹擾的根源是共享資料庫:

阿裡研究員:線下環境為何不穩定?怎麼破

過去,stable環境以及多個項目的dev環境的代碼都是通路同一個庫的,互相影響就是不可避免的。資料的邏輯隔離和實體隔離都可以解決多項目間的幹擾:

  • 邏輯隔離:多個項目的dev環境仍然和stable一起共享同一套庫表,但是在表的資料層面增加一些辨別列,并且在應用的代碼邏輯裡面根據這種辨別來讀寫資料。
  • 實體隔離:每個dev環境分别有自己的庫或者表,各自的資料在庫或表的層面就是隔離的。相比邏輯隔離,實體隔離有兩個優點:1)對應用代碼的入侵很小,需要的應用改造工作量很小;2)不同的項目能夠有不同的資料庫表結構。
阿裡研究員:線下環境為何不穩定?怎麼破

除了資料庫,緩存、DRM等也需要進行隔離,減少多個項目之間的互相幹擾。做好隔離對提升穩定性有很大的幫助。而且,資料庫和緩存等的隔離也能大大降低“髒”資料引起的問題。

7 dev環境:多環境

除了多個項目之間的幹擾以外,同一個項目中幾個同學各自在做聯調內建時候,由于大家都在同一套dev環境(項目環境)上工作,也會出現互相幹擾。

解決項目内互相幹擾的出路是多環境:

阿裡研究員:線下環境為何不穩定?怎麼破

IaC(Infrastructure-as-Code)和GitOps是實作多環境能力的關鍵。有了GitOps能力(包括Configuration-as-Code和Database-as-Code),能反複快速建立出一套套新的項目環境,并且保證新建立的項目環境中的配置都是對的(IaC也能更好更有效的確定stable的配置、二方包版本、CE版本等和生産環境是一緻的)。

8 dev環境:持續內建

單應用的持續內建已經是比較普遍了:在master分支和項目分支上,每次有代碼送出都會觸發一次單應用的編譯建構和測試(包括unit test和接口測試),或者以某個固定周期(例如每15分鐘或者每小時)定時觸發一次,確定該應用的編譯建構和測試一直是好的。

多應用的持續內建就是:在項目分支上,每次有代碼送出、或者每隔一定時間,把本項目各個應用的項目分支最新代碼部署到dev環境上,并且跑一遍鍊路級别的用例,確定本項目的這些應用的項目分支代碼還是好的。

在很多團隊,今天開發同學的很多受挫感和時間的浪費都與缺乏項目級别的多應用持續內建有關,例如:

  • 小李跟我說收單支付已經跑通了,讓我可以開始測結算了。但我今天到項目環境裡一跑,發現收單有問題。我又去找小李,小李看了一下承認是他的問題,他當時隻看了行業層的resultCode是Success,沒有check下遊單據的狀态是否正确。
  • 我兩天前已經把正向流程(例如:支付)跑通了,但今天我要調逆向流程(例如:退款)的時候發現項目環境裡正向流程又不work了。逆向流程的調試被block了,我要先花時間排查正向流程的問題。
  • 項目環境裡正向流程兩天前是work的,今天不work了,從兩天前到現在,這個中間正向流程是從什麼時間開始不work的?兩天時間,如茫茫大海撈針啊。
  • 我是負責下遊應用的。上遊的同學今天一次次來找我check資料,每次他在項目環境裡發起一筆新的調用,都要來找我讓我做資料check。這事兒我躲也躲不掉,因為上遊的同學不了解我的應用的内部實作,要他們了解每個下遊應用的資料邏輯也不現實。
  • 我是負責上遊行業層的,我在項目環境裡每次發起一筆新的測試交易的時候,我都要挨個兒找下遊各域的同學去做資料check,找人找的好辛苦啊。我也了解他們的難處,那麼多項目,那麼多項目環境,那麼多人都去找他們做資料check。
  • 我是負責上遊行業層的,下遊的同學經常來找我,讓我幫他們發起一筆交易,因為他們的應用改了代碼,他們先知道新的代碼work不work。後來我實在覺得這種要求太多了,寫了一個發起交易的小工具,讓他們自己去跑。但有些會自己去學着用這個小工具,有些還是會來找我。
  • 我是負責下遊應用的,我經常要去找上遊同學幫我發起一筆。他們被我騷擾的很煩,但我也沒辦法。他們雖然給了我一個小工具,但很難用,很多參數不知道怎麼填。

做好了多應用的持續內建,這些問題就都解決了:

  • 由于用例都自動化了,發起交易和做check都不需要再求爺爺告奶奶的刷臉找人了。
  • 由于用例都自動化了,發起一筆新的交易和驗證各域的資料是否正确 都已經都自動化在用例的代碼裡了,無論是上遊還是下遊的同學,都隻要跑這些用例就可以了,不需要了解小工具的參數怎麼填,也不會因為疏漏少check了資料。
  • 由于用例都自動化了,是以可以高頻的跑,可以每個小時都跑一次,或者可以每15分鐘就跑一次。這樣,一旦前兩天已經跑通的功能被break了,我馬上就知道了。
  • 由于用例高頻的跑了,一旦前兩天已經跑通的功能被break了,我馬上就知道了,而且問題排查也很容易聚焦。比如,如果這個功能一直到上午9:30還是好的,但是從9:45開始就開始失敗了,那我就可以聚焦看9:30-9:45這段時間前後總共幾十分鐘時間裡發生了什麼、誰送出了新代碼、誰改了資料或配置。

做好了多應用的持續內建,其他的好處還有:

  • 由于用例高頻的跑了,一個用例一天要跑幾十次,就很容易暴露出用例本身或者應用代碼的一些穩定性問題。比如,有一個鍊路,從昨天到今天在本項目的多應用持續內建裡面跑了幾十次,其中有幾次失敗了。但從昨天到今天,這個鍊路沒有相關代碼和配置改動。是以雖然失敗的比例小于10%,我還是要排查一下,排查結果發現了一個代碼的bug。如果放在過去,沒有這種多應用的持續內建,一個鍊路跑了一次失敗了,第二次通過了,我很難判斷第一次失敗到底是“環境問題”,還是真的代碼有bug。
  • 由于用例在項目分支裡高頻的跑了,我就有一個參考物。如果一個用例在項目分支裡是一隻穩定pass的,但今天在我的個人分支代碼上失敗了,有了持續內建的結果作為參照物,我就很快能判斷出來這很有可能是我的個人分支的代碼有問題。

三 線下環境和線上環境的差別

線下環境和線上環境的差別是什麼,不同的人有不同的回答。有的說線下的容量沒有線上大,有的說線下沒有真實使用者,有的說線下缺少生産的真實資料,等等,各種答案都有。線下環境和線上環境還有一個很本質的差別是:它們是兩個不同的場景。

線下環境是一個場景。

我們做業務架構,先要搞明白業務場景,然後才能正确的設計業務架構和技術實作。資料的讀和寫是高頻的還是低頻的,資料塊是大而少的還是小而多的,讀取資料的時間段上有沒有明顯的峰谷,資料寫入後是否會修改(mutable vs. immutable)等等,這些都會影響我們的架構和技術實作方案。

線下環境也是一個場景,一個和生産環境有不少差異的場景[3]:

1 基礎設施層面

中間件

一個配置值、一個開關值,線上上的改動是低頻的,大部分情況下一天可能也就推個一兩次,但線上下可能每天會有幾十次、幾百次,因為推送一個配置一個開關可能是測試的一部分。這個差異就是場景的差異。

伺服器

伺服器重新開機,在生産環境裡是一個低頻事件,很多應用隻會在釋出的時候重新開機一次,兩次重新開機間的間隔一般都是數天。但線上下環境,重新開機的頻率可能會高很多。

資料庫

在生産環境,庫的建立和銷毀是一個低頻事件,但是線上下,如果搞了持續回歸和一鍵拉環境,線下環境資料庫就會有比生産高的多得多的庫建立銷毀操作。

資料丢失

生産環境,我們是不允許資料丢失的。是以,資料庫(例如螞蟻的OceanBase)和DBA團隊花了大量的心血在資料丢失場景上。但線上下,資料丢失是完全可以接受的。這個差異,對資料層的架構和技術實作意味着什麼?例如,資料庫在生産環境是三副本、五副本的,線上下不能支援單副本,能不能很容易的在單伺服器、單庫級别配置成單副本。

代碼版本

生産環境,一個系統,最多同時會有幾個不同的代碼版本在運作?線下環境呢?這個差異,意味着什麼?

抖動

“抖動”是很難避免的,業務應用一般都有一些專門的設計能夠容忍線上的基礎設施層的一些”抖動“。是以,在生産環境場景裡,基礎設施層面每天抖N次、每次抖10-20秒,不是一個太大的問題。但這樣的抖動線上下環境就是個比較大的問題:每次抖動,都會造成測試用例的失敗。這并不是因為這些用例寫的不夠“健壯”,而是有很多時候測試用例就是不能有防抖邏輯的。例如,如果測試用例有某種retry邏輯,或者測試平台會自動重跑失敗的案例[4],那麼就會miss掉一些偶發的的bug[5]。線上下環境裡,我們甯可接受每周有一次30分鐘的outage(不可用),也不願意接受每周幾十次的10-20秒抖動。一次30分鐘的outage,大不了就直接忽略掉那段時間的所有測試結果。而每周幾十次的10-20秒抖動意味着大量的測試噪音[6],意味着要麼是大量的額外的排查成本,要麼是漏過一些問題的可能。

2 業務應用層面

業務資料

線下的資料模式和生産是不一樣的。由于執行測試用例,線下的營銷系統裡的目前營銷活動的數量可能比生産要高一個數量級。是以營銷應用要在技術層面處理好線下這個場景,如果一個營銷應用會在啟動的時候就加載所有的目前活動,可能就會線上下出現很長的啟動時間。

資料的生命周期

我一直倡導的一個原則是“Test environment is ephemeral”,也就是說,線下環境的存在時間是很短的。存在時間短,要求create的成功率高、時間短,但對資料清理要求比較低。存在時間長的,就要求upgrade的成功率高,對create的要求很低,對資料完整性和測試資料清理的要求非常高。繼續推演下去,要做好測試資料清理,需要什麼?基建層有什麼技術方案?業務層需要做什麼?業務層是否需要對資料進行打标?測試資料清理這件事,是放在業務層做(基建層提供原子能力),還是在基礎設施層做(業務層按照規範打标)?這就是一個架構設計問題。這樣的問題,要有頂層設計、架構設計,要針對場景進行設計,不能有啥用啥、湊合将就。

業務流程

生産環境入駐一個商戶,會經過一個人工審批流程,這個流程也許會走兩三天,有六七個審批步驟。這線上上是OK的,因為線上的商戶入駐是相對低頻且能夠接受較長的處理周期的。但線上下,由于要執行自動化的測試用例,而且要確定測試用例是“自包含”的,商戶的建立就會是高頻,而且必須快速處理的。是以在技術層面,針對線下環境的場景,要能夠“短路”掉審批流程(除非本身要測試的就是審批流程)。類似的流程還有網關的映射配置,線上的網關配置是低頻的,但線下的網關配置是高頻動作,而且會反反複複。

3 其他

問題排查

線上環境是有比較清楚的基線的,比較容易把失敗的交易的鍊路資料和成功的交易的鍊路做比較。這個做法線上下環境同樣有效嗎?如果不是,為什麼?是什麼具體的線下環境的場景差異導緻的?又比如說,對日志的需求,線上線下有差異嗎?

權限模型

線下資料庫的權限,如果讀和寫的權限是綁定的、申請權限就是同時申請了讀和寫,就會很難受。因為工程師為了更好的做問題排查,希望申請上下遊應用的資料庫讀權限,但他們隻需要讀權限,不需要寫權限。如果讀寫權限是綁定的,即便他們隻需要讀權限,也要經過繁瑣的申請審批,因為涉及了寫權限,寫權限如果缺乏管控,容易出現資料經常被改亂掉的情況。讀寫權限申請的時候是綁定的,這線上上環境的場景下也許是OK的,因為生産環境要跑DML本身是有工單流程的,不容易出現資料被改亂掉的情況。但讀寫權限綁定線上下就不合适了。從架構和設計層面說,讀寫權限綁定是因為ACL的模型本身沒有支援到那個顆粒度。

我們一直說,做技術的要了解業務。比如,做支付系統的,要深刻了解不同的支付場景的差異(比如,代扣、協定支付、收銀台、…),才能有效的進行架構設計和技術風險保障。例如,代扣場景,沒有uid。這意味着什麼?沒有uid,意味着灰階引流的做法會不一樣,精準灰階的做法可能會不一樣,建立機房的切流方案也會不一樣。

線下環境也是類似的道理。線下環境也是一個場景。這個場景和生産是不同的場景。每一層(SaaS、PaaS、IaaS)都要深刻的了解不同場景的差異,才能有效的把不同場景都保障好。如果一個應用、一個平台,它的設計和實作隻考慮了X場景、沒有考慮Y場景,那麼它在Y場景下就會遇到這樣那樣的不舒服,也會使得Y場景下的客戶不滿意。

充分了解“線下環境”這個場景,把這個場景納入到架構和技術實作的考慮中,有助于讓線下環境盡量保持穩定。

四 結語

總結一下上面所說的一些關鍵點:

  1. 避免過多的籠統使用“環境問題”的說法。
  2. stable層首先要把單應用可用率提升上去。單應用如果無法做到99.999%或100%都是能調通的,鍊路的穩定性就是緣木求魚、根本無從談起。
  3. 減少dev環境的問題,主要有四個重點:a)做好聯調內建前的自測;b)架構上的投入(契約化、可測性);c)通過多環境、資料庫隔離等手段減少互相打擾;d)通過持續內建盡早暴露問題,降低問題的影響和修複成本。

Note

[1] 線下環境:這裡主要講的是網際網路應用的分布式系統的線下環境。也就是通常說的“服務端”的線下環境。這是阿裡集團和螞蟻集團裡面涉及技術人員最多的一類線下環境。

[2] 其實,很多”髒“資料一點都不”髒“。很多時候,”髒“資料隻不過是之前其他人測試和調試代碼留下的資料,但這些資料的存在使得後面的執行結果不符合我們的預期。例如,我要測試的是一個檔案打批功能,這個功能會把資料庫裡面尚未清算的支付都撈出來、寫到一個檔案裡。我建立了一筆未清算的支付,然後運作打批,我預期結果是檔案裡面隻有一條記錄,但打出來實際有兩條記錄,不符合我的預期。這種情況其實是我的預期有問題,是我的測試用例裡面的assert寫的有問題,或者是我的測試用例的設計、我的測試架構的設計有問題,也有可能是被測代碼的可測性(testability)有問題。

[3] 這些場景的差異,也許有人會把它們都歸結為“可測性”。這樣說也不是沒有道理,因為測試就是線下環境最大的一個作用。但我們還是不建議把線下環境這個場景就直接說成“可測性”,因為“可測性”是一種能力,能力是用來支撐場景的,這就好像“可監控”是一種能力,“可監控”這種能力是用來支撐線上環境這個場景的。

[4] 我們是堅決反對測試平台提供自動重跑失敗用例能力的,因為自動重跑對品質是有害的。自動重跑會掩蓋一些bug和設計不合理的地方,久而久之這些問題就會積累起來。

[5] 偶發bug也可以是很嚴重的bug。曾經有過一個bug,這個bug會以1/16的幾率出現。最後排查發現,原因是這段業務應用代碼在處理GUID的時候代碼邏輯有問題(而GUID是16進制編碼的)。當時的test case隻要rerun一下,大機率就會通過(有15/16的通過幾率)。

[6] 有噪音的測試,比沒有測試 還要糟糕。沒有測試,是零資産。有噪音的測試,是負資産。有噪音的測試,要額外搭進去很多排查的時間,而且還會損害大家對測試的信心(類似“狼來了”)。