天天看點

聊聊雲原生

前言

雲原生是未來IT技術的一個重要的發展方向。作為雲計算的從業者,我們還是要搞清楚雲原生到底代表着什麼,以免在跟使用者交流的時候,給出不準确的解釋顯得不夠專業。這段時間以來,我也積累了一些對雲原生的知識,希望能夠通過這篇文章做一個沉澱。

要了解雲原生,首先需要知道其定義。下面是CNCF(雲原生計算基金會)對于雲原生的定義:

雲原生技術有利于各組織在公有雲、私有雲和混合雲等新型動态環境中,建構和運作可彈性擴充的應用。雲原生的代表技術包括容器、服務網格、微服務、不可變基礎設施和聲明式API。

這些技術能夠建構容錯性好、易于管理和便于觀察的松耦合系統。結合可靠的自動化手段,雲原生技術使工程師能夠輕松地對系統作出頻繁和可預測的重大變更。

解讀上面這段話之後,我發現這裡其實說明了兩個事情。第一個是雲原生包含哪些技術,第二個是雲原生的目标是什麼。

雲原生的技術

下面先來讨論第一個話題,雲原生包含哪些技術。就第一段話而言,其實它在描述給我們一個目前的IT環境的變化。在沒有雲計算之前,我們知道,所有公司的IT建構都是需要自己購買伺服器,然後在上面自行安裝應用。或者有些公司實力更強,會在上面做一些簡單的虛拟化。不同的伺服器,雖然運作環境有差異,但是因為都是公司自建,相對可控。進入雲計算時代之後,我們會發現,由于出現了公有雲,而且提供公有雲的各供應商也有自己不同的規格和作業系統,底層運作環境開始變得複雜起來。

如果說是這些差别還隻是停留在IaaS層面,那麼更複雜的差異應該是應用層。随着開源軟體的發展,我們在社群可以找到各種各樣解決不同場景不同問題的中間件和資料庫。由于引入了這些元件,必要地,我們也會将相應的驅動加入到應用軟體當中。在元件更新或者應用更新的過程中,這些額外引入的元件都可能存在版本相容性的問題,為系統添加了一些不确定風險性。

最後一個複雜度來自于研發團隊自身。以前公司會用的程式設計語言比較少,基本上Java/PHP占了絕大多部分的比例。也可以看到有很多公司就一套技術棧,也能解決各種問題。但是現在不一樣了,随着網際網路規模的不斷擴大,日常對于系統的要求也千奇百怪。有要求高并發的,有要求延時低的,有要求編寫簡易的,有要求資料處理性能強的。對于不同的場景,選擇不同的程式設計語言有時候成為一種必須。而且這些程式設計語言所打造的系統,互相之間還需要能夠互動,被對方調用。這其實就需要一套屏蔽底層程式設計語言差别的有效的通信協定或者方案來完成。

說了那麼多,都是我們目前IT業務會遇到的問題,那應該怎麼解決呢?CNCF給我們規範了一些工具來解決這些問題,它們就是容器,服務網格,微服務,不可變基礎設施和聲明式API。在這裡,我想先逐個簡單說一下這些東西都是什麼。

容器技術是以Docker為代表,是一種标準化的軟體單元。它将應用及其所有依賴項打包在一起,能夠快速部署到任何能夠運作該容器技術的環境中。換句話中,以前我們部署應用的時候是提前将應用的運作環境先安裝好,然後将應用部署上去。利用容器,我們隻需要一個容器的運作環境,不管是跑在CentOS還是Ubuntu上面,直接把應用以及其依賴部署上去,這樣應用就可以運作起來。而且不同應用之間,不會出現因為依賴版本問題導緻沖突。這對于運維效率來說是一個重大的提升。是以簡單來說說容器是解決了部署和隔離的問題。加上現在流行的K8S,容器運作的容錯和排程能力又上了一個台階。

服務網格和微服務,這兩個詞經常被大家混在一起談,甚至有人認為它們是同一個概念。我認為,兩者的視角是不一樣的。先談微服務,它是應用從單體應用到分布式應用過渡之後,對于分布式應用的一種統稱。微服務的視角,更多是從應用的角度,如何就應用域進行拆分來展開的。應用域關心的是業務之間的邊界和關系。基于這些邊界如何拆分應用,變成一個個的微服務。基于這些關系,微服務之間如何進行調用。它解決的是一個單體應用過于臃腫,難以快速疊代和快速排查定位問題的難題。而服務網格,視角則更多是研發和運維之間展開。這是因為微服務發展到一定的階段,更多的程式設計語言群組件的引入,原來一些分布式應用中的通用能力需要被下沉到基礎設施中去。這些通用能力中,最具代表性的就是網絡通信能力。把網絡能力下沉下去之後,整個系統的流量情況,系統架構就會變得可被觀察(Observable),這樣發生問題的時候就更容易排查。另外,由于通信被底層接管,也就一并屏蔽了應用層的程式設計語言差異。

