首頁>科技>

簡介: 為什麼線下環境的不穩定是必然的?我們怎麼辦?怎麼讓它儘量穩定一點?

這篇文章想講兩件事:

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

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

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

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

以下是正文:

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

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

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

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

線下環境裡面有不穩定的程式碼線下環境不穩定帶來的影響小

這兩個原因是相互有關係的:我們需要有一個地方執行不穩定的程式碼,但我們怕不穩定的程式碼引起很大的問題,所以我們需要這個地方是低利害關係的(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環境放在一起一跑才發現跑不通的情況。

過去,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場景下的客戶不滿意。

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

四 結語

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

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

Note[1] 線下環境:這裡主要講的是網際網路應用的分散式系統的線下環境。也就是通常說的“服務端”的線下環境。這是阿里集團和螞蟻集團裡面涉及技術人員最多的一類線下環境。[2] 其實,很多”髒“資料一點都不”髒“。很多時候,”髒“資料只不過是之前其他人測試和除錯程式碼留下的資料,但這些資料的存在使得後面的執行結果不符合我們的預期。例如,我要測試的是一個檔案打批功能,這個功能會把資料庫裡面尚未清算的支付都撈出來、寫到一個檔案裡。我建立了一筆未清算的支付,然後執行打批,我預期結果是檔案裡面只有一條記錄,但打出來實際有兩條記錄,不符合我的預期。這種情況其實是我的預期有問題,是我的測試用例裡面的assert寫的有問題,或者是我的測試用例的設計、我的測試架構的設計有問題,也有可能是被測程式碼的可測性(testability)有問題。[3] 這些場景的差異,也許有人會把它們都歸結為“可測性”。這樣說也不是沒有道理,因為測試就是線下環境最大的一個作用。但我們還是不建議把線下環境這個場景就直接說成“可測性”,因為“可測性”是一種能力,能力是用來支撐場景的,這就好像“可監控”是一種能力,“可監控”這種能力是用來支撐線上環境這個場景的。[4] 我們是堅決反對測試平臺提供自動重跑失敗用例能力的,因為自動重跑對質量是有害的。自動重跑會掩蓋一些bug和設計不合理的地方,久而久之這些問題就會積累起來。[5] 偶發bug也可以是很嚴重的bug。曾經有過一個bug,這個bug會以1/16的機率出現。最後排查發現,原因是這段業務應用程式碼在處理GUID的時候程式碼邏輯有問題(而GUID是16進位制編碼的)。當時的test case只要rerun一下,大機率就會透過(有15/16的通過幾率)。[6] 有噪音的測試,比沒有測試 還要糟糕。沒有測試,是零資產。有噪音的測試,是負資產。有噪音的測試,要額外搭進去很多排查的時間,而且還會損害大家對測試的信心(類似“狼來了”)。

12
最新評論
  • 整治雙十一購物亂象,國家再次出手!該跟這些套路說再見了
  • 互相攀比發紅包,網際網路大廠被春節綁架了