隨著業務規模的增長,系統的可擴充套件性成為關鍵。傳統的擴充套件方式成本高昂且效率低下,而現代的容器化技術和微服務架構提供了更有效的解決方案。本文將探討軸向擴充套件的三個維度,並比較 Kubernetes、Docker Swarm 和 Mesos 等容器叢集管理工具,幫助讀者選擇最適合自身需求的解決方案,以應對日益增長的業務需求。從單體應用到微服務架構的轉變,以及如何利用容器叢集管理工具實作自動化佈署和擴充套件,都是本文探討的重點。同時,文章也將分析不同工具的優缺點,例如 Kubernetes 的功能強大但複雜度高,Docker Swarm 的易用性但功能相對有限,以及 Mesos 的彈性和對多種佈署方式的支援。
叢集與擴充套件服務
組織設計系統時,產出的設計往往是其內部溝通結構的翻版。 —— M. Conway
許多人聲稱他們擁有可擴充套件的系統。畢竟,擴充套件很容易。購買伺服器,安裝WebLogic(或其他龐大的應用程式伺服器),然後佈署應用程式。幾週後,你會發現一切都變得如此“緩慢”,以至於你點選一個按鈕後,需要喝杯咖啡,直到回到辦公桌時,結果才會出來。你該怎麼辦?你會擴充套件。你會購買更多的伺服器,安裝龐大的應用程式伺服器,並在上面佈署龐大的應用程式。系統的哪個部分是瓶頸?沒人知道。為什麼要重複一切?因為你必須這樣做。然後隨著時間的流逝,你繼續擴充套件,直到資金耗盡,同時,團隊成員也變得瘋狂。如今,我們對擴充套件的態度已經不同了。今天,我們明白擴充套件涉及許多其他方面。它關乎彈性,關乎能夠根據流量變化和業務增長快速輕鬆地擴充套件和縮減規模,並且在此過程中不會破產。它關乎幾乎每家公司在擴充套件業務時,不把IT部門視為負擔。它關乎擺脫那些龐然大物。
可擴充套件性
讓我們暫時退一步,討論為什麼要擴充套件應用程式。主要原因是高用性。為什麼我們需要高用性?因為我們希望我們的業務在任何負載下都能運作。負載越大越好(除非遭受DDoS攻擊)。這意味著我們的業務正在蓬勃發展。隨著高用性,使用者會感到滿意。我們都想要速度,如果載入時間太長,許多人會直接離開網站。我們希望避免宕機,因為業務無法運作的每一分鐘都可能轉化為金錢損失。如果一家線上商店無法使用,你會怎麼做?可能會去另一家。也許不是第一次,也許不是第二次,但遲早會厭倦並轉到另一家。我們習慣了所有東西都快速且反應靈敏,而且有太多替代方案,以至於在嘗試其他選擇之前,我們不會猶豫太久。如果那個替代方案更好的話… 一個人的損失就是另一個人的收穫。我們是否透過可擴充套件性解決了所有問題?遠非如此。還有許多其他因素決定了應用程式的可用性。然而,可擴充套件性是其中的重要一部分,也是本章的主題。
可擴充套件性究竟是什麼?它是系統的一種屬性,表明其能夠以優雅的方式處理增加的負載,或隨著需求的增加而擴大的潛力。它是接受增加的數量或流量的能力。
事實是,我們設計應用程式的方式決定了可用的擴充套件選項。如果應用程式不是為擴充套件而設計的,那麼它就不會很好地擴充套件。這並不是說沒有為擴充套件設計的應用程式就無法擴充套件。一切都可以擴充套件,但不是一切都能很好地擴充套件。
常見的場景如下:
我們從簡單的架構開始,有時有負載平衡器,有時沒有,設定幾個應用程式伺服器和一個資料函式庫。一切都很好,複雜性很低,我們可以快速開發新功能。營運成本很低,收入很高(考慮到我們剛剛開始),每個人都很高興也很積極。
業務正在增長,流量正在增加。事情開始出問題,效能下降。新增防火牆,設定額外的負載平衡器,擴充套件資料函式庫,增加應用程式伺服器等等。事情仍然相對簡單。我們面臨新的挑戰,但障礙可以及時克服。儘管複雜性正在增加,但我們仍然可以相對輕鬆地處理它。換句話說,我們正在做的事情仍然或多或少相同,但規模更大。業務運作良好,但仍然相對較小。
然後它發生了。你一直在等待的那件大事。也許其中一個行銷活動擊中了要害。也許競爭對手發生了不利的變化。也許最後那個功能確實是一個殺手級的功能。不管是什麼原因,業務都得到了很大的推動。在短暫的幸福之後,你的痛苦增加了十倍。新增更多的資料函式庫似乎不夠。增加應用程式伺服器似乎也不能滿足需求。你開始新增快取和其他東西。你開始覺得,每次你增加某些東西,效益都不再那麼大。成本增加了,你仍然無法滿足需求。資料函式庫複製太慢。新的應用程式伺服器不再有那麼大的區別。營運成本的增長速度超過了你的預期。這種情況對業務和團隊都造成了傷害。你開始意識到,你引以為傲的架構無法滿足負載的增加。你無法拆分它。你無法擴充套件最痛苦的部分。你無法從頭開始。你所能做的只是繼續增加,但效益卻越來越小。
上述情況相當常見。一開始好的做法,在需求增加時不一定仍然正確。我們需要在YAGNI(你不需要它)原則和長期願景之間取得平衡。我們不能一開始就最佳化系統以適應大公司,因為這樣太昂貴,而且當業務規模較小時,並不能提供足夠的好處。另一方面,我們不能忽視任何業務的主要目標之一。我們不能從第一天開始就不考慮擴充套件性。設計可擴充套件的架構並不意味著我們需要從一開始就建立一個由數百台伺服器組成的叢集。這也不意味著我們必須從一開始就開發一些龐大而複雜的東西。這意味著我們應該從小處著手,但要以當它變大時易於擴充套件的方式進行。雖然微服務不是實作這一目標的唯一方法,但它們確實是解決這個問題的好方法。成本不在開發,而在營運。如果營運是自動化的,那麼這種成本可以很快被吸收,而不需要代表巨大的投資。
微服務與可擴充套件性
微服務架構是一種將應用程式分解為一系列小型、獨立服務的方法,每個服務執行特定的業務功能。這種架構風格促進了可擴充套件性,因為每個服務都可以獨立於其他服務進行擴充套件。
圖示說明:此圖示展示了一個根據微服務架構的系統,使用者請求透過API Gateway路由到不同的服務,每個服務連線到其各自的資料函式庫。
內容解密:
- 使用者請求:使用者發起請求到系統。
- API Gateway:作為入口點,將請求路由到適當的微服務。
- 服務A/B/C:各自處理特定業務功能的微服務。
- 資料函式庫A/B/C:每個微服務連線到其專用的資料函式庫。
這種架構允許根據需求獨立擴充套件每個服務,從而提高整體系統的可擴充套件性和彈性。
叢集與擴充套件服務
在自動化的世界中,我們擁有優秀的開源工具可供使用。自動化最大的優勢在於其投資的維護成本往往低於手動操作。我們已經討論了微服務及其在小型規模上的自動化佈署,現在是時候將這個小規模擴充套件到更大的規模。在進行實際操作之前,讓我們先探討一下擴充套件的不同方法。
我們的設計往往限制了我們的選擇,而應用程式的建構方式則嚴重限制了我們的選擇。儘管有多種不同的擴充套件方法,但最常見的是軸向擴充套件(Axis Scaling)。
軸向擴充套件
軸向擴充套件可以透過立方體的三個維度來表示:x軸、y軸和z軸。每個維度都代表了一種擴充套件方式。
- X軸:水平複製
- Y軸:功能分解
- Z軸:資料分割槽
X軸擴充套件
X軸擴充套件是透過執行多個應用程式或服務例項來實作的。在大多數情況下,頂層會有一個負載平衡器,以確保流量在所有例項之間分享。X軸擴充套件的最大優勢是簡單性。我們只需將相同的應用程式佈署在多台伺服器上即可。
然而,當應用於單體式應用程式時,X軸擴充套件也帶來了一些缺點。龐大的應用程式通常需要大量的快取記憶體,這對記憶體的需求很大。當這樣的應用程式被複製時,所有東西都被複製了,包括快取記憶體。另一個問題是資源使用不當。效能問題幾乎從來都與整個應用程式無關,並非所有模組都受到同等影響,然而,我們卻複製了所有東西。
X軸擴充套件在微服務中的應用
在微服務架構中,X軸擴充套件的效果更加明顯。我們可以根據需要對特定的服務進行擴充套件,而不是對整個應用程式進行擴充套件。這使得資源利用更加高效。
Y軸擴充套件
Y軸擴充套件是關於將應用程式分解為更小的服務。微服務是實作這種分解的最佳方法之一。當微服務與不可變性和自給自足性結合時,確實沒有更好的替代方案(至少從Y軸擴充套件的角度來看)。與X軸擴充套件不同,Y軸擴充套件不是透過執行多個相同的應用程式例項來實作的,而是透過在叢集中分佈多個不同的服務來實作的。
Z軸擴充套件
Z軸擴充套件很少被應用於應用程式或服務,其主要用途是在資料函式庫中。Z軸擴充套件的思想是將資料分佈在多台伺服器上,從而減少每台伺服器的工作量。資料被分割和分佈,使得每台伺服器只需要處理一部分資料。這種分離方式通常被稱為分片(sharding),並且有很多資料函式庫是專門為此目的而設計的。
叢集
伺服器叢集由一組相互連線的伺服器組成,它們共同工作,可以被視為一個單一的系統。它們通常透過快速區域網路(LAN)連線。叢集和簡單的一組伺服器之間的主要區別在於,叢集作為一個單一的系統,試圖提供高用性、負載平衡和平行處理。
此圖示展示了一個由多台伺服器透過區域網路組成的叢集。
內容解密:
此Plantuml圖表描述了一個叢集的結構,其中多台伺服器透過快速區域網路連線,形成一個單一的系統。每台伺服器都是叢集中的一個節點,共同提供高用性、負載平衡和平行處理能力。這種架構允許系統更有效地分配資源,提高整體效能和可靠性。
真正的叢集是在我們停止以個別伺服器為單位思考,而開始將所有伺服器視為一個大實體時實作的。當我們佈署應用程式時,我們傾向於指定它需要的記憶體或CPU資源,但不決定具體使用哪些記憶體槽或CPU。同樣,在更高層次上,我們應該關注的是應用程式或服務的需求,而不是它們將被佈署到哪裡。
我們應該能夠定義服務的特定需求,並告訴某個工具將其佈署到叢集中的任何一台滿足需求的伺服器上。實作這一目標的最佳(如果不是唯一)方法是將整個叢集視為一個實體。透過增加或移除伺服器,我們可以增加或減少叢集的容量。
容器叢集管理工具比較:Kubernetes、Docker Swarm 與 Mesos
在現代化的軟體開發與佈署流程中,容器化技術已經成為不可或缺的一環。隨著容器數量的增加,如何有效地管理和協調這些容器成為了一項挑戰。Kubernetes、Docker Swarm 和 Apache Mesos 是目前最為流行的三種容器叢集管理工具,它們各自具有不同的特點和優勢。
Kubernetes:源自 Google 的容器協調經驗
Kubernetes 是由 Google 開發的開源容器協調平台,它根據 Google 多年來在 Linux 容器技術上的經驗。Kubernetes 提供了一套完整的容器管理解決方案,包括持久化儲存、網路管理、負載平衡和服務發現等功能。然而,Kubernetes 也帶來了一些額外的複雜性,例如需要使用不同的 CLI、API 和 YAML 定義檔。這意味著開發者需要重新學習一套新的工具和組態方式。
# Kubernetes Deployment YAML 範例
apiVersion: apps/v1
kind: Deployment
metadata:
name: example-deployment
spec:
replicas: 3
selector:
matchLabels:
app: example
template:
metadata:
labels:
app: example
spec:
containers:
- name: example-container
image: example/image
ports:
- containerPort: 80
內容解密:
apiVersion和kind定義了 Kubernetes 資源的型別和版本。metadata提供了 Deployment 的基本資訊,如名稱。spec描述了 Deployment 的預期狀態,包括副本數量和容器範本。replicas指定了應該執行的 Pod 副本數量。selector和template中的labels用於匹配和管理 Pod。containers定義了容器相關的組態,包括映像檔和埠號。
Docker Swarm:原生 Docker 叢集管理
Docker Swarm 是 Docker 官方提供的叢集管理工具,它的最大優勢在於對 Docker API 的原生支援。這意味著任何與 Docker 相容的工具都可以無縫地與 Swarm 協同工作,無需額外的學習成本。然而,Swarm 的功能也受限於 Docker API 的能力,如果 Docker API 不支援某些功能,那麼 Swarm 也無法實作這些功能。
# Docker Swarm 初始化命令範例
docker swarm init --advertise-addr <MANAGER-IP>
內容解密:
docker swarm init初始化了一個新的 Swarm 叢集。--advertise-addr指定了管理器節點的 IP 地址,用於叢集內部的通訊。
Apache Mesos:彈性和可擴充套件的叢集管理
Apache Mesos 是一個歷史悠久的叢集管理框架,它抽象了 CPU、記憶體和儲存等資源,使得構建和執行分散式系統變得更加容易。Mesos 不僅支援 Docker 容器,也支援其他型別的佈署。它使用 ZooKeeper 進行服務發現,並利用 Linux 容器進行行程隔離。Mesos 的一大優勢是其強大的排程器和對多種佈署方式的支援。
# Mesos 叢集啟動命令範例(簡化)
mesos-master --work_dir=/var/lib/mesos --quorum=1 --zk=zk://localhost:2181/mesos
內容解密:
mesos-master命令啟動了一個 Mesos 主節點。--work_dir指定了工作目錄,用於儲存狀態資訊。--quorum設定了參與選舉的節點數量門檻。--zk指定了 ZooKeeper 的連線字串,用於服務發現和協調。
容器叢集與擴充套件服務的比較:Docker Swarm 與 Kubernetes
在容器叢集管理領域,Docker Swarm 和 Kubernetes 是兩個主要的競爭者。過去,Mesos 也曾經是一個重要的選擇,但隨著 Docker 的興起,Mesos 的優勢逐漸喪失。對於新專案來說,選擇 Docker Swarm 或 Kubernetes 成為了一個重要的決策。
設定與安裝
Docker Swarm 的設定非常簡單直接。使用者只需安裝一個服務發現工具,並在所有節點上執行 Swarm 容器即可。由於 Swarm 本身被封裝成一個 Docker 容器,因此無論作業系統為何,其運作方式都相同。使用者可以輕鬆地使用 Swarm,而無需擔心複雜的安裝過程。
相較之下,Kubernetes 的安裝過程則複雜得多。不同的作業系統和服務供應商需要不同的安裝指示,每個指示都有其特定的維護團隊和問題。此外,Kubernetes 的安裝依賴於 bash 指令碼,這在組態管理成為必備的時代可能造成一些困擾。
執行容器
在 Docker Swarm 中,使用者可以使用熟悉的 Docker CLI 或 Docker Compose 命令來定義和執行容器。這意味著現有的 Docker 經驗和工具可以直接套用於 Swarm,無需額外的學習成本。
然而,Kubernetes 則需要使用者學習其特定的 CLI 和組態格式。現有的 Docker Compose 定義需要被轉換成 Kubernetes 的格式,且需要使用 Kubernetes CLI 來管理容器。這對於已經習慣 Docker 生態系統的使用者來說,可能會增加額外的學習和維護成本。
維護與擴充套件
採用 Kubernetes 後,使用者需要維護多套組態定義:一套用於 Kubernetes,一套用於 Docker 環境(如開發者的本地環境或測試環境)。這將導致更高的維護成本,不僅是組態的複製,還包括命令列工具的差異。
程式碼範例:Docker Compose 與 Kubernetes 組態比較
# Docker Compose 組態範例
version: '3'
services:
web:
image: nginx:latest
ports:
- "80:80"
# Kubernetes 組態範例
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
內容解密:
- Docker Compose 組態:這是一個簡單的 Docker Compose 檔案,用於定義一個執行
nginx:latest映像的服務,並將容器的 80 埠對映到主機的 80 埠。 - Kubernetes 組態:這是一個 Kubernetes Deployment 組態檔案,用於佈署一個
nginx:latest映像的應用。它指定了副本數量為 3,並定義了容器的埠對映。
未來趨勢與建議
隨著容器技術的不斷發展,叢集管理和服務協調工具也在不斷演進。未來,我們可能會看到更多的整合和創新,以簡化容器的佈署和管理。對於企業來說,瞭解這些技術的發展趨勢,並選擇適合自己的工具,將有助於提高開發效率和降低營運成本。
Docker Swarm 與 Kubernetes 的比較
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title 容器叢集與服務擴充套件策略
package "Kubernetes Cluster" {
package "Control Plane" {
component [API Server] as api
component [Controller Manager] as cm
component [Scheduler] as sched
database [etcd] as etcd
}
package "Worker Nodes" {
component [Kubelet] as kubelet
component [Kube-proxy] as proxy
package "Pods" {
component [Container 1] as c1
component [Container 2] as c2
}
}
}
api --> etcd : 儲存狀態
api --> cm : 控制迴圈
api --> sched : 調度決策
api --> kubelet : 指令下達
kubelet --> c1
kubelet --> c2
proxy --> c1 : 網路代理
proxy --> c2
note right of api
核心 API 入口
所有操作經由此處
end note
@enduml
此圖示展示了 Docker Swarm 和 Kubernetes 在容器叢集管理領域的不同特點。Docker Swarm 以其簡單易用和與 Docker 的緊密整合而受到歡迎,而 Kubernetes 則以其強大的功能和靈活性著稱,但同時也伴隨著更高的複雜度。