分佈式系統最全詳解 -萬字圖文總結-

大家好,我是 mikechen。

分佈式系統是大型網站架構的必經之路,是處理大規模數據、和高併發請求的關鍵,下面我就全面來詳解分佈式系統 @mikechen

分佈式系統

分佈式系統:是通過網絡連接的多臺獨立計算機 (比如:物理服務器、虛擬機、或容器) 協同工作,共同完成特定任務的計算系統。

一般,具體典型的 4 大特點:

分佈式系統關鍵技術,會涉及到:負載均衡、數據分片、一致性協議、分佈式鎖、分佈式緩存.......... 等等,下面我就分別來詳解 @mikechen

負載均衡

負載均衡是一種在多個計算資源(如: 服務器、節點)之間分配工作負載的技術,以確保沒有單個資源過載,從而提高系統的可用性、和響應速度。

如下圖所示:

可以動態添加 / 或移除服務器,以應對流量變化,實現系統的彈性擴展。

而且,通過在多個服務器之間分配流量,即使部分服務器發生故障,系統仍然可以繼續運行。

負載分配策略,常見的有:

數據分片

數據分片(Sharding)是一種將大數據集分割成更小的數據塊,並分佈存儲在多個數據庫、或存儲節點上的技術。

典型的就是,大家現在熟知的 “分庫分表”:

比如:**按業務分庫,**根據不同的業務模塊,將數據分配到不同的數據庫中。

如下圖所示:

將用戶數據、訂單數據、和商品數據,分別存儲在不同的數據庫中,這就是典型的 “垂直分庫”,這些都是典型的 “數據分片策略”。

除此之外,還有 “水平分庫”,比如:將一個表的數據按某個字段(如用戶 ID)分割成多個子表。

例如:將用戶表分成 user_0001、user_0002 .......user_000N 等多個子表,這就會涉及到具體的分片策略:

通過這些分片策略,可以極大的降低數據量,從而,提升數據查詢效率。

分佈式事務

分庫分表是解決數據庫性能 / 和擴展性問題的有效手段,但同時也會帶來一些挑戰、和問題,比如:分佈式事務。

跨多個數據庫實例的事務管理複雜度增加,會引入分佈式事務問題,如:一致性、和隔離性的保障... 等等。

在分佈式系統中,由於存在多個獨立的數據庫實例、或服務,跨越這些實例進行事務,就會涉及到 “分佈式事務”。

如下圖所示:

這裏就會涉及到具體的 “分佈式事務解決方案 “,比如:

  1. 兩階段提交(2PC):是最經典的分佈式事務協議之一,它分爲準備階段和提交階段,通過協調器和各個參與者的交互,保證事務的原子性;

  2. 三階段提交(3PC):在 2PC 的基礎上增加了一個 CanCommit 階段,用於減少潛在的阻塞風險;

  3. 補償事務(Compensating Transaction):事務分爲 Try、Confirm 和 Cancel 三個階段,通過預留資源、確認執行和取消操作來實現分佈式事務。

分佈式 ID

同樣,分庫分表還會帶來的分佈式 ID 問題,比如:如何生成全局唯一的 ID。

傳統的自增長 ID ,在分庫分表後無法滿足全局唯一性的要求,因爲每個數據庫實例的自增長 ID 只能保證在當前實例中的唯一性。

因此,需要全局唯一的分佈式 ID,來解決這個問題。

分佈式 ID 的方案有很多,但目前使用比較主流,依然還是” 雪花算法 “,如下圖所示:

雪花算法:結合了時間戳、機器標識、和序列號的方式,生成全局唯一的 64 位整數。

包含:

  1. 符號位(1 位):最高位固定爲 0,表示生成的是正數;

  2. 時間戳(41 位):時間戳部分記錄的是當前時間與一個固定的起始時間點之間的毫秒數差值,可以表示約 69 年的時間跨度;

  3. 機器標識(10 位):機器標識部分用來標識不同的機器或節點,可以支持多達 1024 個節點;

  4. 序列號(12 位):序列號部分:用來保證在同一毫秒內生成的 ID 的唯一性。

雪花算法也是萬能,也會面臨,比如:如果系統時鐘發生回撥,有可能導致生成的 ID 出現重複。

分佈式緩存

分佈式緩存的主要作用就是:加速數據訪問,減輕數據庫等後端存儲的壓力,提高系統的性能和吞吐量。

分佈式緩存還將緩存數據存儲在多個節點上,利用多臺機器的內存資源,不僅可以提供更大的緩存容量、和更快的訪問速度。

而且,分佈式緩存可以水平擴展,即通過增加緩存節點來增加緩存容量和處理能力,從而應對系統的增長需求。

如下圖所示:

所以,目前大型架構都會廣泛使用分佈式緩存,典型的就是:”Redis 集羣 “。

分佈式鎖

一旦開始分佈式的時候,很多” 單機鎖 “比如:"Synchronized" 的實現方式,就失靈了。

原因很簡單,鎖的是一個實例,現在變成多個” 服務器實例 “,當然,就失靈了。

所以,需要分佈式鎖,來保證資源。

常見的解決方案,如下圖所示:

比如:有基於數據庫的樂觀鎖、基於 ZooKeeper 的臨時順序節點、以及基於 Redis 的 方式來實現。。。等。

一般,主要都是使用 Redis 來實現:

**1、獲取鎖
**

使用 Redis 的 SETNX 命令(Set if Not Exists)來嘗試獲取鎖,該命令只有在鍵不存在時纔會設置鍵的值。

**2、設置過期時間
**

爲了防止死鎖問題,通常會在獲取鎖的同時設置一個過期時間,可以使用 SET key value EX seconds NX 命令來實現。

**3、釋放鎖
**

只有持有鎖的客戶端才能釋放鎖。,使用 Lua 腳本來確保原子性,即檢查鎖的持有者並刪除鎖。

分佈式一致性

一致性協議是用於保證分佈式系統中數據一致性的協議或算法,確保不同節點之間的數據能夠達到一致的狀態。

一致性協議的實現,通常會涉及到:

  1. 選舉算法:如在 Paxos 和 Raft 協議中,通過選舉一個 Leader 節點來協調和管理數據的寫入操作。

  2. 日誌複製:Leader 節點將寫入操作日誌複製到所有 Follower 節點,確保所有節點接收到相同的操作日誌。

  3. 提交操作:Leader 節點等待大多數節點確認接收到日誌後,提交操作並通知所有節點應用該操作。

  4. 故障恢復:在 Leader 節點故障時,通過選舉機制選出新的 Leader,確保系統的連續性和一致性。

總之,分佈式系統是大型架構的必經之路,也是處理大規模數據、和高併發請求的必備解決方案。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/uovxX-p0jVeTqy2HGwtNRw