從架構上看 OB 與 TIDB 擅長的業務領域

這兩年分佈式數據庫比較火,金融行業客戶上數據庫產品的時候,大多數都選擇了分佈式數據庫。實際上並不是說集中式數據庫不能承擔金融的核心業務,因爲對於大多數銀行業務來說,目前的集中式數據庫完全是能夠承擔其負載的,實際上郵儲銀行等銀行業選擇了 openGauss 作爲核心系統的數據庫。很多銀行選擇分佈式數據庫,最主要的還是考慮了高可用的問題。因此目前很多國產集中式數據庫也在準備推出類似 ORACLE RAC 的組件,從而補上集中式數據庫在關鍵業務運行環境中的一個短板。

實際上集中式數據庫與分佈式數據庫在不同場景上是各有勝場的。在我們以前進行的一項測試中,對於一些核心業務表,如果設計了多個二級索引。對於集中式數據庫,二級索引對於數據併發寫入和修改的影響並不大,而對於分佈式數據庫,影響就很大了。這主要是因爲分佈式數據庫的全局索引維護成本因爲多節點與網絡延時的存在而被放大了。因此一些交易在分佈式數據庫上的延時要略高於在集中式數據庫上。分佈式數據庫因爲可以橫向擴展,能夠承受更高併發的交易量,並不能降低單個交易的延時。今年年初的時候,有一家商業銀行曾經和我討論過,他們想拆掉 RAC, 改爲 HA 架構,從而降低核心交易延時中 GES/GCS 帶來的負面影響。和分佈式數據庫一樣,RAC 可以提高總的交易併發量,而當系統沒有瓶頸的時候,並不能提高單個交易的性能。

對於分佈式數據庫也是如此,不同架構的優缺點十分明顯,某些分佈式數據庫存在某方面的缺陷是因爲架構問題,是較難解決的,因此瞭解某個分佈式數據庫屬於哪種架構,有哪些優點和缺點十分重要。讓你的應用特點與分佈式數據庫架構的優點相吻合,纔是你的最佳選擇。今天我們用當前最熱門的國產分佈式數據庫 TiDB 和 OceanBase 來做一個分析,因爲這兩種代碼自主率都比較高的分佈式關係型數據庫正好分別採用了兩種不同的架構。

分佈式數據計算最主要有兩種形式,一種是分區 SHARDING,一種是全局一致性 HASH,根據這種分佈式數據計算的種類不同,衍生出存算分離和存算一體這兩種分佈式數據庫架構。進一步再分出一系列子類別,比如對等模式,代理模式,外掛模式等。

存算一體 SHARDING 模式的分佈式數據庫最爲典型的是 Oceanbase。下面是 OB 的架構圖:

每個 Observer 是一個計算存儲一體化的獨立服務,帶有 SQL 引擎,事務引擎和存儲引擎,並存儲一部分分片數據(分區)。OB 採用的是對等模式,客戶端連接到任何一個 OBSERVER 都可以全功能使用數據庫。OBSERVER 會自動產生分佈式執行計劃,並將算子分發到其他參與協同計算的 OBSERVER 上,完成分佈式計算。管理整個集羣的 RootService 只在部分 Observer 中存在,並全局只有一個是主的,其他都是備的。實際上每個 OBSERVER 就組成了一個完整的數據庫子集,如果所有的數據都存儲於一個 OBSERVER 上,我們的訪問方式類似於一個集中式數據庫。

這種架構下的數據分區採用了高可用,一個數據寫入主副本(Leader)後會自動同步到 N 個備副本,OB 採用 Paxos 分區選舉算法來實現高可用。其備副本可以用於只讀或者弱一致性讀(當副本數據存在延遲時),從而更爲充分的利用多副本的資源。實際上不同的分佈數據庫的主備副本的使用方式存在較大的差異,有些分佈式數據庫的備副本平時是不能提供讀寫的,只能用於高可用。

