Categories
程式開發

2010 年代的分佈式系統:軟件構建方式和演化


我上大學的時候專業是軟件工程,當時的軟件工程是 CMM、瀑布模型之類。十幾年過去了,看看現在我們的軟件開發模式,尤其是在互聯網行業,敏捷已經成為主流,很多時候老闆說業務下週上線,那基本就是怎麼快怎麼來,所以現代架構師對於可複用性和彈性會有更多的關注。我所知道業界對 SOA 的關注是從 Amazon 的大規模 SOA 化開始, 2002 年 Bezos 要求 Amazon 的工程團隊將所有的業務 API 和服務化,幾條原則放在今天仍然非常適用:

  • All teams will henceforth expose their data and functionality through service interfaces.

  • Teams must communicate with each other through these >interfaces.

  • There will be no other form of inter-process communication allowed: no direct linking, no direct reads of another team's data store, no shared-memory model, no back-doors whatsoever. The only communication allowed is via service interface calls over the network .

  • It doesn’t matter what technology they use.

  • All service interfaces, without exception, must be designed from the ground up to be externalizable. That is to say, the team must plan and design to be able to expose the interface to developers in the outside world. No exceptions.

尤其最後一條,我個人認為對於後來的 AWS 的誕生有直接的影響,另外這條也間接地對工程團隊的軟件質量和 API 質量提出了更高的要求。亞馬遜在 SOA 上的實踐是組件化在分佈式環境中的延伸,盡可能地將業務打散成最細粒度的可複用單元(Services),新的業務通過組合的方式構建。這樣的原則一直發展到今天,我們提到的微服務、甚至 Serverless,都是這個思想的延伸。

SOA 只是一個方法論

很多人在思考SOA 和微服務的區別時,經常有一些觀點類似:「拆的粗就是SOA,拆的細就是微服務」,「使用RESTful API 就是微服務,用RPC 是SOA」,「使用XXX (可以是任何流行的開源框架) 的是微服務,使用YYY 的是SOA」… 這些觀點我其實並不認可,我理解的SOA 或者微服務只是一個方法論,核心在於有效地拆分應用,實現敏捷構建和部署,至於使用什麼技術或者框架其實無所謂,甚至SOA 本身就是反對綁定在某項技術上的。

對於架構師來說, 微服務化也並不是靈丹妙藥,有一些核心問題,在微服務化的實踐中經常會遇到:

1、服務的拆分粒度到底多細?

2、大的單體服務如何避免成為單點,如何支持快速的彈性水平擴展?

3、如何進行流控和降級?防止調用者 DDoS?

4、海量服務背景下的 CI/CD (測試,版本控制,依賴管理),運維(包括 tracing,分佈式 metric 收集,問題排查)

上面幾個問題都很大。熟悉多線程編程的朋友可能比較熟悉Actor 模型,我認為Actor 的思想和微服務還是很接近的,同樣的最佳實踐也可以在分佈式場景下適用,事實上Erlang OTP 和Scala 的Akka Framework 都嘗試直接將Actor 模型在大規模分佈式系統中應用。其實在軟件工程上這個也不是新的東西,Actor 和CSP 的概念幾乎在軟件誕生之初就存在了,現在服務化的興起我認為是架構複雜到一定程度後很自然的選擇,就像當年CSP和Actor 簡化並發編程一樣。

服務化和雲

從服務化的大方向和基礎設施方面來說,我們這幾年經歷了:本地單體服務+ 私有API (自建數據中心,自己運維管理) -> 雲IaaS + 本地服務+ 雲提供的Managed Service (例如EC2 + RDS) -> Serverless 的轉變。其本質在於雲的出現讓開發者對於硬件控制力越來越低,算力和服務越來越變成標準化的東西。而容器的誕生,使得資源復用的粒度進一步的降低(物理機 -> VM -> Container),這無疑是雲廠商非常希望看到的。對公有云廠商來說,資源分配的粒度越細越輕量,就越能精準地分配,以提升整體的硬件資源利用率,實現效益最大化。

這裡暗含著一個我的觀點:公有云和私有云在價值主張和商業模式上是不一樣的:對公有云來說,只有不斷地規模化,通過不斷提升系統資源的利用率,獲取收益(比如主流的公有云幾乎對小型實例都會超賣)。而私有云的模式可以概括成降低運維成本(標準化服務+ 自動化運維),對於自己擁有數據中心的企業來說,通過雲技術提升硬件資源的利用率是好事,只是這個收益並沒有公有云的規模化收益來得明顯。

在服務化的大背景下,也產生了另外一個趨勢,就是基礎軟件的垂直化和碎片化,當然這也是和現在的workload 變得越來越大,單一的數據庫軟件或者開發框架很難滿足多變且極端的需求有關。數據庫、對象存儲、RPC、緩存、監控這幾個大類,幾乎每位架構師都熟悉多個備選方案,根據不同需求排列組合,一個 Oracle 包打天下的時代已經過去了。

