Categories
程式開發

讀TiDB 論文有感| 數據強一致性且資源隔離的HTAP 數據庫


PingCAP 團隊的論文《 TiDB:基於筏的HTAP數據庫》入選VLDB 2020,這是對TiDB 數據庫階段性成果的肯定,非常為國內數據庫技術的快速發展而感到高興。 由於關於TiDB 數據庫在高可用、水平擴展和ACID 事務的實現方案很久以前就已經公佈出來了,對於這些主題大家都比較熟悉,所以就不再贅述了,下面主要談談論文中關於如何實現數據強一致性且資源隔離的HTAP 數據庫的一些啟發和感想。

OLTP或OLAP

大家都知道數據庫分為OLTP 和OLAP 類型,那麼數據庫為什麼要分成這兩類型呢?

首先,OLTP 和OLAP 是定義數據處理方式的,這是兩個差異特別明顯的工作負載,OLTP 操作是涉及數據少,但是實時性和事務要求高,並發量大;OLAP 操作是實時性和事務要求低,但是涉及數據量大,並且查詢模式不固定,很難通過索引來覆蓋。 其次,早期的數據庫是沒有OLTP 和OLAP 類型之分的,在一個數據庫(主要為關係數據庫)裡進行OLTP 和OLAP 類型的數據相關的操作,後來數據量慢慢變大,直接在關係數據庫中同時處理OLTP 和OLAP 類型的請求開始力不從心,更壞的情況可能還會影響到OLTP 類型的請求,所以針對OLAP 場景設計了更符合其工作負載的OLAP 類型數據庫,通過將OLTP 類型的數據同步到OLAP 類型的數據庫,然後再進行OLAP 類型的操作。

通過上面的方式,解決了OLTP 和OLAP 類型工作負載衝突的問題,但是引入了一次額外的外部數據複製(從OLTP 到OLAP),因而也導致了OLAP 類型操作數據的實時性和一致性丟失的問題。 這是從數據庫系統外部通過異構系統來解決這一個問題,犧牲了數據的實時性和一致性,在論文中,TiDB 提出了一個新的方案,從數據庫系統內部來解決這個問題,同時避免數據的實時性和一致性的丟失。

數據強一致性or 資源隔離

前文中,我們談到OLTP 和OLAP 是兩種差異非常大的工作負載,通常要兩者兼得的方案分為:

  1. 設計一套同時適合OLTP 和OLAP 工作負載的存儲引擎,在這一個存儲引擎來處理所有的數據請求,這樣數據的實時性和一致性的問題很好解決,但是OLTP 和OLAP 工作負載相互不影響是一個很難解決的問題,並且一套存儲引擎要同時適合OLTP 和OLAP 工作負載,在存儲引擎的設計與優化上的限制是比較多的,感覺這是在設計一種五彩斑斕的黑。
  2. 在數據庫內部同時存在兩套存儲引擎,分佈負責OLTP 和OLAP 工作負載,這可以很好避免上面的問題,但是數據需要從兩套存儲引擎中復制,這樣會導致同時滿足數據強一致性和資源相互隔離是一個很難解決的問題。

論文中,TiDB 選擇的是方案2,針對OLTP 工作負載提供一個行存引擎TiKV,針對OLAP 工作負載負載提供一個列存引擎TiFlash,那麼數據強一致性和資源相互隔離怎麼解決呢?

一般來說,對於一個分佈式存儲系統,數據強一致性和資源相互隔離經常是一個二選一的選擇題,選擇數據強一致性,一般是通過同步複製的方式(比如同步雙寫等)將數據複製到多個相關的實例上,那麼將導致所有的計算與存儲資源都會緊耦合在一個系統中,一個局部的小問題可能會導致其他的部分受到影響,牽一發而動全身;而選擇資源相互隔離,一般是通過異步複製的方式(比如主從同步等)將數據複製到其他的相關實例上來實現的,這樣可以確保資源的相互隔離,但是數據強一致性得不到保證。

對於這個問題, TiDB 論文給出的解決方案是:擴展Raft 算法,增加Learner 角色。

追隨者或學習者

TiKV 將每一段連續的數據稱為一個Region(默認96 M),每一個Region 是一個Raft Group,通過Raft 協議從Leader 節點向Follower 節點複製數據,這是一個同步複製的過程(超過半數節點複製完成就算成功複製),如果TiFlash 也採用Follower 的方式來同步數據,那麼TiKV 和TiFlash 之間的數據複製可以簡單理解為同步複製(其實嚴格來說算是介於同步和異步之間的複制,因為如果TiFlash的Follower 同步慢或者掛掉後,相當於增加了一個複制失敗的節點,這樣就降低了多數派節點複製成功的概率,也就降低了TiKV 的可用性)的,這樣兩個存儲引擎之間就會相互影響,無法達到資源隔離的目標。