大家看到這裏,可能覺得 OB 的架構不錯,各種問題都考慮的比較周到了。不過還是那句話,沒有完美的分佈式數據庫架構,SHARDING 存儲需要分佈在各個 SHARDING 分區中的分區表要有一個 SHARDING KEY, 根據 SHARDING KEY 來做分片處理。SHARDING 模式雖然應對一般的數據庫操作是沒問題了,不過如果一條複雜的查詢語句中沒有關於 SHARDING KEY 的過濾條件,那麼就沒辦法根據 SHARDING KEY 去做分區裁剪,必須把這個算子分發到集羣中存儲這張表的分區的所有 OBSERVER 上,這種情況被稱爲 SHARDING 數據庫的讀放大。

另外一方面,在 OB 數據庫中創建一張表的時候需要考慮採用哪種模式,是創建爲分區表還是普通的表,如果創建表的時候不指定是分區表,那麼這張表只會被創建在一個 OBSERVER 中,無法在集羣內多節點橫向擴展。另外如果有多張表要進行 JOIN,如果要 JOIN 的數據分別屬於不同的 OBSERVER 管理,那麼這種 JOIN 是跨網絡的,其性能也會受到一定的影響。爲了解決這個問題,OB 提供了 TABLE GROUP 的功能,可以讓分區屬性類似的分區表或者經常 JOIN 的單表的數據存放在相同的 OBSERVER 中,從而避免上面所說的多表 JOIN 的性能問題。這種模式對於數據庫用戶來說似乎變得麻煩了,不過就像開車一樣,如果要能夠發揮出車輛的最大性能,手動模式可能是最好的。

既然存算一體的 SHARDING 模式有這種缺陷,那麼能不能採用存算分離的方案呢?大家來看 TIDB 的架構:

TIDB 是採用完全的存算分離的,計算引擎 TIDB 和存儲引擎 TIKV 是分離的,因此 TIDB 不存在存算一體的 SHARDING 分佈式數據庫的這種讀放大的問題。似乎 TIDB 要技高一籌,完美的解決了 OB 等 SHARDING 數據庫的問題,不過事實上沒有那麼簡單。

首先是那就是計算節點的本地緩衝問題。因爲大型分佈式計算環境下實施緩衝區融合成本極高,因此每個 TIDB 節點只能有本地緩衝,不能有全局緩衝。因此在 TIDB 的 SQL 引擎上是沒有全局 DB CACHE 的,TIDB 的數據緩衝只能建立在 TIKV 和 TIFLASH 上。SQL 引擎 ->DB CACHE-> 存儲路徑 -> 數據存儲介質這種傳統數據庫的數據讀取模式變成了 SQL 引擎 -> 本地局部緩衝 -> 存儲路徑(網絡)-> 存儲節點緩衝 -> 存儲介質這種模式。這種模式對於一些小型的需要超低延時的 OLTP 業務並不友好。爲了解決這個問題,採用此類架構的數據庫系統,就必須採用更快的存儲介質和低延時的網絡架構,從而解決缺乏全局 DB CACHE 支持的問題。當然這個問題也並不是不能解決的,通過更爲細緻的算子下推,採用類似 ORACLE 的 SMART SCAN 等技術,可以解決大部分問題。

存算分離也是一個雙刃劍,消除大多數 SHARDING 方式存儲數據的弊端也是有代價的。所有的讀寫操作都必須經過網絡,不像 OB 那樣,如果是本地數據讀寫不需要經過網絡。因此每個單一的讀寫操作,TiDB 都必須承受網絡延時的放大。不過 TiDB 的這種延時放大是穩定的,不會像 OB 那樣,同一條 SQL,時快時慢(經過網絡肯定要比讀取本地數據慢一些)。

TiDB 的完全存算分離的架構,很好的解決了 Sharding 架構的讀放大問題,這種架構避免了不必要的讀放大,但是也讓數據讀寫的平均延時因網絡而受到了一定的影響,得失之間也是有所取捨的。TiDB 也在通過計算引擎的優化來減少其負面影響。比如對於不變更的歷史數據,TiDB 也引入了計算節點本地讀緩衝機制來提升性能,同時通過算子儘可能早的向 TiKV 和 TiFlash 下推來利用分佈式數據庫的併發能力來提升性能。