這樣帶來的結果是數據或狀態在不同系統之間的同步和傳遞成為一個新的普遍需求,這就是為什麼以 Kafka,Pulsar 為代表的分佈式的消息隊列越來越流行。但是在異構數據源之間的同步,暗含了異步和不一致(如果需要一致性,那麼就需要對消費者實現冪等的語義),在一些對一致性有極端需求的場景,仍然需要交給數據庫處理。

在這種背景下,容器的出現將計算資源分配的粒度進一步的降低且更加標準化,硬件對於開發者來說越來越透明,而且隨著workload 的規模越來越大,就帶來的一個新的挑戰:海量的計算單元如何管理,以及如何進行服務編排。既然有編排這裡面還隱含了另外一個問題:服務的生命週期管理。

Kubernetes 時代開始了

其實在 Kubernetes 誕生之前,很多產品也做過此類嘗試,例如 Mesos。 Mesos 早期甚至並不支持容器,主要設計的目標也是短任務(後通過Marathon Framework 支持長服務),更像一個分佈式的工作流和任務管理(或者是分佈式進程管理)系統,但是已經體現了Workload 和硬件資源分離的思想。

在前Kubernetes 時代,Mesos 的設計更像是傳統的系統工程師對分佈式任務調度的思考和實踐,而K8s 的野心更大,從設計之初就是要在硬件層之上去抽象所有類型的workload,構建自己的生態系統。如果說 Mesos 還是個工具的話,那麼 K8s 的目標其實是奔著做一個分佈式操作系統去的。簡單做個類比:整個集群的計算資源統一管控起來就像一個單機的物理計算資源,容器就像一個個進程,Overlay network 就像進程通信,鏡像就像一個個可執行文件,Controller 就像Systemd, Kubectl 就像Shell……同樣相似的類比還有很多。

從另一方面看,Kubernetes 為各種IaaS 層提供了一套標準的抽象,不管你底層是自己的數據中心的物理機,還是某個公有云的VM,只要你的服務是構建在K8s 之上,那麼就獲得了無縫遷移的能力。 K8s 就是一個更加中立的雲,在我的設想中,未來不管是公有云還是私有云都會提供標準 K8s 能力。對於業務來說,基礎架構的上雲,最安全的路徑就是上K8s,目前從幾個主流的公有云廠商的動作上來看(GCP 的GKE,AWS 的EKS,Azure 的AKS),這個假設是成立的。

不選擇 K8s 的人很多時候會從性能角度來攻擊 K8s,理由是:多一層抽像一定會損害性能。對於這個我是不太同意的。從網絡方面說,大家可能有個誤解,認為 Overlay Network 的性能一定不好,其實這不一定是事實。下面這張圖來自 ITNEXT 的工程師對幾個流行的 CNI 實現的評測:

2010 年代的分佈式系統:軟件構建方式和演化 1

(圖1: Kubernetses CNI benchmark )

我們其實可以看到,除了WaveNet Encrypted 因為需要額外的加密導致性能不佳以外,其它的CNI 實現幾乎已經和Bare metal 的host network 性能接近,出現異常的網絡延遲大多問題是出現在iptable NAT 或者Ingress 的錯誤配置上面。

所以軟件的未來在哪裡?我個人的意見是硬件和操作系統對開發者會更加的透明,也就是現在概念剛開始普及起來的 Serverless。我經常用的一個比喻是:如果自己維護數據中心,採購服務器的話,相當於買房;使用雲 IaaS 相當於租房;而 Serverless,相當於住酒店。長遠來看,這三種方案都有各自適用的範圍,並不是誰取代誰的關係。目前看來 Serverless 因為出現時間最短,所以發展的潛力也是最大的。

從服務治理上來說,微服務的碎片化必然導致了管理成本上升,所以近年 Service Mesh (服務網格)的概念才興起。服務網格雖然名字很酷,但是其實可以想像成就是一個高級的負載均衡器或服務路由。比較新鮮的是 Sidecar 的模式,將業務邏輯和通信解耦。我其實一直相信未來在七層之上,會有一層以 Service Mesh 和服務為基礎的「八層網絡」,不過目前並沒有一個事實標准出現。 Istio 的整體架構過於臃腫,相比之下我更加喜歡單純使用 Envoy 或者 Kong 這樣更加輕量的 API Proxy。不過我認為目前在 Service Mesh 領域還沒有出現有統治地位的解決方案,還需要時間。

作者介紹:

黃東旭:分佈式系統專家,架構師,開源軟件作者。 PingCAP 聯合創始人兼 CTO,知名開源項目 Codis / TiDB / TiKV 主要作者,曾就職於微軟亞洲研究院,網易有道及豌豆莢。 2015 年創業,成立 PingCAP,致力於下一代開源分佈式數據庫的研發工作,擅長分佈式存儲系統設計與實現,高並發後端架構設計。

相關閱讀:

2010 年代的分佈式系統:存儲之數據庫篇