因此,TiDB 擴展了Raft 算法,增加Learner 角色。 Learner 角色只異步接收Raft Group 的Raft 日誌,它不參與Raft 協議來提交日誌或選舉領導人,這樣,在數據的複製過程中,TiFlash 的Learner 節點對TiKV 的性能開銷非常小。 TiFlash 通過Learner 角色接受到數據後,將行格式元組轉換為列式數據存儲,達到了數據在TiDB 集群中同時行存儲和列存儲的目的。

到這裡,大家可能會發現一個問題,TiFlash 的Learner 角色是異步接受Raft Group 的Raft Log,那麼怎麼保證TiFlash 的數據強一致性呢?

這個問題是在TiFlash 讀數據的時候來解決的。 類似Raft 的Follower Read 的機制,Learner 節點提供快照隔離級別,我們可以通過特定時間戳從TiFlash 讀取數據。 在接收到讀取請求後,Learner 向其Leader 發送一個readindex 請求,Learner 根據收到的readindex 阻塞等待相應的Raft Log 同步成功並且回放到本地存儲後,再根據請求的時間戳過濾出滿足要求的數據。

這樣,TiDB 就將同步的數據複製機制轉變成異步的數據複製機制了,並且保證了數據的強一致性。 在TiFlash 讀數據的時候,TiFlash 的Learner 只需要和TiKV Leader 節點做一次readindex 操作,這是一個非常輕量的操作,所以TiKV 和TiFlash 之間的影響會非常小。 論文中實驗的數據也驗證了這一點,TiDB 中,同時進行AP 和TP 操作,AP 操作對TP 吞吐量的影響最多不到10%,TP 操作對AP 吞吐量的影響最多不到5%。

另外,論文的實驗表明中,TiDB 在從TiKV 到TiFlash 異步數據複製機制導致的數據延遲也非常小:在10 個warehouses 的數據量下,數據複製的延遲大部分在100 ms 以下,最大不超過300 ms;在100 個warehouses 的數據量下,數據複製的延遲大部分在500 ms 以下,最高不超過1500 ms。 並且這個數據的延遲不會影響TiFlash 的一致性級別,只會讓TiFlash 上的請求稍微慢一點,因為接受到讀請求的時候需要去做一次數據同步。

HTAP或(OLTP和OLAP)

到這裡,TiDB 有了兩個存儲引擎:對OLTP 友好的行存TiKV,對OLAP 友好的列存TiFlash,其實這個不關鍵,關鍵的是這個兩個存儲引擎的數據同步是強一致性的,能對外提供一致的快照隔離級別,這對於計算層的查詢優化器來說是一個非常大的優勢,對於一個請求,查詢優化器可以有三種掃描方式選擇:TiKV 的行掃描和索引掃描,TiFlash 的列掃描,並且對於同一個請求,可以針對不同的部分採用不同的掃描方式,這為查詢優化器提供了巨大的優化空間。 從論文的實驗數據也表明,同時使用TiKV 和TiFlash 的AP 請求比單獨只使用任何一個都是更優。

我們再回到文章的開頭,當初由於數據庫由於需要好處理OLTP 和OLAP 工作負載,將數據庫按工作負載分為OLTP 和OLAP 類型數據庫,然後讓使用者再將請求分類成OLTP 和OLAP 類型請求相應類型的數據庫,在這裡卻是另一種解決方式:對於使用者來說只有一個數據庫,數據庫通過對請求進行分析後決定用哪一個或者同時使用兩個存儲引擎,將數據庫和查詢按工作負載進行分類的方式消除,這個一個更高層次的抽象。

人們碰到一個問題,在當前找不到根本的解決方案時,總是先將問題按場景解構,在每一個小場景中一一解決而達到解決問題的目的,這只是一個權宜之計,等待理論或者技術進步後,再從根本上解決問題。 比如在通信技術的發展過程中,先用有線電話解決在固定地點通信的問題,然後用尋呼機移動接受信息,再加有線電話來解決移動通信的問題,最後手機的出現,直接解決了遠距離通信的問題,在這之前通過解構通信場景針對性的解決方案有線電話和尋呼機就慢慢退出歷史舞台了。 對於數據庫來說也是一樣,先分成不同的工作負載一一解決,最後肯定會形成統一來方案來解決的,TiDB 向前走了一大步,我們拭目以待。

單點or 水平擴展

論文中也發現了一個比較有意思的地方,由於在分佈式架構中,任何不能水平擴展的單點問題都是原罪,因為只要有一個不能水平擴展的單點,理論上就有可能成為整個系統的瓶頸,TiDB 作為一個可水平擴展的分佈式數據庫,在架構上是有一個單點依賴的:從PD 獲得時間戳。 在論文中,通過嚴格的性能測試證明這個地方不會成為整個系統的瓶頸,感受到TiDB 滿滿的求生欲了。

完全的去中心化or 統一的中心化調度

目前的分佈式存儲系統,國外出現了很多完全的去中心化架構設計,比如Cassandra 和CockroachDB,但是TiDB 的架構設計不是完全去中心化的,它有一個中心大腦角色PD,正好和東西方的意識形態對應上了,小政府與大政府的方案,這也是一個比較有意思的地方。

