CeresDB 的分佈式架構探索 — Shard Lock 機制
CeresDB 最近發佈了 v1.2.0,這個是一個比較大的版本,在這個版本中,我們對於 CeresDB 的可觀測性、寫入性能、InfluxQL 支持、Proxy 模塊都做了相當大的增強,此外,最重要的是重構了集羣的 failover 和動態調度的實現機制,讓後續的集羣特性開發變得更加簡潔、優雅,本文將就這一點進行一些經驗的分享,希望對於讀者有所啓發。
-
GitHub 倉庫:https://github.com/CeresDB/ceresdb
-
CeresDB 文檔:https://docs.ceresdb.io
-
Release v1.2:https://github.com/CeresDB/ceresdb/releases/tag/v1.2.0
1. 背景
我們在官方文檔集羣模式篇中介紹了 CeresDB 的集羣方案,簡單總結一下就是:
-
計算存儲分離;
-
由中心化的元數據中心,管理整個集羣;
存算分離的架構下,有個重要的問題在於:在集羣調度的過程中,如何保證在共享的存儲層中的數據不會因爲不同的計算節點訪問導致數據損壞。一個簡單的例子就是如果同一塊數據塊被多個計算節點同時更新,可能就會出現數據損壞。
而 CeresDB 的解決方案是通過特定的機制,在共享存儲的情況下達到了類似 Shared-Nothing 架構 的效果,也就是說存儲層的數據經過一定規則的劃分,可以保證在任何時刻最多隻有一個 CeresDB 實例可以對其進行更新,本文中,將這個特性定義成集羣拓撲的正確性,如果這個正確性得到保證的話,那麼數據就不會因爲集羣的靈活調度而受到損壞。
本文對於 Shared Nothing 架構的優劣不做贅述,主要分享一下,CeresDB 集羣方案是如何在計算存儲分離的方案下,達到 Shared Nothing 的效果(即如何保證 集羣拓撲的正確性)。
2. 數據劃分
爲了達到 Shared-Nothing 的效果,首先需要將數據在共享的存儲層上面進行好邏輯和物理的劃分。在 此前的集羣介紹文章 中介紹了 Shard 的基本作用,作爲集羣的基本調度單元,實際上也是數據分佈的劃分單元,也就是說不同的 Shard 在存儲層的數據是隔離的:
-
WAL 中,寫入的 Table 數據會按照 Shard 組織起來,按照 Shard 寫入到 WAL 的不同區域中,不同的 Shard 在 WAL 中的數據是隔離開的;
-
在 Object Storage 中,數據的管理是按照 Table 來劃分的,而 Shard 和 Table 之間的關係是一對多的關係,也就說,任何一個 Table 只屬於一個 Shard,因此在 Object Storage 中,Shard 之間的數據也是隔離的;
3.Shard Lock
在數據劃分好之後,需要保證的就是在任何時刻,同一時刻最多隻有一個 CeresDB 實例能夠更新 Shard 的數據。那麼要如何保證這一點的呢?很自然地,通過鎖可以達到互斥的效果,不過在分佈式集羣中,我們需要的是分佈式鎖。通過分佈式鎖,每一個 Shard 被分配給 CeresDB 實例時,CeresDB 必須先獲取到相應的 Shard Lock,才能完成 Shard 的打開操作,對應地,當 Shard 關閉後,CeresDB 實例也需要主動釋放 Shard Lock。
CeresDB 集羣的元數據服務 CeresMeta 是基於 ETCD 構建的,而基於 ETCD 實現分佈式的 Shard Lock 是非常方便的,因此我們選擇基於現有的 ETCD 實現 Shard Lock,具體邏輯如下:
-
以 Shard ID 作爲 ETCD 的 Key,獲取到 Shard Lock 等價於創建出這個 Key;
-
對應的 Value,可以把 CeresDB 的地址編碼進去(用於提供給 CeresMeta 調度);
-
Shard Lock 獲取到了之後,CeresDB 實例需要通過 ETCD 提供的接口對其進行續租,保證 Shard Lock 不會被釋放;
CeresMeta 暴露了 ETCD 的服務提供給 CeresDB 集羣來構建 Shard Lock,下圖展示了 Shard Lock 的工作流程,圖中的兩個 CeresDB 實例都嘗試打開 Shard 1,但是由於 Shard Lock 的存在,最終只有一個 CeresDB 實例可以完成 Shard 1 的打開:
4. 其他方案
Shard Lock 的方案本質上是 CeresDB 通過 ETCD 來保證在集羣中對於任何一個 Shard 在任何時刻最多隻有一個 CeresDB 實例可以對其進行更新操作,也就是保證了在任何時刻 集羣拓撲的正確性,需要注意,這個保證實際上成爲了 CeresDB 實例提供的能力(雖然是利用 ETCD 來實現的),而 CeresMeta 無需保證這一點,下面的對比中,這一點是一個非常大的優勢。
除了 Shard Lock 這個方案,我們還考慮過這樣的兩種方案:CeresMeta 狀態同步和 CeresDB 提供一致性協議。下面我們進行重點對比介紹。
CeresMeta 狀態同步
CeresMeta 規劃並存儲集羣的拓撲狀態,保證其正確性,並將這個正確的拓撲狀態同步到 CeresDB,而 CeresDB 本身無權決定 Shard 是否可以打開,只有在得到 CeresMeta 的通知後,才能打開指定的 Shard。此外,CeresDB 需要不停地向 CeresMeta 發送心跳,一方面彙報自身的負載信息,另一方面讓 CeresMeta 知道該節點仍然在線,用以計算最新的正確的拓撲狀態。
該方案也是 CeresDB 一開始採用的方案,該方案的思路簡潔,但是在實現過程中卻是很難做好的,其難點在於,CeresMeta 在執行調度的時候,需要基於最新的拓撲狀態,決策出一個新的變更,並且應用到 CeresDB 集羣,但是這個變更到達某個具體的 CeresDB 實例時,即將產生效果的時候,該方案無法簡單地保證此刻的集羣狀態仍然是和做出該變更決策時基於的那個集羣狀態是一致的。
讓我們用更精確的語言描述一下:
上述的例子的問題在於,t3 時刻,CeresDB 執行變更 U 是否正確呢?執行這個變更 U,是否會讓數據遭到損壞?這個正確性,需要 CeresMeta 完成相當複雜的邏輯來保證即使在集羣狀態爲 S1 的情況下,執行 U 變更也不會出現問題,除此之外,狀態的回滾也是一個非常麻煩的過程。
舉一個例子,就可以發現這個方案的處理比較麻煩:
自然是有一些辦法來避免掉 t2 時刻的事情,比如在 t0 時刻失敗了之後,需要等待一個心跳週期,來獲知 CeresDB0 是否仍然在嘗試打開 Shard0,來避免 t1 時刻發出的命令,但是這樣的邏輯比較繁瑣,難以維護。
對比 Shard Lock 的方案,可以發現,該方案嘗試獲得更強的一致性,即嘗試保證集羣的拓撲狀態在任何時刻都需要和 CeresMeta 中的集羣狀態保持一致,顯然,這樣的一致性肯定是能夠保證集羣拓撲的正確性的,但也正因爲如此實現起來纔會更加複雜,而基於 Shard Lock 的方案放棄了這樣一個已知的、正確的集羣拓撲狀態,轉而只需要保證集羣狀態是正確的即可,而不需要知道這個狀態究竟是什麼。更重要的是,從另外一個角度來看,保證集羣拓撲的正確性這部分邏輯和集羣的調度完成了解耦,因此 CeresMeta 的邏輯大大簡化,只需要專注於完成負載均衡的集羣調度工作即可,而集羣拓撲的正確性由 CeresDB 本身來保證。
CeresDB 提供一致性協議
該方案是參考 TiDB 的元數據服務 PD 的,PD 管理着所有的 TiKV 數據節點,但是 PD 不需要維護一致性的集羣狀態,並且應用到 TiKV 節點上面去,因爲 TiKV 集羣中,每一個 Raft Group 都能夠達到一致性,也就是說 TiKV 無需藉助 PD,本身就具備了讓整個集羣拓撲正確的能力(一個 Raft Group 不會出現兩個 Leader)。
參考該方案,實際上我們也可以在 CeresDB 實例之間實現一致性協議,讓其本身也具備這樣的能力,不過在 CeresDB 之間引入一致性協議,似乎把事情變得更加複雜了,而且目前也沒有更多的數據需要同步,通過外部的服務(ETCD)依然可以同樣的效果,從 CeresMeta 看,就等價於 CeresDB 本身獲得了讓集羣一致的能力。
因此 Shard Lock 的方案,可以看作是該方案的一個變種,是一種取巧但是很實用的實現。
5. 總結
CeresDB 分佈式方案的最終目標自然不是保證集羣拓撲正確就夠了,但是保持正確性是後續特性的重要基石,一旦這部分的邏輯簡潔明瞭,有充分的理論保證,就可以讓後續的特性實現也同樣的優雅、簡潔。例如,爲了使得 CeresDB 集羣中的各個節點達到負載均衡的效果,CeresMeta 就必須根據 CeresDB 實例上報的消息,對集羣中的節點進行調度,而調度的單位必然是 Shard,然而任何一次 Shard 的變動都可能造成數據的損壞(一個 Shard 被兩個實例同時打開),在有了 Shard Lock 的保證後,CeresMeta 就可以放心地生成調度計劃,根據上報的負載信息,計算出當前狀態的最佳調度結果,然後發送到涉及的 CeresDB 實例讓其執行,即使計算的前提可能是錯誤的(即集羣狀態已經和計算出調度結果時的狀態不一樣了),也不用擔心集羣拓撲的正確性遭到破壞,因而 CeresMeta 的調度邏輯,變得簡潔而優雅(只需要生成、執行,不需要考慮失敗處理)。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/wM6WTSTCMf7pPb5T7YSQZA