分散式資料庫 TiDB 過去現在和未來

qiuyesuifeng發表於2016-10-11

近年來,隨著移動網際網路、物聯網、人工智慧等技術的興起,我們已經進入了一個資訊爆炸的大資料時代,需要處理和分析的資料越來越多,與此同時,PC Server 的造價不斷降低,促使 Hadoop、Spark 等分散式分析計算框架得到廣泛的使用,可以肯定的是,在未來,分散式一定是主流的資料處理技術。TiDB 是 PingCAP 團隊開發的一款開源的 NewSQL 資料庫,整個設計參考 Google Spanner 和 F1,目標是構建一個面向高併發、高吞吐的線上海量資料儲存的關係型資料庫,提供透明的跨行事務及相容 MySQL 的 SQL 語法支援,支援無縫的水平伸縮以及跨資料中心多活等特性。目前專案社群相當活躍(5000+ Stars),已經成為在國際上有影響力的頂級開源專案。

為什麼要做這麼一個資料庫?現在的方案有什麼問題嗎?其實一直以來,在關係型資料庫這一層幾乎沒有一種優雅的分散式方案。但是作為儲存架構的核心,關係型資料庫的水平擴充套件是不可避免的,目前大多數方案基本都需要對業務層有很強的侵入性,比如採用 NoSQL 替換原有關係型資料庫,但是這樣就需要涉及大規模的業務重構,相當於將資料庫層的複雜度轉嫁給業務層;另外一種方案是通過中介軟體,或者分庫分表,但是這種方案仍然很難做到透明和資料的均勻分佈,也無法支援一致性的跨節點事務和 JOIN 操作,而且隨著叢集規模的增大,維護和擴充套件的複雜度呈指數級上升。另外經常被人忽略的是,兩種方案都沒有很好的解決高可用的問題,跨機房多活、故障恢復、擴容經常都需要繁重的人工介入。直到 Google 釋出 Spanner 和 F1 ,這才出現了一個真正在 Google 這樣的業務規模上驗證過的分散式關係型資料庫。作為 Google Spanner 和 F1 的開源實現,TiDB 和 TiKV 完美地解決了現有的這些問題。下面簡單介紹一下我們是如何解決這些問題的。

TiDB 包含三個子專案:一個是 TiDB,一個是 TiKV,還有 PD (placement driver)。TiDB 是一個無狀態的 SQL 層,客戶端可以任意連線到一個 TiDB Server 例項上,看到的儲存層是完全一致的。TiDB 負責解析使用者的 SQL 請求,生成查詢計劃,交給底層的 TiKV 去執行,TiDB 和 TiKV 通過 Protobuf RPC 進行通訊;而 TiKV 負責實際的資料儲存,支援全域性分散式事務,提供對上層透明的水平擴充套件。另外一個元件 PD 負責儲存元資訊,如 Region 具體分佈在哪臺物理節點上,每個 TiKV Node 每隔一定的時間會將自己的狀態資訊和本機的 Region 分佈情況上報給 PD,PD 會根據需要進行 Region 資料的移動和發起新增副本指令等操作,可以說是叢集的大腦,整個 TiDB 專案的架構大致就是如此。 水平擴充套件 我們先來看看 TiKV 是如何實現無縫的水平擴充套件的。

從以上 TiKV 的架構圖中可以看出,TiKV 將資料邏輯上分為很多小的 Region,每一個 Region 是一系列連續按照位元組排序的 Key-value 對。和很多傳統的中介軟體方案不同的是,TiKV 並不關心上層的 Schema 結構,也不知道上層每個 Column 的型別,就是一個很純粹的 Key-value 資料庫。 資料移動的單位是 Region,每個 Region 都會在不同的機器上維護副本(預設 3 副本)。當一個 Region 的資料增長到一定程度的時候,這個 Region 就會像細胞分裂一樣會分裂成兩個新的 Region,然後新的 Region 可能會被移動到不同的機器上,用這種方式來進行負載均衡以及容量的擴充套件。