Vitalik Buterin 指出選擇完全去中心化設計的主要原因:fault tolerance、attack resistance、collusion resistance。 由於數據庫都是部署在內部可信賴的網絡,所以attack resistance、collusion resistance 都不會是問題,這和比特幣等數字貨幣為了確保不能被某一些人或者組織控制,出於社會和政治方面的原因採用去中心化架構是不一樣的,並且fault tolerance 在中心化的架構也是可以解決的。

另外,更重要的是對於TiDB 等NewSQL 或者HTAP 數據庫本身就是為海量數據設計的,數據庫集群管理的節點和數據量會越來越大,特別是與雲原始的彈性能力結合後,數據庫的智能調度能力將是決定數據庫性能和穩定性的關鍵因素,但是去中心化的架構會讓調度決策變得困難,特別是需要全局視角和多節點協同的調度決策會更加困難。

所以,只要中心化角色不是系統瓶頸,那麼中心化的調度是有其天然的優勢的,畢竟對於調度來說,最重要的是全局視角和多節點協調能力。 TiDB 對於其中心化的大腦角色PD 定位是非常輕量,沒有持久化調度相關狀態的信息,所以不會是影響整個系統的水平擴展能力。

現在or 未來

從TiDB 的內部來看,我們可以看到TiDB 是徹底的存儲計算分離架構,目前計算層有兩個引擎:SQL Engine 和TiSpark,存儲層也有兩個引擎:TiKV 和TiFlash, 未來,不論是計算層還是存儲層都能很方便的擴展到新的生態中,所以TiDB 的目標感覺不僅僅只是一個數據庫,同時也是在打造一個分佈式存儲的生態。

從單集群TiDB 的角度來看,數據強一致性但資源相互隔離的HTAP 是一個非常高效的能力,省去了數據從OLTP 數據庫同步到OLAP 數據庫的過程,也省去了將OLAP 數據庫計算結果需要提供在線業務使用時,再將數據同步到OLTP 數據庫的過程,這樣,工程師都開開心心的搬磚和寫SQL,而不是頻繁的搬數據。 比起搬磚來說,搬數據像運水,更容易出現灑水、滲水等問題。

從多集群TiDB 的角度來看,雖然TiDB 提供了HTAP 數據庫水平擴容的能力,但是沒有提供租戶隔離能力,導致出於業務隔離、數據級別隔離和運維保障(比如備份和恢復)等方面的原因,所以從目前來看,不可能將整個公司的所有數據都放入一個TiDB 集群中,那麼雖然TiDB 提供了OLAP 能力,但是如果需要做AP 操作的數據分佈在多個集群中,這樣依然需要將多個集群的數據從外部同步到一個提供OLAP 能力的數據庫中(可以是TiDB),導致前面TiDB 通過HTAP 解決的問題又再一次出現。 感覺一個可行的思路是在TiDB 集群之上增加一個類似Google F1 層,這樣在一個統一的F1 層下,可以有很多個TiDB 集群,每個TiDB 集群之間是徹底隔離的,每一個TiDB 集群相當於一個租戶,F1 層提供元數據的管理、讀寫請求的路由能力和跨TiDB 集群的AP 能力;另一個思路是在TiDB 內部來解決,在存儲層增加租戶的概念,每個租戶對應一組存儲節點,這樣租戶之間存儲層是隔離的,計算層可以做跨租戶的AP 操作。 總的來說,這是一個存儲層希望資源隔離,但是計算層希望統一視角的問題,期待TiDB 後續的解決方案。

最後

最後,我們聊聊這篇論文的價值,一般來說工程論文的價值和學術論文是不一樣的,工程論文的貢獻,很多時候不是思想、理論等方面有特別大的創新,而是告訴大家,這個方向是可以行的,通過確定性的工程實現來減少了很多不確定的探索。 比如Google 的GFS、MapReduce、Bigtable 相關的論文,在學術上創新是不大的,幾乎所有的思想和理論都是已經存在的,但是它告訴大家,將其分佈式實現是可行的,這個意義就非常大了,極大地推進了分佈式存儲系統的普及與發展。

所以,TiDB 的論文作為業界第一篇Real-time HTAP 分佈式數據庫工業實現的論文,希望能加速Real-time HTAP 分佈式數據庫的普及與發展,從這個層面來說,這個意義是非常大的。

作者介紹

陳現麟,伴魚技術中台負責人,從0 到1 搭建伴魚技術中台,對分佈式架構、服務治理、穩定性建設、高並發高QPS 系統和中台化的組織架構搭建有一定的經驗,崇尚簡單優雅的設計,關注云原生和分佈式數據庫。

本文轉載自公眾號PingCAP(ID:pingcap2015)。

原文鏈接

讀TiDB 論文有感| 數據強一致性且資源隔離的HTAP 數據庫