分佈式系統基礎
1.簡介
在本教程中,我們將了解分佈式系統的基礎。本文將介紹它們的基本特性以及它們所帶來的挑戰以及常見的解決方案。
我們還將簡要介紹一些跨多個類別的流行分佈式系統採用的方法。
2.基本概念
在了解不同系統的分佈式體系結構之前,讓我們首先清除一些基礎知識。
儘管動機在很大程度上影響了分佈式體系結構,但仍有一些基本原理和挑戰適用於所有這些。
2.1。什麼是分佈式系統
因此,讓我們從正式定義一個分佈式系統開始。分佈式系統由可能跨越地理邊界的多個組件組成,這些組件通過消息傳遞來傳達和協調其動作。對於該系統外部的參與者,它看起來好像是單個連貫系統:
現在,我們可能經常聽到有關分散式系統的信息,並將它們與分佈式系統混淆。因此,必須區別對待。分散系統是分佈式系統,其中沒有特定的組件擁有決策權。儘管每個組成部分都擁有決策的一部分,但它們都不具有完整的信息。因此,任何決定的結果都取決於所有組成部分之間的某種共識。
與分佈式系統密切相關的另一個術語是並行系統。雖然這兩個術語均指擴大計算能力,但它們實現它們的方式卻有所不同。在並行計算中,我們在一台計算機上使用多個處理器來同時執行多個任務(可能使用共享內存)。但是,在分佈式計算中,我們使用沒有共享內存且與消息傳遞進行通信的多個自治機器。
2.2。分佈式系統的好處
儘管分佈式系統的設計和構建肯定更加複雜,但它可以帶來它們帶來的好處。
讓我們快速了解一些關鍵優勢:
- 可擴展性:垂直擴展通常受硬件限制的限制,例如,我們只能有這麼多的處理器內核。但是,從理論上講,我們可以使用相對便宜的商品機器實現無限的水平縮放。
- 可靠性:由於分佈式系統由多台計算機組成,並且數據在多個節點上複製,因此它對於系統部分故障通常更具彈性。因此,即使容量降低,整個系統仍將繼續運行。
- 性能:分佈式計算的典型應用程序通過將工作負載分解為可以同時在多台計算機上運行的較小部分來進行工作。因此,這極大地提高了許多複雜工作負載的性能,例如矩陣乘法。
2.3。分佈式系統中的挑戰
如果我們認為我們能夠在沒有任何挑戰的情況下獲得分佈式系統的所有好處,那麼我們離現實還差得遠!
讓我們了解一下分佈式系統給我們帶來的一些關鍵挑戰:
- 一致性與可用性:由於分佈式系統按定義具有分區容限,因此必須在CAP定理的約束下在一致性還是可用性之間進行選擇。對於通用計算平台而言,這並非易事。
- 數據分發:分佈式系統中的數據或工作負載需要分區才能將其發送到多個節點。這引起了對複雜算法進行有效劃分並隨後組合它們的需求。
- 協調:由於分佈式系統中的數據或工作負載也跨多個節點進行複制以實現容錯功能,因此協調它們非常棘手。參與節點需要復雜的協議來達成決策。
通常在企業應用程序中,我們需要在一個事務下進行多個操作。例如,我們可能需要作為單個工作單元對數據進行多次更新。雖然在數據共置時這變得不那麼重要,但是當我們在節點集群上分配數據時,它變得相當複雜。許多系統確實使用諸如Paxos和Raft之類的複雜協議在分佈式環境中提供諸如語義之類的事務。
3.建築與類別
儘管近來對分佈式系統的興趣重新興起,但基本原理並不新鮮。相當長一段時間以來,分佈式系統已經看到了許多體系結構模式來解決與數據相關的特定用例的泛型。
在本節中,我們將討論分佈式系統的一些架構模式以及它們可以服務的不同類別的用例。
3.1。分佈式系統架構
分佈式系統的系統架構取決於用例和我們對它的期望。但是,在大多數情況下,我們可以找到一些常規模式。
實際上,這些是該體系結構採用的核心分發模型:
- 主從:在此模型中,分佈式系統的一個節點扮演主角色。在此,主節點具有有關係統的完整信息並控制決策。其餘節點充當臨時節點並執行主節點分配給它們的任務。此外,出於容錯目的,主節點可以具有冗餘備用數據庫。
- 對等:在此模型中,在分佈式系統的節點之間沒有指定單個主服務器。所有節點均平等地承擔主節點的責任。因此,我們也將其稱為多主模型或無主模型。以增加複雜性和通信開銷為代價,此模型提供了更好的系統彈性。
雖然這兩種體系結構都有各自的優缺點,但不必只選擇一種。實際上,許多分佈式系統都創建了將兩個模型的元素結合在一起的體系結構。
對等模型可以提供數據分發,而主從模型可以在同一體系結構中提供數據複製。
3.2。分佈式系統類別
設計分佈式系統可能有多種理由。例如,我們需要在機器學習模型中大規模執行諸如矩陣乘法之類的計算。這些不可能容納在一台機器上。
同樣,處理大型文件並將其處理並存儲在單台計算機上的系統可能是不可能的,或者至少效率很低。
因此,根據用例,我們可以將分佈式系統大致分為以下幾類。但是,這絕對不是分佈式系統可能用例的詳盡列表:
- 資料儲存庫
- 訊息傳遞
- 電腦運算
- 分類帳
- 文件系統
- 應用領域
傳統上,相當長一段時間以來,關係數據庫是數據存儲的默認選擇。但是,隨著最近數據量,種類和速度的增長,關係數據庫開始達不到預期。這就是NoSQL數據庫及其分佈式體系結構開始被證明更有用的地方。
同樣,傳統的消息傳遞系統也無法與現代數據規模的挑戰保持隔離。因此,對可以提供性能,可伸縮性以及可能的耐用性的分佈式消息傳遞系統的需求開始上升。如今,該領域中有幾種選項可以提供多種語義,例如發布-訂閱和點對點。
在本教程中,我們將討論一些流行的分佈式數據庫和消息傳遞系統。重點將主要放在通用體系結構上,以及它們如何解決分佈式系統的一些關鍵挑戰,例如分區和協調。
4. Apache Cassandra
Cassandra是採用分佈式寬列存儲模型的開源,分佈式鍵值系統。它具有完整的多主數據複製功能,可提供高可用性和低延遲。它具有線性擴展能力,沒有單點故障。
Cassandra支持高可用性和可伸縮性,因此是最終一致的數據庫。從本質上講,這意味著對數據的所有更新最終將到達所有副本。但是,相同數據的不同版本可以暫時存在。但是,Cassandra還以一致性級別列表的形式提供可調的一致性,供讀取和寫入操作選擇。
4.1。資料分配
Cassandra通過在集群中的節點之間平均劃分所有數據來提供水平擴展。在集群上分佈數據的一種簡單方法是使用分佈式哈希表。但是,如果群集中的節點數發生更改,它們通常會遭受重新哈希處理。這是一致哈希證明更好的地方,因此由Cassandra使用。
一致性哈希是一種分佈式哈希方案,與群集中的節點數無關。它具有抽象環的概念,該環代表哈希值的總範圍,也稱為令牌:
Cassandra將群集中的每個節點映射到此令牌環上的一個或多個令牌,以便總令牌範圍均勻地分佈在群集中。因此,每個節點在此環中都擁有一系列令牌,具體取決於我們在令牌中放置令牌的位置。
為了確定密鑰的所有權,Cassandra首先通過哈希密鑰來生成令牌。它使用分區程序作為哈希函數,Murmur3Partitioner是默認的分區程序。一旦它在環上找到了密鑰的令牌,它就會沿順時針方向移動環以識別擁有令牌並因此擁有密鑰的最近節點。
現在,Cassandra還可以跨多個物理節點複製每個分區,以提供容錯能力。它支持可插拔複製策略(如Siple策略和網絡拓撲策略),以確定哪些節點充當給定令牌範圍的副本。對於簡單策略,它只是一直走下去,直到找到由複制因子(RF)定義的不同節點的數量。
4.2。協調
由於Cassandra集群是多主機集群,因此集群中的每個節點都可以獨立接受讀取和寫入操作。接收到請求的節點充當應用程序的代理。我們稱代理節點為協調器,並負責使用分區器識別擁有密鑰的節點。
因此,每個節點都需要知道集群中哪些節點處於活動狀態或死亡狀態,以最佳地路由操作。 Cassandra使用Gossip協議在群集中傳播基本的群集引導信息:
閒話是一種對等通信協議,其中每個節點定期與其他幾個節點交換狀態信息。他們交換有關自己以及他們知道的其他節點的信息。此外,它使用矢量時鐘對信息進行版本控制,以便八卦可以忽略群集狀態的舊版本。
多主機體系結構的另一個問題是多個副本可以同時接受相同的密鑰更改請求。因此,必須有一種機制可以協調副本集上的並發更新。
Cassandra使用Last-Write-Wins模型來解決此問題。為簡化起見,在這裡,每個突變都帶有時間戳記,而最新版本總是勝出。
5. MongoDB
MongoDB是一個開源的,通用的,基於文檔的分佈式數據庫,將數據存儲為文檔的集合。文檔是由字段和值對組成的簡單數據結構。此外,它還提供用於復雜數據建模的嵌入式文檔和數組。
我們可以將MongoDB分片部署為副本集。副本集的主要成員處理所有請求。在自動故障轉移期間,分片通常仍然無法處理請求。默認情況下,這使MongoDB高度一致。但是,為了獲得高可用性,客戶端可以選擇從二級複製副本中讀取,在該副本中,數據最終只會保持一致。
5.1。資料分配
MongoDB使用分片鍵在多個分片中分佈集合中的文檔。我們可以從文檔中的一個或多個字段創建分片鍵。顯然,分片密鑰的選擇暗含了分片集群的性能,效率和可伸縮性。
MongoDB使用分片鍵將數據劃分為多個塊。它試圖在集群中的所有分片上實現塊的均勻分佈:
MongoDB支持兩種分片策略,即哈希分片和範圍分片。使用散列分片,它可以計算分片鍵值的散列,並為每個塊分配一定範圍的散列值。使用遠程分片,MongoDB根據分片鍵值將數據劃分為多個範圍,並為每個塊分配一個範圍。
平衡分片之間的塊分佈也很重要。 MongoDB中的默認塊大小為64 MB。當數據塊超過指定的大小限製或文檔數超過配置的限制時,MongoDB會根據分片鍵值拆分數據塊。此外,MongoDB運行平衡器過程,該過程自動在碎片之間遷移塊以實現均勻分配。
為了提高數據的局部性,MongoDB提供了區域的概念。當分片跨越多個數據中心時,這特別有用。在分片群集中,我們可以基於分片鍵創建區域。此外,我們可以將每個區域與集群中的一個或多個分片相關聯。因此,MongoDB將僅將區域覆蓋的塊遷移到與該區域關聯的碎片。
5.2。協調
MongoDB使用分片作為在多台計算機之間分配數據的方法。因此,MongoDB的分片集群可水平擴展。分片包含數據的子集,每個分片都可以作為副本集部署。集群還包括mongos,查詢路由器和用於存儲元數據和配置設置的配置服務器:
副本集在MongoDB中提供自動故障轉移和數據冗餘。正如我們在上面看到的,副本集是一組維護相同數據集的mongod實例。主數據庫通過將所有寫入操作記錄在其稱為oplog的操作日誌中來處理所有寫入操作。然後,輔助服務器異步複製主服務器的操作日誌。
當主要節點在配置的時間內未與輔助節點進行通信時,合格的輔助節點可以通過選舉來提名自己為新的主要節點。除了主要的和次要的,我們還可以有其他mongod實例(稱為仲裁器),它參與選舉但不保存數據。群集嘗試完成新主數據庫的選擇。
這確實為MongoDB中的數據丟失留出了空間,但是我們可以通過選擇適當的寫入關注點來將其最小化。寫關注是我們從MongoDB請求的確認級別。對“多數”的關注是指我們要求確認該寫操作已傳播到計算出的大多數含數據投票成員。
6. Redis
Redis是一個開源數據結構存儲,我們可以將其用作數據庫,緩存甚至消息代理。它支持各種類型的數據結構,例如字符串,列表,映射等。它主要是具有可選持久性的內存鍵值存儲。
Redis使用主從結構(從站是主站的精確副本)提供高可用性。主節點接受來自客戶端的寫請求。它還進一步將寫入異步複製到從屬節點。但是,客戶端可以使用WAIT命令請求同步複製。因此,Redis優先考慮可用性和性能,而不是強一致性。
6.1。資料分配
Redis將數據劃分為多個實例,以受益於水平縮放。它提供了幾種替代的數據分區機制,包括範圍分區和哈希分區。現在,範圍分區很簡單,但是使用起來不是很有效。相反,散列分區被證明效率更高。
哈希分區的基本前提很簡單。我們可以獲取密鑰,並使用任何標準的哈希函數(例如CRC32)來生成密鑰的哈希,而哈希只是一個數字。然後,我們對散列執行模運算,以獲得可以在其上映射此鍵的實例。顯然,這有一定的局限性,即一致的哈希性能更好。
現在,可以在Redis的軟件堆棧的不同部分進行分區。從客戶端開始,一些Redis客戶端實現客戶端分區。然後,我們進行了基於代理的分區,其中像Twemproxy這樣的代理處理了分區:
在這裡,Redis Sentinel通過在實例或分片內提供自動故障轉移來提供高可用性。最後,我們還可以使用查詢路由,其中集群中的任何隨機實例都可以通過將請求路由到正確的節點來處理請求。
Redis Cluster允許自動分區和高可用性,因此是實現此目標的首選方法。它混合使用查詢路由和客戶端分區。 Redis集群使用分片的形式,其中每個鍵都是哈希槽的一部分。 Redis群集中有16384個哈希槽,每個節點負責其中的一個子集。
6.2。協調
Redis Cluster是Redis的分佈式實現,具有高性能目標,線性可伸縮性,高可用性和可接受的寫入安全性。它遵循一個主動-被動體系結構,該體系結構由多個主機和從機組成:
Redis集群中的節點負責保存數據,將密鑰映射到正確的節點,檢測集群中的其他節點,並在需要時提升從屬節點進行主控。為了完成所有這些任務, Redis群集中的每個節點都通過TCP總線和稱為Redis群集總線的二進制協議進行連接。此外,節點使用八卦協議傳播有關群集的信息。
由於Redis Cluster使用異步複製,因此需要提供合理的寫安全性以防止出現故障。 Redis Cluster使用上一個故障轉移勝出隱式合併功能。這意味著最後選舉的主數據集最終將替換所有其他副本。當在分區期間可能丟失寫操作時,這會留下一小段時間。但是, Redis會盡最大努力保留客戶端連接到大多數master時執行的寫操作。
Redis Cluster不會將命令代理到正確的節點。相反,它們將客戶端重定向到服務於鍵空間給定部分的正確節點。客戶端可以自由地向所有群集節點發送請求,並在需要時進行重定向。但是,最終,客戶端會收到有關群集的最新信息,並可以直接聯繫正確的節點。
7. Apache Kafka
Kafka是一個開放源代碼平台,旨在提供統一的,高吞吐量,低延遲的系統來處理實時數據饋送。它使我們能夠發布和訂閱事件流,持久而可靠地存儲事件流,並在事件發生或追溯時處理事件流。
為了增強耐用性和可用性,Kafka通過自動故障轉移跨多個節點複製數據。僅當所有in-sync-replicas使用完該事件後,該事件才被視為已提交。而且,只有承諾的使用者才能接收消息。因此, Kafka的設計具有高度的一致性和可用性,可以使用許多配置。
7.1。資料分配
Kafka組織並持久存儲主題中的事件。生產者是將事件發佈到主題的應用程序,消費者是從主題中訂閱事件的應用程序。我們可以將每個主題劃分為一個或多個分區,並將它們分佈在不同的節點上以實現可伸縮性。這也允許多個使用者並行地從一個主題讀取數據:
從生產者的角度來看,這裡的分區很簡單,一個提交日誌以追加模式工作。分區中的每個事件都有一個稱為偏移的標識符,該標識符唯一地標識事件在提交日誌中的位置。此外,Kafka將主題中的事件保留一段可配置的時間。
生產者可以控制將事件發佈到哪個分區。它可以是可用分區之間的隨機負載平衡,也可以使用某些語義分區功能。我們可以定義一個分區鍵,Kafka可以使用該鍵將事件散列到固定的分區。這導致事件在分區中的局部性,這可能對消費者很重要。
消費者可以選擇從任何偏移點讀取事件。 Kafka中的使用者組在邏輯上將多個使用者分組,以負載均衡某個主題分區的消耗。 Kafka僅將主題分區分配給使用者組中的一個使用者。當組中使用者的數量發生變化時,Kafka會自動嘗試重新平衡使用者之間的分區分配。
7.2。協調
Kafka群集通常由多個服務器組成,這些服務器可以跨越多個數據中心或云區域。它們使用高性能的TCP網絡協議相互通信,並與客戶端通信。我們將保存數據作為主題分區的服務器稱為代理。每個經紀人擁有幾個分區。
此外,Kafka使用ZooKeeper來存儲元數據,例如分區的位置和主題的配置:
如我們所見,Kafka還跨可配置數量的代理複製每個主題分區的日誌。所有對主題的寫入和讀取都通過分區的負責人。領導者協調以使用新數據更新副本。萬一領導者發生故障,其中一個副本將通過自動故障轉移來接管領導者的角色。
如果Kafka可以維持與ZooKeeper的會話並且不會落後於領導者,那麼它會將副本定義為同步副本(ISR)。直到所有in-sync-replicas都收到write,才認為對Kafka的寫已落實。此外,只有同步副本集中的成員才有資格被選舉為領導者。因此,Kafka可以忍受除一個同步副本之外的所有故障,而不會丟失已提交的數據。
根據我們配置和使用Kafka客戶端的方式,我們可以實現不同的消息傳遞語義。例如,最多一次,至少一次或恰好一次。在生產者端,我們可以通過配置生產者的acks
屬性和代理的min.insync.replica
屬性來實現不同的交付語義。同樣,在消費者方面,我們可以使用enable.auto.commit
配置來控制傳遞語義。
8. CAP定理的一個註記
埃里克·布魯爾(Eric Brewer)提出了CAP定理,以根據它可以保證的屬性定義對分佈式系統的約束。基本上,這意味著分佈式系統不能同時提供以下三個保證中的兩個以上:
- 一致性:每次讀取都會收到最近的寫入或錯誤
- 可用性:每次讀取都會收到非錯誤響應,即使它不是最近的寫入也是如此
- 分區容限:即使部分網絡出現故障,系統仍可繼續運行
在上面,我們可以看到CAP定理如何被用作對分佈式系統進行分類的指導性星!但是,這種分類通常過於簡單,可能會被誤導,並且在某種程度上也不必要。
現在,在分佈式系統中幾乎不可能完全消除網絡分區的可能性。因此,基本上,CAP定理的含義可以歸結為在一致性或可用性之間進行權衡。因此,一個聲稱是分佈式的系統和CA必須對其運行所在的網絡抱有堅定的信念。
但是,正如我們在前面討論的幾個分佈式系統的上下文中所看到的那樣,這確實不是一個容易的選擇。因此,大多數這些系統在配置中提供了很多控制,因此我們可以選擇行為作為標準要求。因此,將這些系統簡單地分類為CP或AP幾乎是不公平甚至不正確的。
9.結論
在本教程中,我們介紹了分佈式系統的基礎知識,並了解了主要的好處和挑戰。此外,我們對跨數據存儲和消息傳遞系統的一些流行的分佈式系統進行了廣泛的評估。
我們強調了它們如何在分佈式體系結構中實現數據分發和協調。