不可變基礎設施和聲明式API,這兩個技術比較少為人所談及,但是其實所描述的場景也是非常重要。不可變基礎設施是指在當你更新一個應用的時候,不會在目前的應用運作環境中執行。取而代之的是,在一個新的運作環境,将應用部署進去,替代原有的應用。這種操作方式在雲計算之前使用的是比較少的。因為每個公司内部,即使是已經有了虛拟化技術,但是空閑出來的資源肯定也是相對緊張的。在公共雲上,由于理論上算力是無窮大的,是以使用者可以在每次部署的時候完全建立一個虛拟機,然後将應用和環境準備好,再去導入流量,再釋放上一個版本。這是雲計算帶來的好處。聲明式API,有别于指令式API,是通過對目标最終狀态的定義來發出指令的方式。聲明式的指令,其實更符合人對于事情的了解。打個比分,我想要部署某個版本的應用,并且該應用應該運作5個執行個體。這樣的描述方式很清晰,很好了解。放到執行環境中,也很容易将其解析成一個個的執行動作。而且這樣的指令還有一個好處,就是幂等性能夠得到保證,不管我執行多少次,結果狀态都會是一緻的。

雲原生的目标

上面簡單介紹了各種雲原生的技術,下面來談談雲原生的目标。其實第二段話對于雲原生的目的描述的也比較清晰,就是容錯性好,易于管理,便于觀察和松耦合。

為什麼我們要強調上述幾個目标?以我的經驗,一些高速發展中的網際網路公司,由于業務快速疊代的需求,系統數量會成爆炸式發展。中型規模的公司,内部管理着成百上千小系統是很正常的事情。這些系統之間的關系紛繁複雜,給架構師和運維人員帶來不少的壓力。從老闆的層面,一般對技術就要求一句話“不要影響業務”。這簡單的一句話,翻譯成技術同學的工作可能就沒那麼簡單了。一般他們也會遵循一個原則,單點問題不影響整體業務,業務故障能夠盡快恢複。雖然具體到名額可能每個公司會不一樣,但是離不開都是圍繞這樣的原則打造IT體系。

在雲原生的體系下面,其實這個問題會變得很好解決。

我們來假想一下一個完美的雲原生系統是怎麼打造起來的。首先,所有應用都通過容器技術來進行打包。無論是本地研發,雲上測試還是生産環境,運作時環境都可以保持一樣。這樣就大大降低了測試和生産可能存在的環境差異導緻的影響降低“不知緣由”問題的發生機率。

其次,容器在雲上一般都用K8S來排程,而K8S正是使用了聲明式的API。上文已經說過,聲明式的API有一個很好的地方是其描述最終的狀态和幂等性。這在實際情況中,友善了我們對于系統部署的定義和發生錯誤時候自動恢複機制的介入。如上文所述,假如我需要部署某應用5個版本A1的執行個體,我隻需要向K8S發送這麼一段描述性指令就好。這個指令不需要關心目前系統的狀态如何(是已經運作着5個執行個體還是超過5個執行個體),隻需要發送者确認所需要的結果狀态即可。是以系統的最終狀态是預測的,也是可控的。對比一下,如果是指令式指令的話,每次發送指令之前,我們都需要先觀察目前系統狀态,并且計算與目标狀态的差異,再将差異轉化成指令發送到系統。這中間人為介入得越多,可能産生的風險的機率就會越大。聲明式還有一個優勢,就是讓K8S一直監測着系統目前的運作狀态。假如一段時間之後,某一個執行個體因為内部原因崩潰了導緻無法繼續服務,K8S會重新拉起這個執行個體,将故障執行個體替換掉。這中間甚至不需要任何人工介入。

不可變的基礎設施,其實在有虛拟機的時候已經可以做到了。但是真正發揚起來應該是容器技術。原因有兩點,第一,容器本身就是一個打包的技術,它把應用運作相關的一切内容都打包在一起。這樣在部署的時候會将所有依賴,包括運作環境也好,元件也好,所有東西都一起部署。要麼一起成功,要麼一起失敗,不會存在中間狀态。這樣就使得部署的最終狀态是可預測的。第二,從整體來看,因為容器的資源使用率更高,這樣我們可以在同樣的資源情況下面,就有更富餘的資源容量去做新部署。這樣一來我們可以對新部署做檢驗而不影響原有業務的負載能力,同時我們也不會擔心新部署對原有部署産生不可預測的影響。

如果說上述那些都是在執行操作層面,對可能存在的風險與故障防範于未然。那麼服務網格就是一種讓故障發生之後,可知可控可排查的手段。如上文提到,服務網格中,很重要的一種下沉能力是網絡監控能力。其實換句話講,應該是網絡接管能力。通過接管整個分布式系統的網絡服務,我們可以輕松地勾畫出系統的架構圖(阿裡雲上的ACK安裝了Istio之後,就有這個能力)。這可不是簡單的服務之間網絡流向,而是可以實時地看到服務與服務之間的請求流量,業務壓力情況,服務健康情況,異常機率等。這對于實時發現系統問題和排查系統瓶頸相當重要。特别在大型分布式環境下,如果沒有這樣一個全局視圖的話,發生問題就會好些盲人摸象一般,無法看清問題。

總結

雲原生還是一個相對新鮮的事物,而這篇文章也隻是我這段時間以來,有限地接觸到雲原生一些概念和場景之後做的一點點總結。希望後續的工作中會有更多相關的場景,也能繼續積累更多的感悟。