基於容器分散式系統的設計模式

  • 2021 年 2 月 23 日
  • AI

面向對象編程引爆了軟體開發領域,其設計模式使得初級程式設計師也能寫出易維護和可重用的程式碼。隨著基於容器的微服務架構越發流行,同時容器的完整性和隔離性,可以使得它作為分散式系統中的「對象」,從而構建分散式系統部署的設計模式。包括,單容器管理模式、單節點多容器模式和分散式演算法的多節點模式。

一、單容器管理模式(Single-container management patterns)

跟面向對象編程中的「對象」一樣,容器天然擁有「介面」的概念。包括,用戶自定義的調用介面和管理系統中的hook介面。一般來說,容器管理介面非常有限,主要圍繞3個動詞來定義,即run(),pause()和stop()。但隨著Restful的興起,在容器中內嵌一個web server,作為管理端點提供各種介面是非常方便的。

站在容器的角度向上看,它可以暴露全面的應用資訊,包括監控(QPS、健康資訊等)、Profile(執行緒、堆棧、鎖、網路流量統計等)、配置和日誌。比如,Kubernetes、Aurora和Marathon都會提供類似/health的HTTP端點來執行用戶自定義的健康檢查。

站在容器的角度向下看,容器也提供生命周期的管理介面。因此,基於容器可以更容易編寫可以被管理系統控制的應用組件內。比如,集群管理系統會為任務分配優先順序,當集群資源不足時,會驅逐正在運行的低優先順序任務並等待資源足夠後,調度高優先順序任務。最粗暴的驅逐是直接殺掉低優先順序任務,但這會為開發人員提供不必要的排錯負擔。因此,應用軟體和管理系統間必須要定義一個規範的生命周期,使應用更容易被管理的同時更可靠。比如,Kubernetes使用「優雅刪除」的特性來實現驅逐,即首先發送SIGTERM訊號,讓應用軟體捕獲後可以自行處理收尾邏輯,包括完成在途操作、臟數據刷磁碟等等,並在指定時間後,再次發送SIGKILL訊號來結束流程。在此流程上進一步擴展,可以實現對狀態序列化和狀態恢復的支援,使得有狀態的分散式系統更容易被管理。

一個更複雜的例子是Android的應用程式,它有一系列的狀態回調,包括onCreate,onStart()和onStop()。在基於容器的應用開發中,容器在創建時、啟動時和終止前,為用戶提供了hook來實現自定義邏輯。

二、單節點多容器模式(Single-node, multi-container application patterns)

在容器提供的介面之上,容器管理系統必須要能夠支援將多個「共生容器」同時調度到一個節點上。比如,Kubernetes的「Pods」和Nomad的「task groups」。這就引出了不同「共生容器」的設計模式。

1、Sidecar模式

首當其衝的就是Sidecar模式,它通過多容器部署實現對主容器的擴展和增強。比如,主容器是一個web server,其sidecar容器是一個log saver,它將server的本地日誌定時同步到一個分散式存儲系統中。或者相反,sidecar是一個sync agent,定時將遠程內容同步到本地,支援web server提供內容服務。畢竟,sidecar模式可以讓單節點上的多個容器共享本地磁碟的volumes。



雖然從理論上,將sidecar容器合入主容器也是非常方便的,但解耦能帶來5個好處:首先,容器是資源審計和分配的原子單位。這使得web server容器可以配置cgroups支援低延時,而log saver在其空閑時才開始同步;第二,容器是程式打包的基本單位,web server和log saver可以由2個不同的小組開發和測試,權責清晰;第三,容器是重用的基本單位,sidecar容器可以作為一個通用組件與其他主容器編排部署;第四,容器提供了失效邊界,功能上互不影響,可以實現優雅降級;最後,容器是部署的基本單位,主容器和sidecar容器都能單獨升級和回滾。但是要注意,測試人員就必須注意生產環境中的聯合版本,並且多組容器間將無法進行原子升級。

2、Ambassador模式

Ambassador容器與主容器共享network namesapce,可以作為其proxy,代理出入的通訊流量。比如,一個需要與memcache集群通訊的應用可以將twemproxy作為一個Ambassador容器,實現客戶端的負載均衡。這給開發人員帶來3點好處:首先,開發時可以只關注對單台localhost memcacbe服務的邏輯;其次,應用測試時可以在本地起一個memcache服務,以standalone的方式完成;最後,twemproxy同樣是一個通用ambassador組件,提供對不同語言開發應用的一致代理。


3、Adapter模式

如果說Ambassador模式為應用程式簡化了複雜的外部世界,那麼Adapter模式完全相反,它為外部世界簡化了複雜的應用程式。即,它為多個容器提供標準化的介面和輸出。比如,當今的應用提供各種複雜的方式暴露監控資訊(JMX,statsd等),apater模式為複雜的世界提供了統一介面,並不需要應用容器作出任何改變。主容器可以通過localhost或local volume與Adapter保持通訊,並由Adapter聚合所有監控資訊,統一對外輸出。



三、多節點應用模式(Multi-node application patterns)

當談到基於容器的多節點分散式系統時,必須要求容器管理平台支援Pod層面的抽象概念。

1、選主模式(Leader election pattern)

在多副本集群中,Leader是一個重要概念,市面上也有各種難以理解的、不同語言實現的選主lib庫。應用容器可以嘗試使用選主容器來作為替選方案。

構建一組選主容器集合,並與需要選主的應用容器一一綁定實現選主。選主容器使用簡單的HTTP API(becomeLeader、renewLeadership等)告知應用容器選主結果。選主容器可以專註複雜領域的優化實現,可以一次構建、到處使用,並且無需關注應用程式的實現語言。這也是軟體工程領域的最佳抽象和封裝。

2、隊列模式(Work queue pattern)

與選主一樣,市面上的隊列框架受限於單一語言的開發環境,或者需要業務開發者適配開發。基於容器的隊列模式可以僅通過2個介面(run和mount),就實現對任意語言和異構數據的簡單、直接處理。比如,應用開發人員僅需要讀取文件系統的輸入文件,處理後再輸出到文件系統,即可作為隊列模式處理中的一個階段。同樣,隊列容器框架也是一次構建,到處使用。



3、Scatter/gather模式

搜索引擎場景下,客戶端向根節點發出請求,根節點將請求分發到後端服務集群執行並行計算,根節點匯總每個shard節點返回部分數據結果,最後返回給客戶端。類似MapReduce的框架同樣可以基於容器來實現。用戶提供2個容器來實現業務邏輯:首先是在葉子節點上執行計算的容器,該容器執行部分計算並返迴響應的結果;其次是匯總計算結果的容器,該容器負責將所有葉子節點容器的計算結果匯總成單條結果,響應客戶端。注意,負責與客戶端交互並分發請求任務的根節點是通用的容器實現。



四、參考文獻

1、Design Patterns for Container-based Distributed Systems

Tags: