不是技術也能看懂雲原生
雲原生越來越火了,無論是企業內部,還是技術論壇,上到應用架構,中到資料庫儲存,下到基礎設施,無不談雲原生。可是雲原生到底是什麼,容易讓人感到概念混亂不清。其實這不怪大家,這個概念太新了,不但大家困惑,業內大牛也在不斷的改變著定義,直到現在才稍稍有所統一。
一、混亂且不斷變化的雲原生定義
1.1.雲原生定義之亂
我們來看看這些大牛們都如何定義雲原生的:
2010年,WSO2技術總監PaulFremantle 首次提出Cloud Native,他一直想用一個詞表達一個架構,這種架構能夠描述應用程式和中介軟體能夠在雲環境中有良好的執行狀態。雲原生有以下特性 分散式、彈性、多租戶,子服務,按需計量和計費,增量部署和測試。
2013年,Netflix雲架構師,Adrian Cockcroft介紹了Netflix在AWS上基於Cloud Native的成功應用,Netflix在AWS上有上萬個例項。
2015年,來自Pivotal的Matt Stine,他的電子書《遷移到雲原生應用架構》,他認為單體架構在向雲原生架構的演進過程中,需要流程、文化、技術共同變革,該書把Cloud Native描述為一組最佳實踐,具體包含如下內容:十二因子,微服務,敏捷基礎設施,基於API的協作,反脆弱性。
2017年,Matt Stine在接受媒體採訪時又改了口風,將雲原生架構歸納為模組化、可觀察、可部署、可測試、可替換、可處理6特質;
而Pivotal最新官網對雲原生概括為4個要點:DevOps+持續交付+微服務+容器。
2015年雲原生計算基金會(CNCF)成立,最初把雲原生定義為包括:容器化封裝+自動化管理+面向微服務。
CNCF於2018年通過了對雲原生重新定義的提案,V1.0的定義如下:雲原生技術有利於各組織在公有云、私有云和混合雲等新型動態環境中,構建和執行可彈性擴充套件的應用。雲原生的代表技術包括容器、服務網格、微服務、不可變基礎設施和宣告式API。這些技術能夠構建容錯性好、易於管理和便於觀察的鬆耦合系統。結合可靠的自動化手段,雲原生技術使工程師能夠輕鬆地對系統作出頻繁和可預測的重大變更。
這裡面涉及到太多的專業詞彙,例如:
- 分散式,彈性,多租戶,子服務,按需計量和計費,增量部署和測試;
- 十二因子,微服務,敏捷基礎設施,基於API的協作,反脆弱性;
- 容器化封裝+自動化管理+面向微服務;
- 容器、服務網格、微服務、不可變基礎設施和宣告式API。
要了解雲原生一個概念,結果被丟擲來這麼多概念,這不越解釋越糊塗麼?
沒關係,如果你看不懂這些概念,就先放一放,後面我們會抽絲剝繭的來講解。
但是第一件讓我們困惑的事情是,這麼多大牛,在長達這麼長的時間內,前赴後繼的來研究和定義雲原生,他們這是幹啥呢?這玩意兒有那麼重要麼?
1.2. 雲原生是發揮技術部門價值的學問
這麼多大牛研究的東西當然重要了,究其本質是在網際網路模式下,如何才能發揮技術部門價值的問題。
為什麼這麼說呢?
因為我們從各行各業越來越網際網路化的趨勢中能夠發現,企業的技術人員比起原來可是越招聘越多,越招聘越貴了。原來只有簡單的開發和運維部,甚至大多數要靠外包和採購商業軟體解決問題,現在開始逐漸萌生出硬體採購部,基礎設施部,系統部,運維部,中介軟體部,服務架構部,資料庫部,大資料部,業務中臺部,業務開發部,前端開發部等等N多部門。
這個時候,給公司賺錢的業務部門肯定在想,公司養這麼多技術人員在幹嘛,技術部門的老大也會想,我養了這麼大的團隊,如何才能展現自己的價值呢?
第一點價值為業務創新。在網際網路大潮下,無論是網際網路企業還是傳統企業,都存在業務變化快的情況,傳統的商業模式被飛速的打破,新的商業模式和玩法只有想不到,沒有做不到,這個時候,業務部門最不想聽的技術部門說的一句話就是,業務部門都想好了新的打法玩法,結果技術部門做不出來,這下技術部門丟人就丟大了,也就沒有了價值。
第二點價值為系統穩定。也就是當前執行著的系統不要掛,不要業務員正依靠系統做活動或者辦業務,結果系統老是刷不出來,肯定會被詬病。
第三點價值為成本優化。雖然IT投入會越來越多,但是商業競爭還是殘酷的,如何提高資源的利用率,在儘量少的資源的情況下,保證業務的創新和穩定,是價值的體現。
第四點價值為技術創新。任何一家公司的技術部門都是希望能夠構建技術影響力的,而且一家沒有技術創新和技術影響力的公司,是無法吸引好的IT人才的,也就沒有辦法保證業務創新和穩定。
然而這四點價值其實是有矛盾的,比如創新就要快速開發,如何同時保證穩定呢?再比如系統穩定需要做多副本的冗餘,那如何成本優化呢?成本優化就要做改造,一折騰,系統可能就不穩了。再比如技術創新引入新技術,成本就會高,新技術就會不穩,咋辦?如果成本控制很嚴,三年五年不創新,IT人員都跑了,到時候想開發新系統,找不到人,咋辦?
這裡面的各種度是很難把握的,我就見過有的企業未來創新,大刀闊斧的系統重構,結果導致系統長時間不穩定,被業務部門投訴從而背鍋的事情。
這也是這麼多大牛,包括國內的CIO們不斷討論如何解決這個問題的原因。
為了解決業務變而系統穩這一對矛盾,大牛們不斷摸索,從而構建了一套目前看來邊界尚未清晰的體系,最終命名為雲原生。
接下來我們沿著大牛們逐漸摸索的道路,看一下雲原生到底是什麼?
二、第一階段:基於虛擬化的雲原生探索期
2.1. Netflix的雲原生分享
讓我們把時光拉回2010年左右,那是一個傳統Web類網站榮光已過,新一代網際網路應用逐漸崛起的時代。傳統Web類網站國外的代表是雅虎,國內的代表是新浪,搜狐,網易。而新一代網際網路應用,包括電商,視訊等都開始崛起。
在國外有一家公司Netflix,本來是做傳統的DVD發行服務的,2007年變為線上視訊公司,實現網際網路化,在2008年正面臨著業務快速發展而穩定性變差的壓力,這家公司摸索這樣一條道路,就是上雲,當時雲端計算市場沒有太多選擇,Netflix選擇了AWS,來解決穩定性問題,擴容問題,業務快速發展問題。
經過幾年的實踐,2013年,Netflix雲架構師,Adrian Cockcroft介紹了Netflix在AWS上基於Cloud Native的成功應用,Netflix在AWS上有上萬個例項。在這個演講裡面,Netflix分享了他們如何基於雲解決問題的。
我貼了幾張當時分享的PPT截圖,如果您不是技術,可以不用關注其中的細節。
第一張圖說明了Netflix使用了大量的AWS服務,並且和自己的資料中心做了打通。
第二張圖看起來比較頭暈,密密麻麻紛繁複雜的的服務之間的呼叫,不過你也不用管他。當時雲原生和微服務還沒有火,也談不上追風口,Netflix是真的因為業務的演進事實性的架構變成這樣的,完全處於業務的需要。
2.2. Netflix與Spring Cloud小插曲
這裡有一個小插曲,現在開發大型分散式系統的主流語言之一是Java,而Java最火的框架之一是Spring,這個框架誕生於2002年,運營他的公司叫springsource,2009年被Vmware收購。
2013年,Vmware、EMC和通用資本合資成立了一家公司叫Privotal,記住這個名字,後面他還會出現。
在Spring基礎上,2014年Privotal釋出了Spring Boot的第一個release版本,你可以認為這是升級版。同年,以Spring Boot為核心的一套分散式應用開發模式Spring Cloud誕生。
模式只是抽象的模型,底層實現可以不同,而Netflix的Spring Cloud Netflix於2015年釋出第一個版本,是最重要的實現之一。一度一提Spring Cloud,就是Spring Cloud Netflix,這正是上面那個網狀的分散式架構的結晶。
2.3. Netflix的雲原生動因
我們回到那次演講的PPT,在下面一頁,Netflix表明了他為什麼要這樣做。
雖然當時雲原生的概念還處在初級階段,但是Netflix在這裡的表述已經從實踐角度非常全面的描述了未來雲原生的方方面面,以至於多少年後,當我們的業務真的發展到某個程度,回過頭來再看這頁《Outcomes》PPT,才理解其中真意。
如果讀到現在你還不能完全理解,則目前僅需關注其中三點,後面回過頭來再說。
第一點:微服務是為了關注點分離(seperation of concern),這是業務層敏捷的關鍵。
這一點其實很好理解,是源於人類思考問題的物理極限。就像按照組織行為學研究的那樣,一個人經歷再旺盛,最多直接領導10-20個人就了不起了,再多一定會效率低下,必須要分子團隊。同理,人類關注問題也一樣,把太多問題混在一起,所有人一起關注,一定不會清晰,一定管理混亂,一定效率低下,要拆分子問題。於是一個大的服務就不斷拆分成子服務甚至微服務,最終每個服務聚焦解決一個子問題,被少量的人關注,則邊界清晰,決策容易,開發速度快,業務敏捷就體現出來了。
當然微服務的實施也是有成本的,因為服務數目多,就一套機制將多個服務統一管理起來。
比如要有註冊和發現機制,服務少的時候,哪些服務可以呼叫,IP是多少,域名是多少不需要怎麼管理,但是一旦服務數目多到上面那張圖,就需要維護一個登記簿管理系統內所有的服務地址。服務啟動的時候會向登記簿註冊自己的地址資訊。當一個服務的域名或IP地址改變了之後可以及時通知依賴方,或者依賴方可以快速的發現服務提供方的地址變化。
再比如要有統一的配置中心,原來一個程式執行,配置放在本地也容易查詢和管理,如果服務數目多了,配置要放在一個集中的地方,才能散而不亂。
我們稱這些為服務管理機制。
第二點:開源實現程式碼共享,是開發敏捷的關鍵。
分散式微服務的開發所需要的新的模式,例如註冊,發現,配置都需要額外的程式碼來適配這種模式。這時候問題來了,每當有一個新的需求要開發一個新的服務,原來都是拷貝一份程式碼,重新造個輪子,開發效率比較低下,還容易出錯,程式碼無法形成標準,很難維護。利用現有的開源軟體,形成開源標準,一方面新開一個工程要容易的多,也標準的多。另外當需求緊張的時候,公司的人員可以在組之間借調,如果部門牆很重,這個部門看不懂另外一個部門的程式碼和框架,那很難形成人力資源池,而開源也解決了這個問題。
第三點:用雲實現資源的彈性,是資源層敏捷的關鍵。
服務數目的增多必然會對資源的靈活性造成一定的壓力,如果不能夠實現快速敏捷的部署,要運維上面那個網狀的架構,運維得累死。
Netflix使用了一種基於虛擬機器映象的敏捷部署機制,如下圖所示,對於要釋出的一個新的應用,會用虛擬機器映象打包一個執行環境,無論複製多少份,無論是在開發,測試,生產部署,都能夠保持環境的一致性,這樣會大大增加發布的效率。
在《Outcomes》那一頁提到了immunitability,也即不可改變基礎設施,這裡的意思是,所有對於部署環境的改變都要通過釋出系統來改變,一旦釋出就不再改變,如果要改變就重新走一次釋出,而不能私自登陸到某臺機器上去做改變。這是因為Netflix已經有上萬臺伺服器了,如果允許私自登陸做改變,那這種改變是無法追溯的,一旦出現了問題也不知道是因為哪次改變導致的問題發生,而且又沒辦法登陸到機器上一臺臺的定位,所以就讓釋出系統追溯對於環境的改變。
其實這裡的很多思想以及十分接近容器了,只不過那個時候還沒有容器罷了。
這三點我畫了下面一個圖,和我們們的技術架構對應起來,就比較容易看明白了。
總而言之,在這個階段,Netflix是通過充分利用雲的彈性和敏捷,利用開源標準,促進業務微服務化和快速迭代,滿足業務需求。
2.4. Netflix雲原生實踐的遺留問題
Netflix雖然很牛,在大規模落地雲原生方面給全世界的人打了個樣兒,但是對於整個行業來講,大家看到的還只是這個PPT,感覺這個思路不錯,至於如何落地仍然心裡沒有譜,大家仍處在各自為政的摸索階段。
比如Netflix為了基礎設施層的彈性和敏捷,堅定的選擇了使用AWS上的服務,這在Netflix上雲的那個時刻,其實雲服務沒有太多的選擇,但是後來不一樣了,雲廠商越來越多了。很多企業意識到了雲平臺彈性和敏捷的重要性,但是不願意像Netflix一樣綁著一家雲廠商玩到底,於是一度開始建設私有云平臺,並試圖形成行業的標準,當時發展的如火如荼的OpenStack社群就被給予厚望,各種平臺爭相遵從OpenStack的介面標準,從現在的角度看,這種統一IaaS的嘗試並沒有成功。
再如開發框架Netflix自己使用並且開源貢獻了Spring Cloud Netflix,也只是在比較新的Java分散式應用開發方面形成了一定的業界影響力。但是很多網際網路企業在發展過程中,根據不同的業務模式,不同的開發語言,不同的技術演進路線,也有了自己的分散式應用開發框架,也是各做各的,沒有形成標準。
於是整個行業處於下圖的狀態,雲已起航,但無法形成標準,其他方面,各做各的。
三、第二階段:跨環境場景下的標準形成期
3.1. Pivotal與雲原生的故事
這種無標準的狀態不利於行業的飛速發展,不過這些Netflix都不在乎,他是做業務的,而非以開源軟體為生的,只要能夠滿足自己的業務需求就可以了。2018年,Netflix 宣佈 Spring Cloud Netflix 系列技術棧進入維護模式,也即不再新增新特性了。業內很多用了Spring Cloud Netfix的也不得不尋找替代方案。
從表中可以看出Netflix不再維護之後,官方有了替代的實現方案,很多網際網路廠商也有了替代方案。
這個表裡面最左面的一列又是很多的新概念,這裡面的分散式配置和註冊發現,我們前面講過了,是一個分散式微服務系統所必備的。這裡又出現了路由,熔斷等其他的機制,這些是幹什麼的呢?我們還是回到《Outcomes》那一頁,裡面還有一個詞叫anti-fragile,叫反脆弱,說白了是如何保持整個系統的穩定性的問題,能不能有一些機制,使得系統沒有那麼脆弱。其實微服務已經比原來的脆弱性好多了,原來一個應用,掛了就都掛了,現在服務數目多,掛了只掛一部分,但是這個時候掛的這部分到底對於整套系統的影響是什麼呢?能不能影響儘量小呢?這就是反脆弱。常用的方式就是進行服務治理,說到治理,你有沒有想到城市治理,交通治理等,意思是類似的,就是通過一些機制,減少意外造成的影響,比如一個地方出了車禍,會越來越堵,就需要治理了,路由就是已經出門的能不能改條道路走,熔斷就是沒出門的先別出門了,從而降低影響面,直到交通恢復正常。我們稱這些問服務治理機制,圖中Spring Cloud的相應的元件中就有是做服務治理的。
說到Spring Cloud官方,前面的小插曲要繼續了。
Pivotal作為Vmware和EMC成立的子公司,明顯就是To B的一家公司,雲原生的標準問題Netflix不關心,Pivotal當然很關心,這對To B公司來講是巨大的一個機會,一個在IaaS已經殺的昏天黑地後的PaaS層的機會。
而且在這個方面Pivotal有著得天獨厚的優勢。背靠Vmware,IaaS層有天然的合作優勢。手握Spring Boot和Spring Cloud社群,開發框架層次也有話語權。在中間的跨雲的執行標準,他還有另一個法寶Cloud Foundry。這個軟體2009年被springsource收購,後來和Spring一起被Vmware收購,後來就歸了Pivotal,他主要解決跨雲服務的執行和生命週期管理的標準化問題。
有沒有感覺Pivotal一下子湊夠了七龍珠的感覺。於是我找了一張Pivotal的PPT,如下圖所示。
這裡面多雲雖然難形成統一標準,但是有Vmware這個私有云第一品牌做靠山,加上很多企業喜歡建設公有云,則誰不得給點面子。跨雲的執行標準和編排標準用Cloud Foundry覆蓋,這裡解釋一下,任何一個程式的執行都需要一個環境,將這個環境標準化稱為執行標準,對於複雜的業務會有多個程式執行,並且互相有一定的關係,維護多個程式執行的相互關係並且形成標準稱為編排標準。開發標準Pivotal有Spring Boot,以及分散式應用開發標準Spring Cloud,同時也是服務治理的標準。
3.2. 雲原生十二要素與Cloud Foundry
於是Pivotal定義了雲原生十二要素,後來又補充了三個,從而開始有了標準的樣子。
這裡的要素其實覆蓋了:
- 執行標準的問題,例如一份程式碼,多份部署,優雅啟動和關閉,而且環境等價
- 編排標準的問題,例如依賴關係,明確埠,以服務的形式關聯
- 彈性的前提,例如無狀態,水平伸縮
- 集中管理的問題,例如配置中心,日誌中心。
這樣一個公司的業務是否符合雲原生,就可以根據這十二個原則來衡量。
可是原則畢竟是虛的,在實現層面還需要有個標準,Pivotal給的方案就是Cloud Foundry,他的架構非常複雜,如下圖所示,覆蓋雲原生的十二要素,並且是一個跨雲的PaaS方案。
這個圖是一個比較新的圖,裡面有了Docker容器,在早期的Cloud Foundry裡面,是另一種容器叫Warden,他主要使用了兩種技術namespace和cgroup。
容器技術,是一種將一臺大的伺服器切割為獨立且隔離小箱子,從而每個小箱子裡面可以執行獨立且隔離的應用。容器主要使用了兩種技術,一種是看起來是隔離的技術,稱為 Namespace,也即每個 Namespace中的應用看到的是不同的 IP地址、使用者空間、程式號等。另一種是用起來是隔離的技術,稱為 Cgroups,也即明明整臺機器有很多的 CPU、記憶體,而一個應用只能用其中的一部分。從這裡可以看出Cloud Foundry對於容器的理念,已經和後面產生的Docker容器非常接近了,但是他卻沒有解決一個問題,就是跨雲的平滑遷移問題。
在虛擬機器時代,跨雲是一個相當難的事情,因為雲主機的映象是不能在雲之間隨意的遷移的,如果一個業務想部署在多個雲上,一般採取的方式是在不同的雲上建立不同的雲主機,每臺雲主機上安裝一個agent,agent通過拉取各種安裝包在不同的雲上部署類似的程式。當時業內幾乎都是這樣做的,別無他法,Cloud Foundry也不例外,雖然他也有容器的概念,通過namespace和cgroup技術進行應用隔離,但是他仍然採取這種傳統的方式,buildpack進行打包,DEA元件Droplet Execution Agent,用於管理應用例項的整個生命週期,也即下載,解壓,執行應用程式。
這種模式的缺點,一是比較重,每個雲建立的虛擬機器都是空的,要全部重新安裝應用。二是不標準,不同的雲建立的虛擬機器裡面的環境多少都有差異,相同的指令碼有時候執行的好,有時候不行。
3.3. Docker橫空出世
後來就有了Docker,這家2010年就建立出來的軟體一開始名不見經傳。Cloud Foundry覺得Docker同樣使用了類似的namespace和cgroup技術,並沒啥新鮮的。
然而Docker除了上述兩個技術,還有一個法寶,就是映象,一個看起來沒有那麼有技術含量的東西,卻產生了深遠的影響。
所謂的映象,就是將你焊好集裝箱的那一刻,將集裝箱的狀態儲存下來,就像孫悟空說:“定”,集裝箱裡面就定在了那一刻,然後將這一刻的狀態儲存成一系列檔案。這些檔案的格式是標準的,誰看到這些檔案都能還原當時定住的那個時刻。將映象還原成執行時的過程(就是讀取映象檔案,還原那個時刻的過程)就是容器執行的過程。
雖然上面我們講過Netflix基於AWS的虛擬機器映象也實現了類似的功能,但是虛擬機器映象是非標準的,不同的雲不一樣,而且非常大,動不動就幾百G。
容器的映象就小很多,在MB級別,而且重點在於標準,一旦有這個映象,無論在哪個雲,哪個環節部署都能得到相同的容器內的環境。這個特性使得Docker既能在開發,測試,生產環境之間進行標準化遷移,也能在多雲間進行標準化遷移,真正實現雲原生的執行標準。
3.4. Kubernetes統一編排標準
執行標準有了,接下來就該編排標準出現了。
2014年,Google推出Kubernetes,並且發展迅速,很快微軟、RedHat、IBM、Docker都加入了社群。當然空白的編排市場豈能讓Kubernetes一家獨佔,很多其他的編排系統也虎視眈眈。2009年產生了一款軟體mesos,被引入了Twitter進行了大規模的落地,這是一款排程演算法非常牛的軟體,被用在spark這種大資料處理領域,需要高效的排程大量容器的場景,非常有效,到了雲原生時代,mesos社群推出了marathon做線上業務程式的編排,成為Kubernetes強有力的競爭者。2016年,Docker在自己成為執行標準之後,開發發力編排標準,大力推廣swarm進行容器編排,由於和Docker社群相容性好,也成為kubernetes的強有力的競爭者。Kubernetes可謂前有攔截,後有追兵。
Kubernetes走的路和另外兩家不一樣,mesos強在有大規模落地案例,側重於以排程為核心,引入很多其他框架形成雲原生生態DCOS(資料中心作業系統),但是DCOS裡面的元件各種語言都有,相比於mesos的成熟,這些元件繁雜且成熟度低,而且並沒有在面向業務的編排標準上下功夫。swarm強在運維簡便,上手容易,也沒有在面向業務的編排標準上下功夫。唯有Kubernetes,既不著急穩定下來,也不著急簡化運維,而是定義了一大套的概念,初看非常困惑,仔細看發現這才是面向雲原生的標準定義的思路,Google和Redhat就是不一般,一流的公司定標準,此言不虛。
我還專門寫了一篇文章,詳細分析了Kubernetes才是真正的站在雲原生業務的角度來編排容器。為什麼 kubernetes 天然適合微服務
下圖是Kubernetes定義的那些複雜的概念,和雲原生十二要素的要求一對應,就讓人恍然大悟了。
這裡麵包含了執行時的標準Docker。
編排用Deployment和Service,服務註冊發現用Service。
例如相互依賴的四個服務,全部部署在容器裡面,分別執行在不同的機器上面。服務之間的呼叫通過服務名稱進行,而非固定IP進行,而服務名稱Kubernetes會用Service管理起來。
當一臺伺服器當機的時候,服務B和服務C會被自動排程到另外兩臺機器上,這時候服務A和服務D如何再找到服務B和服務C呢,這兩個服務的物理主機變了,很可能IP也變了。其實是沒有問題的,Kubernates會自動將服務名和對應的IP地址關聯起來,服務之間只要配置的是服務名,而非IP地址,就依然能夠相互訪問。
彈性是通過Deployment,HPA實現的。通過改一個副本數,就能夠實現程式的橫向擴充套件,程式執行的環境全部標準的封裝在Docker映象裡面了,外部依賴全部在Deployment的編排文字里面定義好了,只需要改數字就可以了。
在集中管理方面,Kubernetes自帶配置中心,註冊發現,對於日誌中心,監控中心都非常容易整合。
可以說除了服務治理Kubernetes稍有欠缺外,其他能覆蓋雲原生的方方面面。
Kubernetes還有一個亮點,是他是基於宣告式API的,這和傳統的運維模式有所區別。傳統的運維模式是面向動作的,比如說需求是啟動三個應用,那面向動作的運維就是找三個地方,把三個應用啟動起來,檢查啟動沒有問題,然後完事兒。稍微自動化一點的,就是寫個指令碼做這個事情。這種模式的問題是一旦三個應用因為某種原因掛了一個,除非人工檢查一遍,要不就沒人知道這件事情。而宣告式API是面向期望狀態的,客戶提交的期望狀態,kubernetes會儲存這種期望狀態,並且會自動檢查當前狀態是否和期望狀態一致,如果不一致,則自動進行修復。這在大規模微服務運維的時候更加友好,因為幾萬個程式,無論靠人還是靠指令碼,都很難維護,必須有這麼一個Kubernetes平臺,才能解放運維,讓運維只需要關心期望狀態。
比如有個程式,狀態一定要是三個副本,每個副本都能在1s內返回,共能承載每秒N筆的QPS,如果用傳統的運維模式,極有可能出現看起來是三個副本,其實有兩個已經不能響應請求了,或者能響應要10s才能返回,這樣雖然表面看起來這個程式是處於高可用的狀態,其實非常危險,剩餘的那個節點一掛,可能就都掛了,或者突然來了客戶流量,另外兩個節點根本扛不住幾個客戶請求。如果用Kubernetes,配合裡面的副本數,健康檢查,服務發現功能,如果有兩個不能響應或者響應過慢,自動就會銷燬重新建立,直到達到標準,並且加入服務,共同承載流量。這樣只要給Kubernetes的編排檔案寫的好,通過介面看到的狀態就可以預設為是真實的狀態,這樣哪怕有一萬個服務,運維起來也很簡單。
設計如此好的一套雲原生標準,很快在各大企業實踐開來,形成如下的樣子。
四、第三階段:跨語言服務治理的標準形成期
前面講Netflix的時候,我們說過業務層的拆分對於運維層的敏捷性帶來了巨大的壓力,從而Netflix基於AWS實現了基礎設施的敏捷性。事務的作用是相互的,基礎設施層因Kubernetes使得敏捷性,可遷移性,可運維性更加容易的時候,又會對業務層的拆分有進一步的促進作用。這就像我們們的電腦和手機,隨著裝的應用越來越多,需要的資源越來越多,會對電腦和手機的配置造成壓力,逼著電腦和手機有更強的CPU,記憶體,硬碟。可是一旦電腦和手機的硬體升級了之後,我們又會裝更多的應用,如此反覆。
但是當服務數目多了,不僅僅對於基礎設施層有壓力,對於自己如何管理也有很大的壓力,雖然一個大服務拆分成了微服務,不會整個掛掉,但是服務之間是相互關聯,相互影響的,就如同Netflix那張圖一樣。雖然通過註冊發現等服務管理機制,可以看到服務之間的關係,但是服務之間的影響卻很難評估,因而為了《Outcomes》裡面的反脆弱,需要防止以下的幾件事情發生:
- 服務雪崩:一個服務掛了,拖累其他服務掛掉一片
- 請求堆積:一個服務慢,拖累整個鏈路慢一整條鏈
- 效能瓶頸:找不到整個服務的效能的瓶頸點
4.1. 服務治理反脆弱的五大場景
要解決這些問題,需要服務治理機制,就像我們前面打過的比方,就是交通治理。現在我們仔細解析一下如何治理。
我們把複雜的服務之間的關係簡化成為一個三層呼叫的關係,如下圖。每個程式會有三個副本,每個程式會多個執行緒,而業務邏輯就是在某個執行緒裡面處理的。比如程式A裡面的業務邏輯是下單,如果兩個人同時進行下單,處理這兩個人的請求可能會被分配到兩個程式副本里面的兩個執行緒,也可能會被分配到一個程式裡面兩個執行緒。A業務的請求處理,需要B,C,D三個上游的業務都完成A才能完成,如果A是下單,B可能是商品,C可能是庫存,D可能是優惠券,這些落地的處理也會被分配到某個B,C,D的某個副本里面的某個執行緒。B也是有上游的,需要E和F都完成B才能完成,假設E是商品的價格,F是商品的規格。
接下來我們來看如果進行服務治理反脆弱。
第一種場景稱為容錯。如下圖所示,這裡面程式F的第2個副本里面的某個執行緒已經處理了1分鐘沒有返回了,這在服務呼叫已經是很長時間了,肯定是某個地方卡住了。但是這裡也會帶來連鎖效應,F不返回,則B程式的某個執行緒會一直等著他,也會被卡住,同理A程式的某個執行緒也會被卡住。而且一個系統裡面的匯流排程數是有限的,卡住一個就少一個,最後使用者請求都進不來了。
這有點像我們們交通堵塞,一個路口出問題被堵住,如果不及時處理,那上一個路口的車都湧過來也會被堵住,從而一堵就很長的一條路。但是車道和路就這麼幾條,那最後誰都別走了。那怎麼辦呢?當然是及時處理,先通暢了再說。
這裡採取的治理策略是快速失敗(Failfast)及失敗轉移(Failover),也即每個服務的呼叫都設定超時時間,比如1s,超過了就不再等了。如圖中F的某個副本不知道為什麼卡住了,不管,超過一定時間就重試呼叫另一個副本,這樣至少B裡面的執行緒不會卡住,A裡面的也不會卡住,這樣故障點就只有程式F的某一個副本,脆弱性就控制在了很小的範圍內了。
第二種場景是熔斷和降級。情況比上面要更加嚴重一些,這次可不是一個F副本出問題了,而是所有的F都出問題了,比如所有的F都1分鐘返回,甚至整個F都掛了,B肯定會收到一個呼叫F的錯誤,這可咋辦?如果處理的不好,如果B錯了就掛了,那接下來A也會掛掉,於是整個鏈條都掛了。
這裡我們做另外一個比喻,比如B是一家小超市,超市的老闆每天早上從菜市場E那裡採購牛肉,從菜市場F那裡採購牛雜,A是一家小牛肉麵館,每天早上從B這裡採購牛肉牛雜,C這裡採購面,D這裡採購一些冷盤。如果有一天菜市場F裡面所有賣牛雜的都起晚了,或者都倒閉了,超市應該關門嗎?如果A發現有一天採購不到牛雜了,牛肉麵館應該關門嗎?當然不應該了。
這裡採取的治理策略是熔斷和降級。所謂的熔斷,就是發現所有的F都有問題了,那就先不呼叫F了,但是B也不要掛掉,而是在有缺陷的情況下執行,等待F被修復,這樣故障點就被控制住了,只要F這一個服務被修復好了,整條鏈路就都好了,如果掛一條鏈路,那還得修復了F,再修B,修完了B再修A,那時間就長了,脆弱性就強了。
那這個時候B沒有F的返回資料如何執行下去呢?這就是降級,常常採取的手段是返回一個預先設定好的值,或者從快取裡面拿一個不那麼實時的值。比如想獲取庫存數目,真實的庫存只有4件,但是發現庫存服務不響應了,無法獲取這個值,則可以返回一個“有庫存”作為預設值,並且設定一個最大可以賣出去的值比如10,那最壞的情況就是多賣出去幾件,如果商業模式允許,也沒啥問題。比如想獲得商品規格,可以定時重新整理一部分到快取裡面,如果商品服務不響應了,那就去快取裡面拿,可能實時性有問題,但是如果重新整理不頻繁,也可以接受。
可能你會問,是不是所有的業務場景都能熔斷和降級呢?當然不是了,如果要支付,但是無法獲得準確的金額,那肯定不行。如果要下單,使用優惠券,發現獲取不了優惠券的扣減資訊,也是不行的。因而我們把服務之間的依賴分為強依賴和弱依賴,牛肉麵館沒有牛肉和麵,今天生意就做不下去,這是強依賴,不可以熔斷和降級,但是如果牛肉麵館沒有冷盤,生意還是可以做下去的,這是弱依賴。這就需要我們能夠分析出強弱依賴,其實服務之間的依賴關係看起來紛繁複雜,但是真實一個業務中,完全強依賴的整條鏈路還是其中很少的一部分,這部分我們長成為核心交易鏈路,或者核心呼叫鏈路,這條鏈路是一個環節出問題整個業務就執行不下去的,是整個團隊要重點關注的部分,好在這部分非常少,比如電商裡面,只有下單,支付的鏈路是比較核心的,哪怕瀏覽商品這些,都可以降級。
第三種場景是限流。任何一個系統無論擴容到如何規模,能夠承載的最大流量是有限度的,每一個模組也是一樣的,這個時候如何再來更多的使用者請求,很可能讓整個系統全部掛掉,最後誰也用不成,因而經常使用的手段就是限流。其實就像故宮每天的遊客限流類似,如果人太多,不但破壞文物,而且光看人了,誰也玩不好。
第四種場景是路由分流與灰度。
除了上面出現異常情況導致系統脆弱,其實變更才是最脆弱的。因而每個服務上線之前,都要經過灰度,如下圖,比如某個功能需要A服務開發一個新功能,C服務開發一個新功能,會形成一個灰度環境,可是這裡的新功能是否能夠保證完全正確呢?當然不能,即便經過嚴格的測試也不能,因為測試環境無法模擬生產環境的所有情況,所以要有分流和灰度措施,比如切分1%的流量到灰度環境,如果有問題,也隻影響1%的使用者,而且可以瞬間切回來。
第五種場景是全鏈路效能監控。
一旦出現了效能問題,其實像交通治理一樣,我們希望能夠看到到底哪條鏈路出現了問題,以及在這條鏈路的哪個環節出現問題。
看這個服務之間的呼叫圖,裡面可以像看地圖一樣,看到紅色的鏈路表示出問題了。這個圖和Netflix那個圖不一樣,那個圖是通過註冊發現畫出來了,僅僅表示關係,但是服務之間的呼叫效能沒有健康,而全鏈路監控需要另外一個APM的系統獲得。
全鏈路監控的思想最初來自於Google的論文提到的Dapper,他會將服務之間呼叫的效能資料通過tracing日誌的形式集中儲存起來分析,從而可以集中展現和定位分散式系統裡面的問題和效能瓶頸。
例如對於某個慢的請求,我們可以通過全鏈路監控看到每層呼叫所花費的時間,如下圖。
4.2. 當前服務治理的問題與Service Mesh的誕生
通過這五個場景,我們會發現,治理的場景還是很複雜的,而且目前業內也沒有一定的標準。下圖是目前比較主流的集中治理方式的選型,而且都是針對Java語言比較友好些。
當前的方案有幾個問題:
- 和應用是綁在一起的,執行在一個程式裡面,無法獨立升級和維護
- 支援Java比較友好,跨語言比較複雜
怎麼解決這些問題呢?一個普遍的思路是將服務治理功能獨立成為一個程式來實現,每個應用都會有一個服務治理程式陪著他,攔截應用發出和接收的所有流量,經過治理策略後再轉發給自己或者其他服務。還記得小時候看鬼子進村的時候開的這種摩托車麼?主駕駛員旁邊會帶著一個人,這個位置叫邊車sidecar。這個獨立做服務治理的程式因為總是在主程式旁邊攔截流量,也被稱為sidecar。
除了sidecar之外,服務治理的策略也需要一個地方統一管理,也即需要一個控制面,兩者加起來,稱為Service Mesh。
2017年,Google,IBM,Lyft聯手釋出Istio,逐漸成為Service Mesh服務治理標準。
下圖是istio的架構圖。
在Sidecar裡面,分流灰度,熔斷降級,限流等都可以做,而且還可以對接統一監控Monitoring和全鏈路監控Tracing。
目前istio已經在很多企業落地,但是說已經成為通用標準,為時尚早。
4.3. 服務治理反脆弱階段的工作模式
一旦服務數目多到需要治理的階段,其實工作模式也需要相應的變化。前面講到超時時間,可是每個服務都不一樣,有的服務可能本來時間就會很長,有可能是整合了外部系統,連優化都沒辦法,這怎麼辦呢?比如熔斷降級裡面,哪些是強依賴,哪些是弱依賴,返回什麼樣的預設資料,如何快取,這些都是和業務相關的,不同的服務也不一樣。再比如限流裡面,每個服務能夠承載的吞吐量也是不一樣的,有的服務比較邊角,也沒必要優化到效能吞吐量過於好。
這個時候你發現,和傳統的應用中,一個技術總監或者運維總監掌控全域性的時代過去了,已經沒有一個人可以掌控系統的全部了,對於服務的治理需要從集權到民主,是不是理解Netflix的說法了,我們回到《Outcomes》那一頁,要信任員工和團隊。每個服務都會有一個小團隊進行維護,一方面滿足快速迭代,一方面保障質量,服務的Owner像牛肉麵館老闆一樣思考,從上游服務進貨,為下游提供服務。每個層次的服務根據依賴的服務和中介軟體的約定來預估自己對於下游客戶的SLA約定,包括高可用性,QPS(每秒查詢數),TPS(每秒交易數),MRT(平均返回時間)。每個服務梳理強弱依賴關係,並採取相應的策略。
比如上游E服務約定的QPS和TPS的值應該預設認為他能達到,如果不滿足,E服務會自己擴容,和你無關,但是如果你超過了約定的值,E服務是有權力自己進行限流的,你要根據你依賴的上游算一個自己的QPS和TPS,並且對於超過的部分也進行限流。
對於上游E服務約定的MRT,是你設定呼叫他超時時間的參考,如果真超時了,就說明E出問題了。如果E沒有超過約定的MRT值,但是你仍然感覺太慢了,無法滿足你對上游的MRT承諾,這個時候,你就需要通過非同步呼叫或者訊息佇列的方式,讓這個慢的部分非同步的完成。
對於弱依賴,你要想好如果掛了怎麼辦,太慢了怎麼辦各種場景。對於強依賴,仍然要考慮後面掛了或者慢了,雖然不能正確返回了,但是如何不被弄掛。
當然對於核心呼叫鏈路上的每個服務,高可用,QPS, TPS, MRT都是會嚴格要求的,這才是技術總監或者總架構師應該重點關注的地方。
經過這個步驟,一個企業的架構如下圖所示,業務部門只要關注業務本身就可以了。
五、第四階段:大量業務使用雲原生的規模落地期
在企業開始大規模落地雲原生的時候,還是會遇到很多問題的,我專門寫了一篇文章闡述這些問題:一篇文章搞定大規模容器平臺生產落地十大實踐
第一個問題是如何相容原來的傳統運維釋出模式。大部分企業都有自己歷史包袱,哪家公司也不可能上來就完全按照雲原生的標準操作來,因為在公司內部,業務方是甲方而容器方是乙方,得根據業務的節奏來。於是業內湧現出很多的富容器的概念,就是經過容器層的修改滿足固定IP,原地升級,可SSH登陸等功能。
支援Pod 繫結靜態 IP ,基於K8s的自定義控制器—Enhanced Statefulset
第二個問題是容器的隔離性的強化。前面講過容器是根據namespace和cgroup進行隔離的,但是對於習慣了虛擬機器隔離的應用來講,這兩種隔離顯然不夠,需要加強。
第三個問題是當K8S節點數目超過一定數量後,效能會有瓶頸,這個時候如何進行優化呢?這個時候有兩個選擇,一個是直接修改K8S原始碼支援超大叢集,一個是採取多叢集的K8S。雙方各有各的優缺點,前者優點是可以一個叢集容納上萬個節點,維護叢集數目少,缺點是可能對於K8S的核心程式碼改動比較多,將來K8S版本升級複雜。後者的優點是可以在不改K8S核心程式碼的情況下做引數調優,升級容易,缺點是調優後規模5000節點,如果規模大,需要維護更多的叢集。
如何用 Kubernetes 管理超過 2500 個節點的叢集
[譯]將 Kubernetes 擴充套件至7500個節點
PPT | 騰訊雲多Kubernetes的多維度監控實踐
第四個問題是K8S網路如何選型的問題。有以下幾種方式,一是使用開源元件Calico等,二是對於效能要求比較高的會使用硬體SDN,三是如果自己有云網路VPC團隊的,或者基於雲上容器平臺的,會使用虛擬網路,四是直接使用host網路,效能好,只是埠需要管理,需要比較好的應用層適配及註冊發現機制,五是通過橋接方式使用扁平網路,這種方法相對比較簡單。
第五個問題是有狀態儲存。大部分採取兩種方式,一是如果有儲存團隊的,則會構建統一物件儲存或者檔案儲存,二是使用本地儲存,簡單,就是管理麻煩一些,三是使用商業化儲存,這在傳統行業比較多一些。
第六個問題是映象如何下發的問題。現在Harbor映象倉庫成為主流,網際網路公司因為下載壓力比較大,會使用另一種P2P的映象下發模式。
騰訊WeMake工業網際網路平臺的邊緣容器化實踐:打造更高效的工業網際網路
ImageApparate(幻影)映象加速服務讓映象分發效率提升 5-10 倍
第七個問題是K8S的版本迭代比較快,如何平滑升級的問題。以及在運維的過程中,etcd如何備份恢復。
第八個問題是叢集大了或者叢集數目增多,如何構建多叢集統一監控,巡檢,審計,保證叢集的穩定性。
如何用Prometheus監控十萬container的Kubernetes叢集
如何使用 K8s 兩大利器"審計"和"事件"幫你擺脫運維困境?
第九個問題是Istio Service Mesh的效能優化問題。
OCTO 2.0:美團基於Service Mesh的服務治理系統詳解
抖音春晚活動背後的 Service Mesh 流量治理技術
六、第五階段:全面發揮雲原生價值的成熟深耕期
別看現在Kubernetes已經在很多企業大規模落地了,其實還存在著非常多的問題,就像前面說的,容器落地的時候,為了適配原有應用的部署模式,不得不做一些讓步,這就使得原來的落地表現出以下特點,從而不能發揮雲原生降本增效的功能:
- 容器以虛擬機器的模式被使用,申請規格大,利用率低
- 業務雖有波峰波谷,但是申請容器的人員往往按波峰申請資源,沒有利用好彈效能力
- 較多使用本地盤,大記憶體的有狀態應用,自愈,遷移,可排程能力比較差
前面主要講使用容器之後,如何增效,也即加快業務的迭代速度,當一個平臺進入成熟期後,企業開始慢慢關注成本了,如果容器平臺深耕下去,也是有很多可以提供利用率的地方。
kubernetes 降本增效標準指南| 容器化計算資源利用率現象剖析
經過調研,我發現資源的利用率呈現以下模型
第一階段:傳統部署模型, 業務為應對不同時間段計算資源使用不同的情況,必須以最高使用資源的峰值加一定的 buff 進行基礎設施的採購,平均利用率降低。
第二階段:簡單容器化改造後的業務,上雲並容器化改造,利用了容器進行業務混合部署,一定程度提高了資源利用率。
第三階段:業務進行微服務改造,業務可利用容器和雲的彈性伸縮能力,結合 Kubernetes 的HPA、VPA、ClusterAutoScaling 等能力,高峰擴容、空閒縮容,極大提高資源利用率。
第四階段:極致利用雲和容器化後的彈性, 提高彈性伸縮靈敏度和精度, 有離線業務的進行在離線混布,極致提高平均資源利用率。
這裡一方面需要業務層的配合,另一方面底層的能力要具備。
對於一些處於穩定狀態的業務,成本的壓力會更大一些,這些業務可以試圖從資源利用率方面提出要求,從而降低成本。比如整個部門可以進行雲原生成熟度的評分,如果使用比較大的規格,不是不允許,但是要減分,如果使用了彈性,彈型的約敏銳,則可以加分等待。
對於底層需要提供一些工具,例如增加彈性的敏感度和準確度的問題,以及通過更好的隔離手段,使得在離線業務可以混合部署,進一步增強利用率。
kubernetes 降本增效標準指南| 資源利用率提升工具大全
Kubernetes 降本增效標準指南 | 基於K8s 擴充套件機制構建雲上成本控制系統
kubernetes 降本增效標準指南|ProphetPilot:容器智慧成本管理引擎
今日Qcon熱門分享|騰訊K8s大規模離線上混部與核心隔離實踐
Kubernetes還提供了多雲多地域的部署能力,可以大大提供可用性。這也需要業務層可以進行適配,進行Set化,也即將業務按使用者或者地域進行拆分到不同的資料中心,並在資料中心之間進行資料同步,既能實現就近訪問,也可以實現容災,任何一個機房掛掉,都可以將使用者切換到其他機房或者城市,這樣才能很好的利用多地多中心的資源。
目前各家網際網路公司都在深耕中......