如何構建分散式系統的知識體系

馬猴燒酒~楪詩月發表於2018-09-02

對於開發工程師們來說,相信對於這種招聘要求的描述並不陌生:”熟悉分散式系統的設計和應用;熟悉分散式、快取、訊息、搜尋等機制;能對分散式常用技術進行合理應用,解決問題”。
現在基本上大多數大、中型企業都會要求工程師們,除了要能在分散式環境中進行開發,還要了解其中的原理、機制,對於架構師來說還需要能夠獨立設計分散式系統。

分散式(計算機)系統的概念起源很早,目前已經基本涵蓋了大多數系統架構設計。無論是SOA架構,或者微服務、Serverless架構,都是基於分散式環境的。掌握分散式系統的知識體系是理解很多架構的基礎。比如日益盛行的微服務架構,也是基於分散式計算環境。設計分散式系統中需要解決的問題,對於微服務架構也是一樣。如果基於容器技術,比如Docker容器來部署微服務例項,那麼還需要了解跨容器平臺的服務治理。

本文主要談談,分散式架構體系的幾個核心內容。開發工程師們可以根據這些內容,逐漸積累和構建自己的知識體系,並往技術架構方向邁進。

分散式知識的核心模組

分散式系統最開始是起源於分散式計算機的概念,隨著資訊科技的發展,需要處理的資料以及計算已經超過了單臺計算機能夠擴充套件的系統資源。將資料、程式分散到多臺計算機,通過一定的通訊機制進行資料傳輸、共享,便產生了分散式的計算機系統。分散式計算髮展至今,衍生了SOA、微服務等架構模型。

在資源的利用方面,最早期的分散式計算是無共享系統資源的,機器與機器之間通過網路通訊進行分散式資料共享。後期隨著虛擬機器技術的發展,一臺機器可以執行多臺虛擬機器,它們可以共享機器的硬體資源,節約維護成本。而今,更加流行的容器技術可以只基於一個作業系統核心,而不需要整個作業系統的資源,一臺機器可以部署更多的容器例項(比如Docker,一臺機器可以部署上千個Docker容器例項),並且例項之間像獨立的作業系統一樣獨立執行、計算。

可以看出,隨著資料和計算規模的增長,分散式系統是朝著越來越輕量級的資源利用,以及越來越細粒度和鬆耦合的服務化方向發展的。

分散式系統發展至今,從技術架構的角度來說,核心模組主要是: 儲存服務通訊和服務治理 以及 分散式事務。這三個模組的每一部分都涉及到很多知識點以及實踐中需要解決的分散式問題。設計一個分散式系統,在技術架構上只要能處理好這三個模組,其餘部分便是具體的 架構模型選擇(如: SOA、微服務、Serverless等)、架構思想選擇(如: 分層的思想、事件驅動的思想、DDD思想等)以及應用層面的中介軟體和框架的選擇(如:會有哪幾種開發語言,基於哪種服務間通訊協議、用什麼框架整合)。如下圖簡單列舉:

分散式系統知識體系

