後Kubernetes時代的微服務

Bilgin Lbryam

原文

關鍵要點

微服務架構依然是分佈式系統最流行的架構風格。但Kubernetes和雲原生運動大規模的重新定義了應用設計和開發的某些方面。

雲原生平臺,服務的可見性還不夠。一個更基本的前提是通過健康檢查,信號的響應以及聲明所需消耗的資源等使微服務自動化

在後Kubernetes時代,使用諸如Hystrix熔斷等庫解決網絡營運問題已經完全被Service Mesh技術取代。

微服務必須設計成可恢復,多維度冪等性。

現代開發者必須很熟練的使用編程語言實現業務功能,同時也要對雲原生技術相當熟練以便實現非功能性基礎架構級別的需求

微服務的炒作是始於一系列關於組織架構,團隊大小,服務大小,拋棄並重寫服務而不是修復它以及避免單元測試等極端思想。以我的經驗,這些思想許多被證明是錯誤的,不實用的,或者至少不是普遍適用的。如今,對剩下的許多原則和實踐的定義亦是如此空泛和鬆散以至於雖然它們都是對的但多年以來卻對實踐沒什麼意義。

在Kubernetes誕生之前就被採納的微服務架構現在依然是最流行的分佈式架構風格。但Kubernetes和雲原生運動大規模的重新定義了應用設計和開發的某些方面。在這篇文章,我想置疑一些最初的微服務思想並且承認一個事實:在後Kubernetes時代,這些思想已經不再和當初一樣重要了。

服務不僅可觀察還需自動化

可觀察性從最初開始就是微服務的基本原則。這條原則對分佈式系統普遍適用。今天(尤其是在Kubernetes上)可觀察性的大部分功能都是平臺級開箱即用的,比如健康檢查,CPU和內存消耗。對應用程序最小的要求就是把log以JSON格式輸出到控制檯。然後,平臺就可以監控資源消耗,進行請求跟蹤,收集各類指標數據,錯誤率等而無需大量的服務級別的開發工作。

雲原生平臺,服務的可見性還不夠。一個更基本的前提是通過健康檢查,信號的響應以及聲明所需消耗的資源等使微服務的自動化。它幾乎可以把所有的應用裝入容器並運行。但是創建能夠被雲原生平臺自動化及有效編排的容器化應用需要遵循某些規則。遵循這些原則和模式可確保容器在許多容器編排引擎上表現得像一位雲原生好公民,能很好地以自動化的方式被編排,伸縮和監控。

我們是希望平臺可以偵測到服務異常然後按聲明恢復到一致狀態,而不是希望觀察服務裏頭髮生了。不管是截止進入服務實例的流量,重啓及伸縮服務,還是遷移服務到健康的宿主機,重試失敗的請求,或其他,這些都不重要。假如服務是自動化的,所有的動作都會自動發生,而我們僅僅需要描述想要的狀態,而不是去發現問題,然後響應。一個服務應該是可觀察的,但也是可以通過平臺調整,不需要人工干預。

智能平臺,智能服務,職責合理分工

從SOA架構轉向微服務架構,“智能終端和啞管道”的概念是另外一個基礎的關於服務間交互的轉變。微服務的世界裏,服務不依賴於中心化的智能路由層的存在,而是依賴處理某些平臺級特性的職能端點。這是通過把傳統的ESB某些功能植入微服務中,並改用不包含業務邏輯元素的輕量協議來達到的。

當這種使用如Hystrix庫在不可靠的網絡實現服務間交互的方式還很流行的時候,現在,在後Kubernetes時代,它已經完全被Service Mesh技術取代了。有趣的是,Service Mesh甚至比傳統的ESB更智能。它可以實現動態路由、服務發現、基於時延,響應類型和監控指標負載均衡以及分佈式跟蹤,重試和超時等你所想到的。

Service Mesh和ESB不同的是,使用Service Mesh,不需要中心化的路由層,每個微服務典型地都會有自己的路由——一個Sidecar容器和一個額外的中心管理層一起執行代理邏輯。更重要的而是,管道(或者說是平臺本身和Service Mesh)不擁有任何業務邏輯;它們純碎關注基礎架構問題,讓服務關注業務邏輯。如下圖所示,其代表從ESB到微服務的演化,以適應動態及不可靠的雲環境。

SOA vs MSA vs CNA

