Dynamo
Apache Cassandra 仰賴 Amazon 的 Dynamo 分散式儲存鍵值系統的許多技術。Dynamo 系統中的每個節點都有三個主要元件
-
在分割資料集上要求協調
-
環狀成員資格和故障偵測
-
本機持久性 (儲存) 引擎
Cassandra 主要取用前兩個叢集元件,同時使用基於記錄結構合併樹 (LSM) 的儲存引擎。特別是,Cassandra 仰賴 Dynamo 風格
-
使用一致性雜湊進行資料集分割
-
使用版本化資料和可調整一致性進行多主體複製
-
透過八卦通訊協定進行分散式叢集成員資格和故障偵測
-
在商品硬體上進行增量擴充
Cassandra 的設計方式是為了滿足大規模 (PiB+) 業務關鍵儲存需求。特別是,由於應用程式要求對 PB 等級資料集進行完整的全球複製,同時還要持續提供低延遲的讀寫功能,因此必須設計一種新的資料庫模型,因為當時的關係資料庫系統難以滿足全球規模應用程式的需求。
資料集分割:一致性雜湊
Cassandra 透過使用雜湊函數分割儲存在系統中的所有資料來達成橫向擴充性。每個分割會複製到多個實體節點,通常跨越故障網域,例如機架甚至資料中心。由於每個複製品可以獨立接受它擁有的每個金鑰的變更,因此每個金鑰都必須建立版本。與最初的 Dynamo 論文中使用確定性版本和向量時脈來協調對金鑰的並發更新不同,Cassandra 使用較簡單的最後寫入優先模型,其中每個變更都會加上時間戳記(包括刪除),然後資料的最新版本就是「優先」值。正式來說,Cassandra 對每個 CQL 列使用最後寫入優先元素集合無衝突複製資料類型,或LWW-Element-Set CRDT,來解決複製品組上的衝突變更。
使用令牌環的一致性雜湊
Cassandra 使用稱為一致性雜湊的特殊雜湊形式,將資料分割到儲存節點上。在單純資料雜湊中,您通常會透過對金鑰進行雜湊模組桶數,將金鑰分配到桶中。例如,如果您想使用單純雜湊將資料分發到 100 個節點,您可能會將每個節點指定到 0 到 100 之間的桶,將輸入金鑰模組 100 進行雜湊,然後將資料儲存在相關聯的桶中。然而,在此單純的架構中,新增一個節點可能會使幾乎所有對應無效。
Cassandra 反而將每個節點對應到連續雜湊環上的至少一個令牌,並透過將金鑰雜湊到環上,然後沿著一個方向「遍歷」環,類似於Chord演算法,來定義擁有權。一致性雜湊與單純資料雜湊的主要差異在於,當雜湊到的節點(桶)數量發生變化時,一致性雜湊只需要移動一小部分金鑰。
例如,如果我們有一個具有均勻間隔令牌的八節點叢集,以及 3 的複製因子 (RF),則要找出一個金鑰的所有者節點,我們首先對該金鑰進行雜湊以產生一個令牌(這只不過是金鑰的雜湊),然後我們以順時針方式「走」環,直到遇到三個不同的節點,此時我們已經找到了該金鑰的所有複本。以下可以視覺化 gRF=3 的八節點叢集範例
您會看到在類似 Dynamo 的系統中,金鑰範圍(也稱為令牌範圍)會對應到相同的實體節點組。在此範例中,所有落在令牌範圍內(不包含令牌 1,包含令牌 2)的令牌(grange(t1, t2]) 都儲存在節點 2、3 和 4 上。
每個實體節點的令牌(虛擬節點)
如果有很多實體節點可以散佈資料,則單一令牌一致性雜湊運作良好,但對於均勻間隔的令牌和少數實體節點,增量擴充(只新增少數容量節點)很困難,因為沒有令牌選取可以讓新節點保持環平衡。Cassandra 會避免令牌不平衡,因為不均勻的令牌範圍會導致不均勻的請求負載。例如,在先前的範例中,沒有辦法新增第九個令牌而不造成不平衡;相反地,我們必須在現有範圍的中點插入8
個令牌。
Dynamo 論文主張使用「虛擬節點」來解決這個不平衡問題。虛擬節點透過將令牌環中的多個令牌指定給每個實體節點來解決問題。透過允許單一實體節點在環中佔據多個位置,我們可以讓小型叢集看起來更大,因此即使只新增一個實體節點,我們也可以讓它看起來像新增了更多節點,當我們新增一個節點時,實際上從更多環鄰居那裡取得許多較小塊的資料。
Cassandra 引入一些術語來處理這些概念
-
令牌:Dynamo 風格雜湊環上的單一位置。
-
端點:網路上的單一實體 IP 和埠。
-
主機 ID:單一「實體」節點的唯一識別碼,通常存在於一個 gEndpoint 中,並包含一個或多個 gTokens。
-
虛擬節點(或vnode):雜湊環上由同一個實體節點擁有的 gToken,與同一個 gHost ID。
將令牌對應到端點會產生令牌對應,Cassandra 在其中追蹤哪些環位置對應到哪些實體端點。例如,在以下圖中,我們可以使用僅有四個實體節點的八個節點叢集,方法是將兩個令牌指定給每個節點
每個實體節點的令牌越多,會提供以下好處
-
當新增一個節點時,它會從環中的其他節點接收大約相等數量的資料,導致資料在叢集中的平均分配。
-
當一個節點停用時,它會大致平均地將資料損失給環中的其他成員,再次使資料在叢集中的平均分配。
-
如果一個節點變得不可用,查詢負載(特別是令牌感知查詢負載)會平均分配到許多其他節點。
但是,多個令牌也可能帶來缺點
-
每個令牌會在令牌環上引入最多
2 * (RF - 1)
個額外鄰居,這表示節點故障的組合更多,我們會在令牌環的一部分中失去可用性。令牌越多,中斷的機率越高。 -
叢集範圍的維護作業通常會變慢。例如,隨著每個節點的令牌數增加,叢集必須執行的離散修復作業數也會增加。
-
跨越令牌範圍的作業效能可能會受到影響。
請注意,在 Cassandra 2.x
中,唯一可用的令牌配置演算法是挑選隨機令牌,這表示為了保持平衡,每個節點的預設令牌數必須相當高,為 256
。這會將許多實體端點結合在一起,增加不可用的風險。這就是為什麼在 3.x +
中新增了一個新的確定性令牌配置器,它會智慧地挑選令牌,使環得到最佳平衡,同時需要每個實體節點的令牌數更少。
多主體複製:版本化資料和可調整一致性
Cassandra 會將資料的每個分區複製到叢集中的多個節點,以維持高可用性和耐用性。當發生變異時,協調器會對分區金鑰進行雜湊,以確定資料所屬的令牌範圍,然後根據複製策略
將變異複製到該資料的複本。
所有複製策略都有複製因子 (RF
) 的概念,它會指示 Cassandra 分區應存在的副本數。例如,對於RF=3
的鍵空間,資料將寫入三個不同的複本。複本總是會選擇不同的實體節點,如果需要,會略過虛擬節點來達成此目的。複製策略也可能會選擇略過存在於相同故障網域(例如機架或資料中心)中的節點,以便 Cassandra 叢集可以容忍整個機架甚至節點資料中心的故障。
複製策略
Cassandra 支援可插入的複製策略,它會決定哪些實體節點會作為特定令牌範圍的複本。資料的每個鍵空間都有自己的複製策略。所有生產部署都應使用NetworkTopologyStrategy
,而SimpleStrategy
複製策略僅適用於測試叢集,其中您還不知道叢集的資料中心配置。
NetworkTopologyStrategy
NetworkTopologyStrategy
需要為叢集中的每個資料中心指定複製因子。即使您的叢集只使用單一資料中心,也建議使用 NetworkTopologyStrategy
而非 SimpleStrategy
,以便在需要時更容易將新的實體或虛擬資料中心新增到叢集。
除了允許個別資料中心指定複製因子之外,NetworkTopologyStrategy
也會嘗試根據Snitch
指定的資料中心中不同機架內的複本。如果機架數大於或等於資料中心的複製因子,則保證每個複本都會從不同的機架中選擇。否則,每個機架至少會有一個複本,但有些機架可能會有多個複本。請注意,這種機架感知行為有一些潛在的令人驚訝的影響。例如,如果每個機架中的節點數不是偶數,則最小機架上的資料負載可能會高很多。類似地,如果將單一節點引導到全新的機架中,它將被視為整個環的複本。因此,許多操作員選擇將單一可用性區域或類似故障網域中的所有節點配置為單一「機架」。
SimpleStrategy
SimpleStrategy
允許定義單一整數 replication_factor
。這會決定每個節點應該包含多少列的副本。例如,如果 replication_factor
為 3,則三個不同的節點應該儲存每個列的副本。
SimpleStrategy
將所有節點視為相同,忽略任何已設定的資料中心或機架。為了決定令牌範圍的複本,Cassandra 會從令牌範圍的興趣開始,逐一檢查環中的令牌。對於每個令牌,它會檢查擁有節點是否已新增至複本組,如果沒有,則會將其新增至組中。此程序會持續進行,直到將 replication_factor
個不同的節點新增至複本組中。
暫時性複寫
暫時性複寫是 Cassandra 4.0 中的實驗性功能,原始的 Dynamo 論文中沒有。此功能允許設定複本的子集,以僅複寫尚未增量修復的資料。此設定將資料備援與可用性分開。例如,如果您的鍵空間以 RF=3 複寫,並將其變更為 RF=5,其中有兩個暫時性複本,則您可以從容忍一個失敗的複本變為容忍兩個,而儲存使用量不會因此增加。現在,三個節點將複寫給定令牌範圍的所有資料,而其他兩個節點將僅複寫尚未增量修復的資料。
若要使用暫時性複寫,請先在 cassandra.yaml
中啟用此選項。啟用後,SimpleStrategy
和 NetworkTopologyStrategy
都可以設定為暫時性複寫資料。設定方式是將複寫係數指定為 <total_replicas>/<transient_replicas
SimpleStrategy
和 NetworkTopologyStrategy
都支援設定暫時性複寫。
暫時性複寫的鍵空間僅支援使用 read_repair
設定為 NONE
建立的表格;目前不支援單調讀取。您也不能在 4.0 中使用 LWT
、記錄批次或計數器。您可能永遠無法將物化檢視與暫時性複寫的鍵空間一起使用,也可能永遠無法將次要索引與它們一起使用。
暫時性複製是一項實驗性功能,尚未準備好供生產使用。預期的受眾是 Cassandra 的經驗豐富使用者,能夠完全驗證其特定應用程式的部署。這表示您有經驗可以檢查讀取、寫入、停用、移除、重建、修復和替換等作業是否都能與您的查詢、資料、組態、作業實務和可用性需求搭配使用。
預計 4.next
中的其他功能包括對暫時性複製的單調讀取支援,以及 LWT、記錄批次和計數器。
資料版本控管
Cassandra 使用變動時間戳版本控管來保證資料的最終一致性。特別是,進入系統的所有變動都會附帶一個時間戳,這個時間戳可以由客戶端時鐘提供,或者在沒有客戶端提供時間戳的情況下,由協調節點的時鐘提供。更新會根據最後寫入獲勝的衝突解決規則進行解決。Cassandra 的正確性確實仰賴這些時鐘,因此請確認有執行適當的時間同步程序,例如 NTP。
Cassandra 會對 CQL 分割中每個列的每個欄位套用不同的變動時間戳。列保證會透過主鍵保持唯一性,而列中的每個欄位會根據最後寫入獲勝的衝突解決規則解決同時變動。這表示對分割中不同主鍵的更新實際上可以在沒有衝突的情況下解決!此外,CQL 集合類型(例如映射和集合)使用相同的無衝突機制,表示對映射和集合的同時更新也保證會解決。
複製品同步
由於 Cassandra 中的複製品可以獨立接受變動,因此某些複製品可能擁有比其他複製品更新的資料。Cassandra 有許多盡力而為的技術來推動複製品的收斂,包括讀取路徑中的 複製品讀取修復 <read-repair>
和寫入路徑中的 提示移交 <hints>
。
不過,這些技術只是盡力而為,為了保證最終一致性,Cassandra 實作了 反熵修復 <repair>
,其中複製品會計算其資料集上的階層式雜湊樹,稱為 默克爾樹,然後可以在複製品之間進行比較以找出不匹配的資料。與原始的 Dynamo 論文一樣,Cassandra 支援複製品雜湊其整個資料集、建立默克爾樹、將它們彼此傳送並同步任何不匹配範圍的完整修復。
與原始的 Dynamo 論文不同,Cassandra 也實作了子範圍修復和增量修復。子範圍修復允許 Cassandra 透過建立大量僅跨越資料範圍一部分的樹狀結構,來提高雜湊樹的解析度(可能低至單一分割層級)。增量修復允許 Cassandra 僅修復自上次修復以來已變更的分割。
可調整一致性
Cassandra 支援透過一致性層級在每個操作中權衡一致性和可用性。Cassandra 的一致性層級是 Dynamo 的 R + W > N
一致性機制的版本,其中操作員可以設定參與讀取 (R
) 和寫入 (W
) 的節點數量大於複製因子 (N
)。在 Cassandra 中,您可以從常見一致性層級的選單中選擇,讓操作員可以在不知道複製因子的情況下選擇 R
和 W
行為。通常,當讀取一致性層級包含足夠的節點以保證與寫入一致性層級的交集時,寫入會對後續讀取可見。
以下一致性層級可用
ONE
-
只有一個複本必須回應。
TWO
-
兩個複本必須回應。
THREE
-
三個複本必須回應。
QUORUM
-
大多數 (n/2 + 1) 的複本必須回應。
ALL
-
所有複本都必須回應。
LOCAL_QUORUM
-
本地資料中心的大多數複本 (協調器所在的資料中心) 必須回應。
EACH_QUORUM
-
每個資料中心的大多數複本都必須回應。
LOCAL_ONE
-
只有一個複本必須回應。在多資料中心叢集中,這也保證讀取請求不會傳送到遠端資料中心的複本。
ANY
-
單一複本可以回應,或協調器可以儲存提示。如果儲存提示,協調器稍後會嘗試重播提示並將變更傳遞給複本。此一致性層級僅接受寫入操作。
寫入操作總是傳送到所有複本,無論一致性層級為何。一致性層級僅控制協調器在回應客戶端之前等待多少回應。
對於讀取操作,協調器通常只向足夠的複本發出讀取命令以滿足一致性層級。唯一的例外是,如果原始複本未在指定的時間視窗內回應,推測重試可能會向額外複本發出重複讀取請求。
選擇一致性層級
通常會挑選讀寫一致性層級,讓副本集重疊,導致所有已確認的寫入對後續的讀取可見。這通常以與 Dynamo 相同的術語表示,即 W + R > RF
,其中 W
是寫入一致性層級,R
是讀取一致性層級,而 RF
是複製因子。例如,如果 RF = 3
,則 QUORUM
要求將需要至少 2/3
副本的回應。如果 QUORUM
同時用於寫入和讀取,則至少一個副本保證參與兩者寫入和讀取要求,這反過來保證法定人數將重疊,而寫入將對讀取可見。
在多資料中心環境中,LOCAL_QUORUM
可用於提供較弱但仍然有用的保證:保證讀取會看到來自同一個資料中心中的最新寫入。這通常就足夠了,因為歸屬於單一資料中心的用戶端會讀取自己的寫入。
如果不需要這種強一致性,則可以使用 LOCAL_ONE
或 ONE
等較低的一致性層級來改善吞吐量、延遲和可用性。在複製跨越多個資料中心的情況下,LOCAL_ONE
通常比 ONE
可用性較低,但通常較快。事實上,如果在任何資料中心中有一個副本可用,ONE
都會成功。
分散式叢集成員資格和故障偵測
複製協定和資料集分割依賴於知道叢集中的哪些節點是存活和死亡的,以便可以最佳化路由寫入和讀取作業。在 Cassandra 中,存活資訊透過基於八卦協定的故障偵測機制以分散式方式共用。
八卦
八卦是 Cassandra 如何傳播基本叢集引導資訊,例如端點成員資格和節點間網路協定版本。在 Cassandra 的八卦系統中,節點不僅交換有關它們自己的狀態資訊,還交換有關它們所知的其他節點的資訊。此資訊使用 (generation, version)
元組的向量時脈加上版本,其中世代是單調時間戳,而版本是大約每秒遞增一次的邏輯時脈。這些邏輯時脈允許 Cassandra 八卦僅透過檢查八卦訊息所呈現的邏輯時脈來忽略舊版本的叢集狀態。
Cassandra 叢集中的每個節點都獨立且定期執行八卦任務。每秒,叢集中的每個節點
-
更新本地節點的心跳狀態(版本)並建構節點的叢集八卦端點狀態的本地檢視。
-
在叢集中挑選另一個隨機節點來交換八卦端點狀態。
-
以機率方式嘗試與任何無法連線的節點進行八卦傳播(如果存在的話)
-
如果步驟 2 沒有發生,則與種子節點進行八卦傳播。
當操作員第一次啟動 Cassandra 群集時,他們會指定特定節點為種子節點。任何節點都可以是種子節點,而種子節點與非種子節點之間唯一的差異在於種子節點可以在不看到任何其他種子節點的情況下啟動到環中。此外,一旦群集啟動,種子節點就會成為八卦傳播的熱點,這是因為上述步驟 4。
由於非種子節點必須能夠連線到至少一個種子節點才能啟動到群集中,因此通常會包含多個種子節點,通常每個機架或資料中心一個。種子節點通常使用現有的現成服務發現機制來選擇。
節點不必同意種子節點,而且一旦群集啟動,新啟動的節點就可以設定為使用任何現有節點作為種子。選擇與種子相同的節點的唯一優點是它會增加它們作為八卦傳播熱點的有用性。 |
目前,八卦傳播也會傳播令牌元資料和架構版本資訊。此資訊形成排程資料移動和架構擷取的控制平面。例如,如果節點在八卦傳播狀態中看到架構版本不符,它會排程與其他節點的架構同步工作。由於令牌資訊會透過八卦傳播,因此它也是用於教導節點哪些端點擁有哪些資料的控制平面。
環節成員資格和故障偵測
八卦傳播形成環節成員資格的基礎,但故障偵測器最終會決定節點是UP
還是DOWN
。Cassandra 中的每個節點都會執行Phi Accrual 故障偵測器的變體,其中每個節點都會持續獨立決定其對等節點是否可用。此決定主要是根據接收到的心跳狀態。例如,如果節點在一段時間內沒有看到來自節點的遞增心跳,故障偵測器會「判決」該節點,此時 Cassandra 會停止將讀取路由到該節點(寫入通常會寫入提示)。如果/當節點再次開始心跳時,Cassandra 會嘗試連線並建立連線,如果它可以開啟通訊管道,它會將該節點標記為可用。
|
Cassandra 絕不會在未經操作員明確指示的情況下,透過停用操作或使用 replace_address_first_boot
選項引導新節點,將節點從八卦狀態中移除。此選擇是故意的,目的是讓 Cassandra 節點在暫時失敗時,不會造成資料不必要的重新平衡。這也有助於防止同時範圍移動,也就是多個令牌範圍的複本同時移動,這可能會違反單調一致性,甚至造成資料遺失。
商品硬體上的增量擴充
Cassandra 可擴充以滿足資料大小和要求速率成長的需求。擴充表示將其他節點新增至環中,而每個其他節點都會帶來線性改善的運算和儲存。相反地,擴充表示將更多容量新增至現有的資料庫節點。Cassandra 也能擴充,在某些環境中,這可能會是較佳的選擇,視部署而定。Cassandra 讓操作員彈性選擇擴充或擴充。
Cassandra 遵循 Dynamo 的一個主要面向是嘗試在商品硬體上執行,許多工程選擇都是基於此假設。例如,Cassandra 假設節點隨時都可能失敗,自動調整以最佳使用可用的 CPU 和記憶體資源,並大量使用進階壓縮和快取技術,以從有限的記憶體和儲存功能中取得最大的儲存空間。