另外很重要的一點是 TiDB 的存算分離架構用增加網絡延時的性能犧牲換來了用戶使用的簡化,我們基本上可以像使用集中式數據庫一樣來使用 TiDB,建表的時候想建分區表就建分區表,想建普通表就建普通表。全局索引,本地索引也和集中式數據庫一樣簡單。這對於一些應用水平不高的用戶來說是十分重要的。因爲大部分分佈式數據庫上的性能問題並不是數據庫本身的問題引起的,而是因爲應用開發商不合理的設計數據結構,以及不合理的表分區與數據分佈引起的。

因爲採用截然不同的架構,OB 和 TiDB 在不同的應用場景下的表現會有所不同。對於一些簡單的小交易爲主的業務來說,因爲 OB 數據庫的 SHARDING 架構,受益於各級緩衝,在這些小交易的延時方面,可能 OB 較爲有優勢。而對於一些經常有大型寫事務的場景,因爲 TiDB 可以從計算節點更加快速的下推算子而比 OB 更有優勢,而 OB 必須將算子分解到各個 OBSERVER 上,交給 OBSERVER 再往下寫數據,其效率肯定是有所損失的。

一些大型的表掃描和多表關聯查詢也是如此,因爲兩種不同的架構,在性能上也會表現的不同。當執行計劃類似的情況下,TiDB 的分佈式執行計劃被分解的粒度更細,並直接下推到 TiKV 和 TiFlash 上,而 OB 需要將算子分別推送給其他 OBSERVER,再由 OBSERVER 下推,在交互上也多了一層。這是架構的差異導致的直接差異,享受好處的同時肯定也需要承受一些缺陷。

實際上對於複雜的查詢,起決定因素的還是 CBO 優化器的水平,作爲兩個國產分佈式數據庫的頭部企業,在這方面大家各有勝場。實際上並不是某一條 SQL 某個數據庫勝過其他競品,就說明這個數據庫的優化器做的比競品好。就像前幾天我在測試一條 OB4 的 SQL 的執行計劃時,發現其已經完成了對一個複雜 HASH JOIN 的自動改寫,因此執行效率遠高於基於 PG 優化器改造的國產數據庫。我的比較僅僅是針對這條 SQL 而已,並不說明 OB 的 SQL 引擎就一定比其他數據庫好。實際上優化器都是在不斷的應用中發現問題,不斷的打補丁打出來的。Oracle 的優化器就是在幾十年的不斷補丁中優化出來的,我們的國產數據庫也必然需要經過這樣的過程。我想只要發現了我上回實驗的那個問題,有實力的國產數據庫廠商很快就能解決那個問題。

正是因爲上面的原因,因此如果你的企業應用十分複雜,數據量十分大。那麼在你從類似 OB/TiDB 這樣不同架構的分佈式數據庫中做選擇的時候,一定要把你比較複雜的 SQL 拿出來做些測試,再來完成你的選擇。因爲對於大多數應用來說,這些分佈式數據庫在架構上的缺陷還是不會造成太大的影響的,而如果某些 SQL 因爲執行計劃無法優化而導致你必須改寫應用就比較麻煩了。

分佈式數據庫與應用的對比實際上是十分複雜的,今天我們僅僅從存算分離的架構上做了一些簡單的分析。實際上還有很多問題沒有涉及,比如說資源管理、多租戶、HTAP 等特性。因爲架構不同,數據庫對不同類型的應用支持是會略有不同的。不過實際上對於大多數應用來說,這些差異並不是不可逾越的鴻溝,並不是某種應用必須選擇某個數據庫產品才能跑起來。數據庫選型只是一次選擇,如何用好一個數據庫產品,是需要長期積累的,不同數據庫廠商的售後支持能力,服務客戶的態度,第三方服務能力可能是數據庫選擇的更重要的考慮因素。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/mHAMWZeg8l2vu6XWkoIXTg