從服務的另外一方面看,我們注意到雲原生不僅僅影響端點和服務的交互。Kubernetes平臺(包括使用的其他額外技術)負責資源管理,編排,部署,配置管理,伸縮,服務交互等。我想最好將其稱之爲各自具有合理職責的智能平臺和智能服務,而不再稱之爲“智能代理和啞端點”。它不僅是關於端點,而是一個完整的平臺,爲聚焦業務功能的服務提供基礎架構方方面面的的自動化。

爲故障更爲恢復設計

運行在本質上不可靠的基礎架構和網絡構成的雲原生應用環境中的微服務必須處理故障。對於這點沒有問題。但由平臺捕獲並處理的故障越來越多,餘下的需要服務本身捕獲的故障就少了。因而我們需要考慮服務故障恢復設計,比如多維度的冪等性。

容器技術,容器編排系統和Service Mesh能夠偵測許多故障並恢復。如:死循環——CPU共享;內存泄漏及內存不足——健康檢查;磁盤獨佔(磁盤豬)——配額管理;Fork 炸彈——進程限制;隔板和進程隔離——內存限制;基於服務發現的延遲和像響應,重試,超時,自動伸縮等。更不用說,隨着轉向無服務器模式,服務僅僅只要幾毫秒來處理單個請求,對垃圾收集,線程池及資源泄露的關注也越來越少了。

平臺可以處理這些故障甚至更多,可以把你的服務想象成一個黑盒子,能夠多次啓動和停止——服務對於重啓是冪等的。你的服務可以多次伸縮——你的服務是無狀態的,能安全的伸縮。假設收到請求將最終會timeout——保證端點冪等性。假設發送請求可能臨時性失敗,平臺將會爲你重試——保證你所使用的服務冪等性。

爲了適合雲原生環境的自動化,服務必須:

重啓是冪等的

伸縮是冪等的

冪等的生產者(服務可以處理請求的重入)

冪等的消費者(服務或者mesh可以重試請求)

如果你的服務在上述動作被多次重複執行時保持行爲一致,那麼當故障發生時,平臺能夠幫助恢復你的服務,而無需人工干預。

最後,需要記住的是,所有由平臺提供的故障恢復都僅僅是局部優化。Christian Posta說得好,確保分佈式系統中應用的安全性和正確性仍然是應用本身的責任。整體業務流程級別的思維(可能跨越多個服務)對設計一個整體穩定的系統是必須的。

混合式開發職責

越來愈多的微服務原則由Kubernetes和其外圍項目來實現並作爲功能提供。因此,開發者必須很熟練的使用編程語言實現業務功能,同時也要對雲原生技術相當熟練以便實現非功能性基礎架構級別的需求,完整實現一個功能。

業務需求和基礎架構(運維,跨功能需求以及系統質量屬性)之間的界限一直是模糊的,不可能你只考慮一方面,而期望其他人去考慮另外一方面。 比如,假如你在Service Mesh這一層實現重試的邏輯,你就必須確保被使用的服務在業務邏輯和其內的數據庫層的冪等性。假如你在Service Mesh層使用timeout,你就必須服務使用者timeout和服務內部timeout的同步。假如你需要實現一個重複運行的服務,那麼你必須配置一個Kubernetes 任務來完成每一次的臨時執行。

繼而,服務一部分功能將作爲業務邏輯在服務內部實現, 而另一部分由平臺實現。使用對的工具做對的事是好的職責隔離的做法,技術的激增極大的提高了整體的複雜性。即便實現一個簡單業務邏輯需求的服務都要求對分佈式技術棧具有良好的理解,因爲職責分佈在不同的層。

Kubernetes已證明可以擴展到數千節點,上萬pod以及每秒百萬級事務。但是它能收縮回去嗎?關於你的應用的大小和複雜度的閾值或者被證明會合理引入“雲原生”複雜性的臨界點是多少對我來說還不清楚。

結論

有趣的是,我們看到微服務運動如何激發大家如此多的動力採用如Docker和Kubernetes等容器技術。起初,是微服務實踐推進這些技術發展,現在Kubernetes定義微服務架構的原則和實踐。

就目前的情況來看,我們不久將會接受函數模型(注:ServerLess, 如AWS Lambda?)是有效的微服務原語,而不會認爲它是微服務的反模式。我們沒有充分置疑雲原生技術對中小型案例的實用性和適用性,反而是興奮的有些手足無措。

Kubernetes從EBS和微服務中學到了很多,正因爲如此,它成爲了最終的分佈式系統平臺。它是定義分佈式系統架構風格的技術,而不是相反。這是好是壞,只有時間可以證明。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章