在 TiKV 中,每個 Region 的不同副本之間通過 Raft 協議進行強一致保證,我們在 TiKV 的上層實現了兩階段提交(2PC)來支援跨 Region 的透明分散式事務。整個模型正是 Raft 的作者 Diego Ongaro 博士於 2014 年其博士論文中描述的理想的 Large-scale storagesystem 的模型:

高可用與跨資料中心多活 其實如果拋開資料庫層面來談高可用並不是太複雜,因為業務邏輯服務是比較容易設計成無狀態的(一般來說,狀態都會持久化到儲存層)。現在很多比較前衛的網際網路公司,已經在業務的最上層通過動態 DNS + LVS 、F5、HAProxy 等負載均衡工具配合 Docker 以及排程器(K8S 或者 Mesos)實現按需的動態伸縮。如果不考慮儲存層,即使整個資料中心當機,業務層也能做到透明的 Failover,也就是多起幾個容器的事情,難點無非是控制好瞬時流量等問題,這從整個模型看是比較完善的。

但是到資料庫這層就不那麼美好了,傳統的關係型資料庫的容災主要依賴主從(master-slave)模型,比如 MySQL 的半同步複製,Oracle 的 DataGuard 都屬於主從複製的範疇。但是主從模型有兩個很大的問題,即資料的一致性和故障的自動切換。在主從模型中,即使是熱備,在極端情況下也並不能保證 Failover 時資料的一致性。網路環境錯綜複雜,比如出現叢集腦裂的狀態(網路部分隔離),監控程式自動的將副本提升 master,但是原來的 master 可能仍然在處理部分客戶端的請求,這種情況下,資料就可能發生不一致。這也就是為什麼很多一致性敏感的業務即使主庫掛掉了,寧可暫停服務也不敢自動切換熱備,這樣業務的中斷時間就不可控了。再者,如果面對一個非常龐大的叢集,可能上百個物理節點甚至更多,機器故障是常態,如果每一次故障都需要人工介入,整個系統的維護代價是非常驚人的。

那有沒有辦法能在強一致的前提下做到安全的故障恢復和故障轉移呢?答案是有的。Spanner 的做法是利用 Multi-Paxos 進行同步,這類分散式選舉演算法擁有很強的容錯能力,即使發生節點當機,網路隔離,整個系統都不會發生資料丟失或者不一致的狀態。而且在保證安全的同時,所有的 Failover 工作都是自動的。自動化是一個能彈性水平擴充套件的系統的重要條件,因為一切需要人工介入的工作都是無法彈性水平擴充套件的。但是長期以來,由於 Paxos 的實現極其複雜,社群並沒有可以在生產環境中使用的實現。

在 TiKV 中我們採用了 Raft 演算法來作為和 Spanner 中的 Multi-Paxos。Raft 是 Diego Ongaro 在 2014 年釋出的一個全新的先進的分散式一致性演算法,在正確性和效能上和 Multi-Paxos 等價,但是對工程實現的複雜度控制很好。目前 TiKV 的 Raft 實現是和 CoreOS 一起合作開發的。CoreOS 是知名的 Raft 專案 etcd 背後的公司。拋棄傳統的主從模型,而選用 Raft 這樣的分散式一致性演算法為 TiDB 在穩定性和健壯性帶來了質的飛躍。可以說,整個 TiDB 系統都是構建在 Raft 這個基石之上的。

