第一章 集中式體系結構
集中式結構就是,由一台或多台服務器組成中央服務器,系統內的所有數據都存儲在中央服務器中,系統內所有的業務也均先由中央服務器處理。多個節點服務器與中央服務器連接,並將自己的信息匯報給中央服務器,由中央服務器統一進行資源和任務調度:中央服務器根據這些信息,將任務下達給節點服務器;節點服務器執行任務,並將結果反饋給中央服務器。
集中式結構最大的特點,就是部署結構簡單。這是因為,集中式系統的中央服務器往往是多個具有較強計算能力和存儲能力的計算機,為此中央服務器進行統一管理和調度任務時,無需考慮對任務的多節點部署,而節點服務器之間無需通信和協作,只要與中央服務器通信協作即可,具體示意圖如下所示:
以 Google Borg、Kubernetes 和 Apache Mesos 三個經典的集群管理系統為例,深入學習集中式結構的原理。
1.1 Google Borg
Borg 是 Google 內部使用的集群管理系統,采用了典型的集中式結構,負責提交、調度、開始、重啟和管理 Google 運行在其上的所有應用。在 Borg 中,一個集群稱為一個 Cell,每個 Cell 里面有一個 Leader,稱為 BorgMaster,即為中央服務器;其他服務器為節點服務器或從服務器,被稱為 Borglet。
BorgMaster由兩個進程組成,一個是 Borgmaster 主進程,一個是獨立的 scheduler 進程:
- 主進程處理客戶端的 RPC 請求,比如任務的執行狀態更新或者查詢等;同時,管理系統中所有實體的狀態(比如,服務器、任務等),並負責和 Borglet 通信
- scheduler 進程負責任務調度,通過任務對資源的需求以及當前 Borglet 所在服務器的資源情況進行匹配,為任務尋找一個合適的節點服務器執行。
Borglet是運行在每個節點機器的一個 agent,負責任務的拉起、停止、重啟等,並管理和收集本服務器資源,將任務的狀態、服務器狀態等信息上報給 BorgMaster。
而 BorgMaster 會周期性地輪詢每個 Borglet,以獲取節點服務器的狀態和資源信息等。
Borg 的整體架構示意圖如下所示:
Borg論文: https://storage.googleapis.com/pub-tools-public-publication-data/pdf/43438.pdf
Borg 的主要用戶是 Google 的開發者以及運行 Google 應用和服務的系統管理員(網站可靠性工程師,簡稱 SRE)。用戶以 Job 的形式向 Borg 提交工作,每個 Job 由運行一個或多個運行相同程序的 Task 組成。每個 Job 運行在一個 Borg Cell 中,並將一組機器當作一個單元進行管理。
Borg 可以運行各種各樣的任務,這些任務主要分為兩類:
- 第一類是長服務,即長時間運行不停止的服務,並且要求能夠處理短暫的、延遲敏感的請求(延遲要求在幾微秒到幾百毫秒之間)。這些服務主要用於面向終端用戶的服務(比如 Gmail、Google Docs、Web 搜索),以及內部的一些基礎設施服務(比BigTable)。
- 第二類是批處理任務。通常需要幾秒到幾天的時間來完成的批處理 Job,這些 Job 對短時間的性能波動並不是非常敏感。
這些負載通常在 Cell 之間混合分布,每個 Cell 隨着主要租戶以及時間的不同會運行各種不同的應用:批處理類型的 Job 來了又走,而許多面向終端用戶的 Job 又期望一個能長時間使用的模式。
對於這些不同的服務,要求 Borg 能很好地處理所有的情況。
Borg 主要有三大優點:
- 開發者只需關注應用,不需要關注底層資源管理。它隱藏了資源管理以及錯誤處理,因此用戶能集中精力開發應用。
- 高可靠性和可用性,支持多種應用。
- 支持上千級服務器的管理和運行。
Borg 並不是第一個解決這些問題的系統,但卻是少數能在這么大規模處理這些問題的同時,還能實現這樣的彈性和完整性的系統之一。
1.2 Kubernetes
Kubernetes 是 Google 開源的容器集群管理系統,是 Borg 的一個開源版本。Kubernetes 是用於自動部署、擴展和管理容器化應用程序的開源系統。其核心是,在集群的節點上運行容器化應用,可以進行自動化容器操作,包括部署、調度和在節點間彈性伸縮等。
Kubernetes 也是典型的集中式結構,一個 Kubernetes 集群,主要由 Master 節點和 Worker 節點組成,以及客戶端命令行工具 kubectl 和其他附加項。
Master 節點運行在中心服務器上,Master 節點由 API Server、Scheduler、Cluster State Store 和 Control Manger Server 組成,負責對集群進行調度管理。
- API Server:是所有 REST 命令的入口,負責處理 REST 的操作,確保它們生效,並執行相關業務邏輯。
- Scheduler:根據容器需要的資源以及當前 Worker 節點所在節點服務器的資源信息,自動為容器選擇合適的節點服務器。
- Cluster State Store:集群狀態存儲,默認采用 etcd,etcd 是一個分布式 key-value 存儲,主要用來做共享配置和服務發現。
- Control Manager:負責整個集群的編排管理。它監視群集中節點的離開和加入,將群集的當前狀態與 etcd 中存儲的所需狀態進行核對。比方說,當某個節點發生故障,它會在其它節點上增加新的 Pod 以匹配所需的副本數。
REST即表述性狀態傳遞(英文:Representational State Transfer,簡稱REST)是Roy Fielding博士在2000年他的博士論文中提出來的一種軟件架構風格。它是一種針對網絡應用的設計和開發方式,可以降低開發的復雜性,提高系統的可伸縮性。
Etcd 是一個分布式的,依賴key-value存儲的,最重要的分布式數據存儲系統。
Worker 節點作為真正的工作節點,運行在從節點服務器,包括 kubelet 和 kube-proxy 核心組件,負責運行業務應用的容器。
- kubelet:用於通過命令行與 API Server 進行交互,根據接收到的請求對 Worker 節點進行操作。也就是說,通過與 API Server 進行通信,接收 Master 節點根據調度策略發出的請求或命令,在 Worker 節點上管控容器(Pod),並管控容器的運行狀態(比如,重新啟動出現故障的 Pod)等。Pod 是 Kubernetes 的最小工作單元,每個 Pod 包含一個或多個容器。
- kube-proxy:負責為容器(Pod)創建網絡代理 / 負載平衡服務,從 API Server 獲取所有 Server 信息,並根據 Server 信息創建代理服務,這種代理服務稱之為 Service。Kube-proxy 主要負責管理 Service 的訪問入口,即實現集群內的 Pod 客戶端訪問 Service,或者是集群外訪問 Service,具有相同服務的一組 Pod 可抽象為一個 Service。每個 Service 都有一個虛擬 IP 地址(VIP)和端口號供客戶端訪問。
Kubernetes 架構示意圖如下所示:
Kube DNS 負責為整個集群提供 DNS 服務;CNI 是 Container Network Interface 的一個標准的通用接口,用於連接容器管理系統和網絡插件。與 Borg 不同的是,Kubernetes 主要是一個容器編排引擎,不僅支持 Docker,還支持 Rocket(另一種容器技術)。
在容器管理方面,Kubernetes 有很多優勢。
- 自動化容器的部署和復制。Kubernetes 執行容器編排,因此不必人工編寫這些任務的腳本。將容器組織為組,彈性伸縮。Kubernetes 引入 Pod 機制,Pod 代表着能夠作為單一應用程序加以控制的一組容器集合。通過 Pod 機制,Kubernetes 實現了多個容器的協作,能夠有效避免將太多功能集中到單一容器鏡像這樣的錯誤實踐中。此外,軟件可以向外擴展跨越多個 Pods 實現初步部署,且相關部署可隨時進行規模伸縮。
- 容器間負載均衡。Services 用於將具備類似功能的多個 Pod 整合為一組,可輕松進行配置以實現其可發現性、可觀察性、橫向擴展以及負載均衡。
- 易於版本控制與滾動更新。Kubernetes 采取“滾動方式”實現編排,且可跨越部署范圍內的全部 Pod。這些滾動更新可進行編排,並以預定義方式配合當前可能尚不可用的 Pods 數量,以及暫時存在的閑置 Pods 數量。Kubernetes 利用新的應用程序鏡像版本對已部署 Pods 進行更新,並在發現當前版本存在不穩定問題時回滾至早期部署版本。
1.3 Mesos
Apache 旗下的開源分布式資源管理框架 Mesos 被稱為是分布式系統的內核,最初由加州大學伯克利分校的 AMPLab 開發,后在 Twitter 得到廣泛使用。
Mesos 的開發受到了 Borg 系統的啟發,也是采用的典型的集中式架構。Mesos 與 Borg 不同之處在於,Borg 的 Master 直接對接用戶應用,也就是說用戶可以向 Borg 的 Master 直接請求任務。但 Mesos 不可以,Mesos 只負責底層資源的管理和分配,並不涉及存儲、 任務調度等功能,因此 Mesos Master 對接的是 Spark、Hadoop、Marathon 等框架,用戶的任務需要提交到這些框架上。也正因為此,Mesos 的任務調度框架是雙層結構。
在 Mesos 中,一個集群包括 Mesos Master 和多個 Mesos Agent。其中,Mesos Master 運行在中央服務器,Mesos Agent 運行在節點服務器上。
- Mesos Master 負責收集和管理所有 Agent 所在服務器的資源和狀態,並且對接 Spark、Hadoop 等框架,將集群中服務器的資源信息告知給這些框架,以便這些框架進行任務資源匹配和調度。
- Mesos Agent 負責任務的拉起、停止、重啟等,並負責收集所在服務器的資源 (比如 CPU、內存等) 信息和狀態,上報給 Mesos Master。
Mesos Master 通常采用一主兩備的方式,以方便故障處理和恢復。而 Mesos Master 的選主策略,采用的是 ZAB 算法。
Mesos 架構示意圖如下所示:
如上所述,Mesos 對接的是框架,並且可以同時對接多個框架。
Mesos具有如下優勢:
- 效率。Mesos 對物理資源進行了邏輯抽象,在應用層而不是物理層分配資源,通過容器而不是虛擬機(VM)分配任務。因為應用程序的調度器知道如何最有效地利用資源,所以在應用層分配資源能夠為每個應用程序的特殊需求做考量 ; 而通過容器分配任務則能更好地進行“裝箱”。
- 可擴展性。Mesos 可擴展設計的關鍵是兩級調度架構,其中 Framework 進行任務調度,Mesos Master 進行資源分配。由於 Master 不必知道每種類型的應用程序背后復雜的調度邏輯,不必為每個任務做調度,因此可以用非常輕量級的代碼實現,更易於擴展集群規模。
- 模塊化。每接入一種新的框架,Master 無需增加新的代碼,並且 Agent 模塊可以復用,為此開發者可以專注於應用和框架的選擇。這,就使得 Mesos 可以支持多種框架,適應不同的應用場景。
隨着分布式應用程序和微服務的流行,越來越多的用戶正在尋找一種技術,來幫助他們管理這些復雜的應用程序。而 Mesos 為數據中心帶來的這些好處,就使得越來越多的人關注 Mesos 及其相關項目。
Mesos 是如何支持容器部署的?
目前,容器技術十分熱門,解決了服務打包發布、資源隔離的問題。我們知道,Kubernetes 的設計主要針對的就是容器,那么 Mesos 又是如何支持容器部署呢?Mesos 本身只負責資源管理,不負責任務調度。但 Mesos 可以對接不同的框架,Mesos+Marathon 可以支持容器調度和部署。Marathon 支持容器的調度,將容器部署請求發給 Mesos Master,Mesos Master 再將請求轉發給 Mesos Agent,Mesos Agent 的執行器會將容器拉起。目前,Mesos+Marathon 支持的容器,主要包括 Docker 和 cgroups。
1.4 總結
在集中式架構中,Master 如何判斷 Slave 是否存活呢?
- Slave定時向Master匯報自己還活着,定時心跳包
- Master定時詢問Slave是否還活着,定時心跳包
- Master與Slave之間建立TCP長鏈接
3 種集群管理系統的對比
第二章 非集中式體系結構
在非集中式結構中,服務的執行和數據的存儲被分散到不同的服務器集群,服務器集群間通過消息傳遞進行通信和協調。也就是說,在非集中式結構中,沒有中央服務器和節點服務器之分,所有的服務器地位都是平等(對等)的。這樣一來,相比於集中式結構,非集中式結構就降低了某一個或者某一簇計算機集群的壓力,在解決了單點瓶頸和單點故障問題的同時,還提升了系統的並發度,比較適合大規模集群的管理。
所以近幾年來,Google、 Amazon、Facebook、阿里巴巴、騰訊等互聯網公司在一些業務中也相繼采用了非集中式結構。
接下來,將介紹 3 種典型的非集中式架構系統,包括 Akka 集群、Redis 集群和 Cassandra 集群。
2.1 Akka 集群
在介紹 Akka 集群的結構之前,我帶你了解一下什么是 Akka 框架吧。Akka 是一個開發庫和運行環境,用於構建可擴展的、彈性的、快速響應的應用程序。Akka 框架是基於 Actor 模型實現的,Actor 模型是一個封裝了狀態和行為的對象,它接收消息並基於該消息執行計算。Actor 之間通信的唯一機制就是消息傳遞,每個 Actor 都有自己的 MailBox。
比如,在分布式系統中,一個服務器或一個節點可以視為一個 Actor,Actor 與 Actor 之間采用 mail 進行通信,如下圖所示:
可以看到,Actor 發送的 Mail 消息會存儲在接收方的 MailBox 中。默認情況下,接收方按照 mail 到達的先后順序,從 MailBox 中提取 mail 消息,並進行相應的計算處理。
顯然,Actor 模型采用異步消息調用機制,具有非阻塞、高性能等特點,可以用於處理並發問題。Akka 集群充分利用了 Actor 模型的優勢,提供了一個非集中式架構的集群管理模塊,用來構建可擴展的、彈性的分布式應用程序。
Akka 集群負責 Actor 模型底層的節點管理,包括故障檢測、節點加入 / 退出集群等。也就是說,Akka 集群為 Actor 模型提供了一個可容錯、去中心化的節點集群管理系統,來保證 Actor 的運行和 Actor 之間的通信。
Akka 集群是一個完全去中心化的分布式集群管理系統。一個集群由多個節點組成,每個節點都可以進行數據處理和任務執行,節點之間均可進行通信。節點有 Leader 節點和非 Leader 節點之分。與非 Leader 節點相比,Leader 節點只是增加了負責節點的加入和移除集群的功能,所以並不會影響非集中式結構中節點的平等關系。
Akka 集群的兩個重點是數據傳輸和集群組建及管理。
首先,我們看一下數據傳輸。在 Akka 集群中,節點是對等的,也就是說每個節點是可以並發處理的,因此必然存在數據傳輸和一致性的問題。
比如,我們要針對數據進行操作,將 X=1 修改為 X=2。現在集群中節點 1 進行了修改使得 X=2,但其他節點上還是 X=1,因此節點 1 需要將 X=2 的消息告知其他節點,以保證最終集群中所有節點上均為 X=2。其實,這個問題就是分布式共識問題。
布式共識是在多個節點均可獨自操作或記錄的情況下,使得所有節點針對某個狀態達成一致的過程。
Akka 集群主要采用的是誰的時間戳最新(也就是數據最新),就以誰為准的原則。在這里我要重點與你講述的是,如何將 X=2 這個消息傳輸給集群中的每個節點。
Akka 集群采用了 Gossip 協議,該協議是最終一致性協議。它的原理是每個節點周期性地從自己維護的集群節點列表中,隨機選擇 k 個節點,將自己存儲的數據信息發給這 k 個節點,接收到該信息的節點采用前面講的共識原則,對收到的數據和本地數據進行合並,這樣迭代幾個周期后,集群中所有節點上的數據信息就一致了。
來看一下集群組建及管理。下圖展示了 Akka 集群的創建過程。在創建集群時,節點被分為三種類型,即:
- 種子節點。使用靜態配置文件方式或者系統運行時指定方式,可以生成種子節點;種子節點是普通節點加入集群的聯系點,可以自動接收新加入集群的節點的信息。
- 首種子節點。首種子節點是配置文件中的第一個種子節點,其功能是集群第一次啟動時,首種子節點啟動起來,集群才能組建成功,保證集群第一次創建時只有一個集群。如下圖 A 節點,就是 Akka 集群的首種子節點。
- 普通節點。可以向種子節點或集群中的任意節點發送 Join 消息,請求加入集群。如下圖的 B 和 C 節點,通過向 A 節點發送 Join 消息,從而加入到 Akka 集群。
Akka 集群的每個節點啟動后,讀取配置文件獲取種子節點列表,然后開始組建集群:
- 如果本節點為首種子節點,則把自己加入到集群列表中,即以自己為中心構建集群;
- 如果本節點為種子節點,則向首種子節點請求加入集群,當首種子節點回復同意消息后,可以加入集群,否則不可加入集群;
- 如果本節點為普通節點,則可以向任一種子節點(包括首種子節點)請求加入集群,收到同意后,則加入集群,否則不可加入集群。
加入首種子節點或種子節點的節點信息,會通過 Gossip 協議的傳播方式傳播給當前已加入的所有節點,以完成集群組建。當集群組建完成后,就不存在種子節點與普通節點之分了,每個節點均可執行 Actor 應用程序。
Akka 集群可以構建可擴展的、彈性的分布式應用程序,因此在 JVM 中應用了 Akka 框架,從而實現並發編程。目前,豌豆莢、蘑菇街等公司采用了 Akka 集群。
Akka 集群是一個完全去中心化的集群管理系統,當集群組建完成后,每個節點均可執行 Actor 應用程序,因此支持並發操作。但,這個並發操作引入了數據同步和一致性問題,所以 Akka 集群采用了 Gossip 協議進行數據同步,通過誰的時間戳最新就以誰為准,來解決一致性問題。
2.2 Redis 集群
除了面向應用程序平台的分布式集群管理之外,分布式數據存儲也是一個非常重要的話題。在這其中,分布式數據存儲中的集群管理便是一個關鍵因素。那么接下來,以開源數據庫 Redis 的集群管理系統為例,展開介紹吧。
Redis 是一個開源的、包含多種數據結構的高性能 Key-value 數據庫,主要有以下特征:
- 支持多種數據結構,包括字符串(String)、散列(Hash)、列表(List)、集合(Set)、有序集合(Sorted Set)等;
- 支持數據的持久化和備份。數據可以保存在磁盤中,下次直接加載使用,且可以采用主從模式(Master/Slave)進行數據備份。
- 基於內存運行,具有極高的性能。
Redis 的這些特征均是為數據存儲進行服務的,數據可分片存儲在不同的 Redis 節點上,多個 Redis 節點間可共享數據,而提供這項能力的就是 Redis 集群。
Redis 集群中不存在中央節點,是典型的去中心化結構,每個節點均可與其他節點通信。所有節點均可負責存儲數據、記錄集群的狀態(包括鍵值到正確節點的映射),客戶端可以訪問或連接到任一節點上。當然,節點之間的數據傳輸仍采用了 Gossip 協議,來保證集群中數據的最終一致性。
Redis 集群中的節點用於數據存儲,所以在設計時,需要考慮數據的可靠性和分片存儲問題。
對於可靠性的問題,集群中每個節點均存在主備,也就是說每台服務器上都運行兩個 Redis 服務,分別為主備,主故障后,備升主。
而對於數據的分片存儲問題,Redis 集群引入了“哈希槽”的這一概念。Redis 集群內置了 16384 個哈希槽,每個節點負責一部分哈希槽。當客戶端要存儲一個數據或對象時,Redis 先對 key 進行 CRC16 校驗,然后進行 16384 取模,也即 HASH_SLOT = CRC16(key) mod 16384,來決定哈希槽的編號,從而確定存儲在哪個節點上。
比如,當前集群有 3 個節點,那么:
- 節點 A 包含 0 到 5500 號哈希槽;
- 節點 B 包含 5501 到 11000 號哈希槽;
- 節點 C 包含 11001 到 16383 號哈希槽。
Redis 集群利用哈希槽實現了數據的分片存儲,從而將 Redis 的寫操作分攤到了多個節點上,提高了寫並發能力。
Redis 集群是一個非集中式集群管理系統,沒有中心節點,不會因為某個節點造成性能瓶頸,每個節點均支持數據存儲,且采用分片存儲方式,提高了寫的並發能力。同時,每個節點的設計采用主備設計,提高了數據的可靠性。
鑒於這些優點,Redis 已被 Twitter、Uber、GitHub、Instagaram 等公司采用。
Redis集群的問題
Redis集群成員管理使用gossip協議,所有節點都對等,管理節點的加入與退出,經過算法收斂,每個節點都能知道完整集群狀態,即存在多少節點、每個節點存儲的數據槽區間;在數據存儲層面,每一個數據分片存儲在一主多備的多個節點上,每個數據分片的主節點通過Raft算法選舉產生。這樣從集群成員管理和數據主備存儲兩個層面理解,就不矛盾了。
https://www.cnblogs.com/zhonglongbo/p/13128955.html
2.3 Cassandra 集群
除了 Redis 外,還有一個開源分布式 key-value 數據庫系統 Cassandra。Cassandra 也支持數據的分布式存儲和操作。因此,Cassandra 的集群架構與數據分片存儲方案,與 Redis 集群類似。
如下圖所示,Cassandra 集群的系統架構是基於一致性哈希的完全 P2P 結構,沒有 Master 的概念,所有節點都是同樣的角色,徹底避免了因為單點問題導致的系統不穩定。Cassandra 集群節點間的狀態同步,也是通過 Gossip 協議來進行 P2P 通信的。
在 Cassandra 集群中,每次客戶端可以向集群中的任意一個節點請求數據,接收到請求的節點將 key 值進行哈希操作,找出在一致性哈希環上是哪些節點應該存儲這個數據,然后將請求轉發到相應節點上,並將查詢結果反饋返回給客戶端。
目前,Cassandra 集群因為完全去中心化的結構模式,已經被 Hulu、Apple、Comcast、Instagram、Spotify、eBay、Netflix 等公司使用。
Cassandra 采用去中心化的架構,解決了集中式結構的單點故障問題,同時因為數據基於哈希值分區存儲,提高了讀寫數據的並發能力。在 Cassandra 集群中,沒有 Master 的概念,每個節點代表一個哈希值,通過哈希映射的方式決定數據存儲的位置。集群間的狀態同步通過 Gossip 協議來進行 P2P 的通信。
2.4 總結
如何優化 Gossip 協議中的重復消息問題?
非集中式結構的通信協議采用了 Gossip 協議。而 Gossip 是一種謠言傳播協議,每個節點周期性地從節點列表中選擇 k 個節點,將本節點存儲的信息傳播出去,直到所有節點信息一致,即算法收斂了。
這里有個問題,如果每次都是隨機選擇 k 個節點的話,勢必會存在重復選擇同樣節點的可能,增加消息量。又應該如何優化呢?
解決方案是,每個節點記錄當前傳輸的消息且還未達到收斂的時候,已經發送給了哪些節點,然后每次選擇時從沒有發送過的節點列表中隨機選擇 k 個節點,直到所有節點均被傳輸或集群收斂為止。這樣,一方面減少了重復消息量,另一方面加快了收斂速度。
3 個集群的主要特征對比