核心知識模組

  1. 分散式儲存
    在分散式系統中,尤其是資料密集型應用會涉及到很多分散式儲存技術。分散式的儲存主要有兩個方向的知識模組,一個是資料複製,也即一個資料在多個節點(Data Node)有相同的資料副本。另一個是資料分割槽,將大資料模型拆成多份到多個節點(Data Node)。這兩個方案都可以提高系統的吞吐量,並且也是一種容災備份的考量。不同的儲存引擎、技術中對於複製、分割槽實現各有不同,但是核心的演算法和分散式計算模型是相通的。
    一般來說開發工程師很少去自己研發一套類似Redis、MongoDB、DynamoDB這樣的儲存系統,但瞭解這些技術的共通的原理和機制,可以幫助我們更好地使用,以及分析各種分散式問題。

    1.1 複製
    資料複製有兩種複製模型:同步,以及非同步同步複製一般是阻塞的,可以保證所有的資料節點都保持有一致的資料副本,但是吞吐量低;非同步複製是非阻塞的,在資料儲存到主庫後請求便立即返回,主庫和其他從庫之間的資料採用非同步的方式進行同步,一致性模型上保證了最終一致性
    從資料節點的角色分配來說,最簡單的資料複製方案即是“主-從”複製。通過資料複製,可以使儲存服務擁有備份,當主庫掛掉時可以將資料讀寫請求切換到從庫。如果遇到網路故障,主,從節點都無法提供服務時,基於“主-主”複製的多資料中心便可以解決。但是,越複雜的資料節點結構需要處理的問題也越多,比如不同資料節點的讀寫一致性問題,多個主節點都接受寫請求時,寫資料衝突的解決等。
    不同的儲存技術的資料複製的實現,以及支援的複製策略會有所區別,學習資料複製相關的知識可以通過不同儲存引擎的官網以及找一些經典的論文資料。這裡舉個簡單的例子,比如Mysql的叢集方案,可以看看Mysql 資料複製實現細節mysql叢集資料複製方案

    1.2 分割槽
    資料複製相當於同一個資料來源的相同副本儲存在不同的資料節點中,資料分割槽是將一份資料來源以一定的規則拆分成多份,也是分佈在不同的資料節點中。簡單來說,複製等於將資料檔案copy到不同機器上,分割槽是將大的資料檔案以一定的規則拆成一個個小的檔案,分散到不同機器上。資料分割槽往往可以和資料複製結合使用。
    很多資料儲存引擎都自帶分割槽功能(如PostgreSQL,Mysql,Oracle),分割槽功能對開發者是透明的。除了分割槽,另外一個常用的將大資料拆成小資料集的方式就是分表,一般是基於索引設定一個路由規則,比如取模,將一個資料表進行拆分。分表和分割槽的實現上以及場景上有所區別,也可以同時使用。這兩者都可以提高資料訪問的速度,並且擴充套件性高。

    總結來說:在分散式環境下,隨著資料量增大,效能的壓力以及擴充套件性的需求,在儲存服務層可以做的技術方案主要是資料複製、分割槽。複製和分割槽一般都是很多儲存服務內建的功能。從應用層或者中介軟體層來說,還可以採用分表(有的儲存服務也自帶分表,或者通過外掛的方式支援分表),分表屬於水平拆分,在業務上還可以做垂直拆分,比如將一個大表拆成有外來鍵關聯的子表,將佔用資料空間大的欄位拆到其它表等方式。
    分割槽中重要的知識點主要是分割槽策略的實現,不同的儲存引擎支援的策略不同,但是基本的分割槽方案策略實現是大同小異的,學習分割槽時可以先以一個資料庫為切入點,比如Mysql 5.7 分割槽概要。想要從巨集觀角度來了解分散式解決方案時,可以看看Distributed systems for fun and profit 系列文章。如果想要體系化學習分散式資料儲存系統的方案,推薦看《Designing Data-Intensive Applications》,這本書從淺到深介紹了分散式資料叢集的方案,並對一些問題的解決機制和原理都有深入介紹。

  2. 服務通訊和服務治理
    分散式系統中,服務例項部署在不同的節點,服務間的通訊可能跨作業系統或者容器。隨著容器技術的發展,服務治理已經成為了容器服務的重點技術領域之一。服務通訊和服務治理關注的問題點以及應用的技術各有不同,但目前有很多分散式技術整合了這兩者(如Kubernates,Consul 1.2版本開始支援 Service Mesh)。

    2.1 服務通訊的基礎是:服務發現、服務註冊、健康檢查。無論是SOA架構或者微服務架構,都需要通過服務名(service name)定位到服務例項的“IP:Port”。SOA一般由企業匯流排來整合這些功能(比如Dubbo基於Zookeeper)。在基於容器的微服務架構下,可以使用類似Consul、Eureka、Etcd等更加輕量級的服務發現技術。學習的時候,可以先了解這些技術的共通點,以及經典理論,比如CAP理論FLP不可能結果理論。然後再學習這些技術背後的原理和機制。比如服務發現和服務序號產生器制,不同的技術使用的一致性演算法不同,Zookeeper基於Zab演算法,Zab又基於Paxos演算法做了很多改進;Etcd、Consul 基於 Raft演算法,在CAP理論中,Zookeeper、Etcd以及Consul 都保證了CP。而 Eureka捨棄了嚴格的一致性,選擇了AP。這些技術的知識的學習可以從官網以及Github中找到專案原始碼。

    2.2 分散式訊息佇列。對於SOA架構、微服務架構來說,訊息佇列可以用來進行服務間的解耦,並且提升請求響應的效能。在學習訊息佇列時,需要先對網路通訊的知識打好基礎(網路協議、編解碼機制,底層框架和原理等),分散式訊息佇列的儲存也是關鍵。最好先從工作中接觸到的MQ進行學習,或者選擇社群活躍的開源MQ:如Kafka、RocketMQ、RabbitMQ等。

    2.3 服務治理。服務治理在SOA架構中類似於企業匯流排涵蓋的功能。容器技術裡比較出名的服務治理技術是Kubernates。對於小規模叢集來說,不是在一開始就需要服務治理,隨著容器規模、服務體系的增長以及團隊的擴充,才開始考慮是否需要構建服務治理平臺。服務治理包含了熔斷機制、流控機制、服務監控、負載均衡、容器的透明化管理、服務例項的動態擴容縮容等等。如果不用一個服務治理技術,一開始也可以手動“治理”加上一些有熔斷、負載均衡的框架(如ribbon,hytrix)來整合到應用。服務治理包含的模組很多,不同技術的實現標準也不同,學習過程應該實踐大於理論,如果對Docker比較感興趣,可以結合Kubernates官網和Github原始碼進行學習,國內的社群可以多看看 k8s中文社群

  3. 分散式事務

    對於設計大型分散式系統,分散式事務基本上是必須要面對的一座大山。理解分散式事務,除了從應用系統的角度出發,還可以從更源頭概念來理解。比如,資料庫儲存系統的事務特點,不同隔離級別的實現。分散式應用系統很難像儲存系統一樣滿足完整的事務特性,比如2PC的解決方案,可以滿足原子性,但會犧牲效能。所以對原子性、一致性要求不嚴格的場景,更多是基於BASE理論。BASE理論適用在很多NoSQL系統中。NoSQl更多的關注點不是保證事務ACID的特性,而是效能、吞吐量、擴充套件性以及可用性。BASE也同樣適用於業務型別的分散式系統。對於分散式事務,簡單列舉下學習Route:

    3.1 瞭解關係型資料庫的事務的特性,尤其是不同的隔離級別。可以從自己最常用的資料庫著手,瞭解該資料庫的隔離級別在哪種併發場景會出現哪些讀、寫資料的問題。這方面的知識需要去一些官網,找對應版本的資料。比如PostgreSQL可以去看下PostgreSQL 事務隔離級別介紹

    3.2 針對工作中平常使用的NoSQL技術,或者自己想學的NoSQL,瞭解它們是怎樣利用叢集的特性實現高可用和高可擴充套件性。對於一些通用的實現,可以看看經典論文。比如Dynamo的這篇論文Dynamo: Amazon’s Highly Available Key-value Store。Google 的BigTable論文:Bigtable: A Distributed Storage System for Structured Data。在一些論文裡,可以瞭解到NoSQL系統是怎樣實現BASE理論,以及對於CAP中一致性模型取捨的考量。

    3.3 在實踐方面,基於X/Open(XA)標準的實現較多,但XA屬於2PC模型,保證了原子性,但是會降低系統的吞吐量,適用於一致性、原子性敏感的業務。基於BASE理論的TCC模型,以及基於可靠的分散式訊息佇列的模型現在越來越成為主流的分散式事務解決方案。這些知識點是比較零散的,不同的公司使用的方案各不相同。學習的時候可以先對這些方案的實現以及可能存在的問題進行整體的瞭解(網上的資料很多,最好找到可靠的學習資料,比如Gitchat上有一些課程和chat)。然後在遇到具體場景時需要對業務進行充分的分析,然後決定使用哪種方案。