另外,得益於 Raft 演算法的特性,TiDB 可以在保證延遲處於可接受範圍內的情況下,能夠真正支援跨資料中心多活,這也是 TiDB 的一個重要特點。現在很多對於強一致性要求極端嚴格的業務,比如金融、支付、計費等,兩地三中心的部署漸漸成為共識,但是在多資料中心容災這個事情上很難找到一個很好的方案。在傳統的方案中,如果要做到強一致的熱備,需要所有資料中心的副本同步寫成功,一個寫入的延遲取決於所有資料中心尤其是最遠的資料中心的延遲。而在 TiDB 上,由於 Raft 協議只需要同步複製到「大多數」的資料中心即可保證資料的強一致性,所以寫入的延遲取決於「大多數」資料中心的延遲。一般來說,對於兩地三中心的部署,一定會有一個同城雙機房,這時候的延遲較於異地機房的延遲就會小很多了。 完整的面向分散式儲存的 SQL Layer TiDB 實現了完整的 SQL 解析器和優化器。傳統的中介軟體方案只做簡單的路由和轉發到底層的資料庫上,並不能很好地支援 JOIN 或者透明的事務,也就很難完整地相容原有的業務,對業務層有比較大的侵入性。另外傳統的單機資料庫的查詢優化器並沒有考慮到底層儲存可能是一個分散式儲存,很多優化技巧和手段都難以利用分散式的計算能力和優勢。出於以上幾點原因,TiDB 選擇了重新實現完整的 SQL 解析和 MPP SQL 優化器等元件以支援客戶端透明的複雜查詢,以及分散式事務。 另外 TiDB 支援完整的 MySQL 語法和網路協議相容。這樣,TiDB 可以直接使用 MySQL 社群的海量測試用例,大量的已有 DBA 工具,更使得那些使用 MySQL 的客戶的遷移和相容的工作成本降到最低。這很好的替代了傳統的分庫分表和中介軟體等過渡方案。而且 TiDB 還能完美相容 MySQL 的 binlog, 可以和現有的 MySQL 互為備份,進一步降低了早期的測試成本。 產品規劃 分散式執行引擎

TiDB 目前內建一個分散式執行框架,採用和 HBase Coprocessor 類似的方案。這套框架可以利用多臺 TiKV 並行處理資料,再將結果彙集到單臺 TiDB 來做最終的處理。在處理 OLTP 請求以及中小規模的 OLAP 請求時,這套框架用起來得心應手。但是當處理大型的 OLAP 請求(例如超大表之間的 Join)時,就顯得力不從心了。後續我們計劃引入一套新的分散式執行引擎,來專門處理複雜 Query。

Spark 整合

Spark 是當前最火的大資料分析工具,在業界得到廣泛的應用。TiDB 可以通過 JDBC 介面和 Spark 對接,原有的基於 MySQL 的 Spark 作業可以無縫遷移到 TiDB 上。這樣使用者可以同時享有 TiDB 海量儲存的能力以及 Spark 強大的通用計算能力,從資料中挖掘出更大的價值。這也讓 TiDB 同時支援了 OLTP 和 OLAP 兩種生態。

Kubernetes

另外一個很重要的事情就是將 TiDB 的整個部署與 Kubernetes 整合。我們認為未來的資料庫一定會和雲深度結合以提供無縫的擴充套件及部署體驗,而第一步就是和容器排程器的深度整合,我們在內部的測試版本中已經成功的將 TiDB 的部署和擴充套件在 Kubernetes 上實現,相信很快就會在社群中亮相。

社群情況 / 如何進行貢獻

目前 TiDB 專案的社群貢獻者達近百人,其中包括京東和華為的大量程式碼及 Use case 貢獻;作為一個國際化開源專案,CoreOS 及 Facebook 等公司也加入進來一起合作開發,因此也非常感謝 Facebook 的 RocksDB team 和 CoreOS 的 etcd team 的大力支援。同時,TiKV 作為 Rust 社群的頂級專案,得到了 Rust 語言官方的大力支援,專案被收錄到 Rust Weekly 作為常駐欄目向 Rust 社群通報每週進展。TiDB 作為一個開放的開源專案,歡迎一切感興趣的開發者的加入,在 Github 的 TiDB 專案首頁有 How to contribute 的文件,Welcome aboard and happy hacking!

原文連結

更多原創文章乾貨分享,請關注公眾號
  • 分散式資料庫 TiDB 過去現在和未來
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章