如何構建知識體系

分散式系統的知識點很多,除了分散式的重要理論(CAP、BASE、FLP不可能理論)、共識演算法(Paxos、Raft、ZAB),還要了解一些開源的高效能、高可擴充套件的分散式NoSQL技術(如Dynamo,MongoDB,Redis)以及關係型資料庫叢集的資料複製、資料分割槽的方案和實現機制(Mysql、Oracle、PostgreSQL)。實踐中還會需要知道分散式事務的解決方案(2PC、3PC、TCC)。面對龐大的知識體系,可以將知識模組進行拆分,然後逐個攻破。
在學習的時候,可以針對各個知識點嘗試下面的方法:

  1. 利用碎片時間瞭解知識點:多在一些活躍的社群上訂閱分散式系統的文章,微服務架構方面可以多閱讀 microservicesGitchatCSDNInfoQDockerOne中關於分散式知識的文章可以每天讀上一兩篇,更加零散的時間可以閱讀一些技術公眾號的文章。

  2. 針對知識面進行體系化學習:進行體系化的學習可以先設定一些目標,比如一個月之內針對某一個知識模組,閱讀完某本書或課程、論文,並對重點知識進行自己的梳理。
    關於分散式知識推薦一些資料,《Designing Data-Intensive Applications》這本書對資料密集型系統以及分散式的儲存體系,從問題的引出到各種解決方案的介紹都非常詳盡,雖然是英文版但是易讀性強。Distributed Systems for fun and profit,其中包含了5篇文章,分別講述了分散式的一些問題和概念,作為初步瞭解是很好的資料。《分散式計算——原理、演算法與系統》這本書對很多分散式的概念,問題從數學和理論角度介紹得全面細緻,需要一定的數學基礎。
    同時,隆重推薦下自己的課程:《分散式微服務架構體系詳解》。該課程基於自己多年的分散式開發及微服務架構經驗,從分散式場景和問題出發,為大家逐一展開介紹實施微服務架構的分散式核心知識體系。
    該系列課程還包含基於Springboot、SpringCloud(Microservice)、RxJava(API-Gateway)的兩個工程原始碼,以及 Docker 映象的基礎 build 檔案。原始碼放在Github上。連結 :MicroserviceGateway。購買課程的讀者可以在讀者圈提問或留言。沒有購買的讀者也可以在Github上提Issue一起探討。感謝各位支援 OvO。

    分散式微服務架構體系詳解

相關文章