導讀
與傳統關系型數據庫相比,分布式數據庫系統具有多集群、多節點、高并發等特性,這就需要分布式數據庫的 SQL 引擎能夠在滿足用戶常規的 SQL 請求以外,提供多集群、多節點協同計算的能力,從而提高查詢效率。本文将介紹分布式數據庫 ZNBase 的 SQL 引擎架構特點,以及其中各大服務組件的技術原理與工作流程。
分布式數據庫架構
目前業界最流行的分布式數據庫主要分為兩種架構。一種是以 Google Spanner 為代表的 Shared nothing 架構,另一種是以 AWS Auraro 為代表的計算/存儲分離架構。
Spanner 是 shared nothing 的架構,内部維護了自動分片、分布式事務、彈性擴展能力,數據存儲還是需要 sharding,plan 計算也需要涉及多台機器,也就涉及了分布式計算和分布式事務。
Auraro 主要思想是計算和存儲分離架構,使用共享存儲技術,這樣就提高了容災和總容量的擴展。但是在協議層,隻要是不涉及到存儲的部分,本質還是單機實例的 SQL 引擎,不涉及分布式存儲和分布式計算,這樣就和傳統數據庫兼容性非常高。
浪潮雲溪 NewSQL 數據庫 ZNBase 完美地繼承了 Spanner 的設計理念,實現了基于對等架構的分布式 SQL 引擎。
ZNBase 的 SQL 引擎
ZNBase 的 SQL 引擎在傳統的 SQL 引擎基礎上,引入了分布式的概念,通過多個集群節點協同計算更高效的執行用戶 SQL 查詢,總體架構圖如下:
SQL 引擎靜态結構,包含五大服務
集群中每個節點 node 都獨有連接服務(Connectivity Service)、編譯服務(Compile Service) 和緩存服務(Cache Service)三大服務,可以完成用戶的 SQL 查詢執行的前端準備工作。
同時,所有節點又共同組成了分布式的目錄服務(Distibuted Catalog Service)和分布式的執行服務(Distibuted Execute Service),通過這兩個服務完成了多個 node 節點的協同執行,提高了分布式 SQL 引擎的執行性能。最終将結構化數據,轉化為底層存儲可識别的 KV 編碼對,通過 Batch 批處理發送到事務層進行處理。
SQL 引擎執行流程
下文将對這五大服務進行展開介紹。
1.連接服務 Connectivity Service
分布式數據庫 ZNBase 采用的是對等架構,集群中的任意節點都可以作為接入節點。同時,ZNBase 支持 PostgreSQL 協議,SQL 查詢可以通過各種支持 PostgreSQL 協議的驅動發送到集群。
連接服務流程如下:
用戶通過後台守護進程進行連接器管理,為每個客戶端構建新的 Executor。
當用戶從客戶端發起指令後,從客戶端接收和解包流。
執行完畢後,将操作結果打包返回給客戶端。
用戶的每一次操作,都被認為是一個單獨的事務操作。
2.分布式目錄服務 Dist Catalog Service
ZNBase 的 Dist Catalog Service 不僅實現了傳統關系數據庫的 schema metadata,包含了常用的庫、表、列、模式等數據庫元數據,而且實現了元數據信息的高可用,以及分布式訪問。元數據采用多副本存儲、分布式存儲,保證少于一半數據不可用的情況下,元數據信息仍然可用。而且每個對等節點在啟動時會直接内存化元數據路由表的第一級 Root Meta Range 數據,保證任意節點都能訪問到需要的元數據信息。
Catalog 信息發生變化時,首先會更新到元數據存儲的寫入節點,通過 Raft 協議同步到多副本。同時使得各個節點的 Catalog 緩存失效,在使用時進行異步的更新,保證各節點數據的一緻性。
3.編譯服務 Compile Service
ZNBase 的編譯服務包括了 SQL 前端和 SQL 中端功能,SQL 前端實現了傳統數據庫的 Scanner、Parser、SQL 語法、SQL 語義以及數據庫對象和權限校驗的處理,生成了 AST(抽象語法樹)。
SQL 中端實現了數據庫的優化器的功能。優化器負責給執行引擎提供輸入,它接收來自 SQL 前端解析好的 AST 樹,然後需要從所有可能的計劃中選擇代價最優的計劃提供給執行引擎。
ZNBase 的優化器是基于 Cascades 論文實現的搜索框架。從數據庫的發展曆程來看,基于 Cascades 的搜索框架已經成為了業界标準,包括商業數據庫 SQL Server 以及開源數據庫 GP/ORCA 都采用 Cascades 實現。編譯服務的整體架構如下:
SQL 引擎編譯服務結構圖
如上圖所示,Client 端輸入的 SQL 語句通過 go-yacc 層的詞法、語法、語意義解析為 AST 語法樹,經過 Memo construction 轉換為 CBO 初始的 Memo 樹。Memo 由一些列等價的 group 組成,每個 group 表示一個邏輯等價表達式集合,Memo 本身是樹狀結構化的,可以代表查詢語句,但是又不包含大量的元數據信息,可以被緩存以提高執行效率,這點在 Cache Service 中會給出解析。構造好的 Memo 直接應用于基本的 RBO 轉換。之後,Memo 數據根據統計信息經過 CBO 優化(等價發掘和最優化Cost)選擇轉換為最優路徑的計劃。
RBO 根據指定的優先順序規則,對指定的表進行執行計劃的選擇。比如在規則中:索引的優先級大于全表掃描。
當某些 SQL 語句的寫法并不利于快速從存儲中查詢數據的場景下,RBO 會對其進行相應轉化,例:
SELECT*FROMt1,t2WHEREt1.a>4ANDt2.b>5;
如果先進行笛卡爾積再進行過濾條件時,則會産生很多不必要的元組。但是如果先過濾 t1 , t2 的關系,在進行笛卡爾積,那麼表達式的消耗将大大減少。在進行過濾時,能做到一個select算子中就做到算子中,不能的話,就在具有過濾需要的列時及時做好,比如 a.a > 5 and b.b > 10 and a.c > a.b,第一個和第二個條件都可以推到 select 算子中,在這兩個算子上面立即加一個 a.c > a.b 的過濾條件。
CBO 則基于統計信息對代價進行代價預估,得到一條較優的查詢路徑。例如:我們在做三個表連接的時候,如果有統計信息的話,我們就可以知道,哪兩個表先做連接會使接下來執行的代價更小,因為在做 hashjoin 時,我們總希望小的表先進入,然後制作成一個小的 hashtable,因為 hashtable 比較小,所以之後的大表在做 join 的時候,就會有更高的命中率。
4.緩存服務 Cache Service
ZNBase 提供了兩種類型的緩存服務,主要是用來提高數據訪問效率,減少重複消耗。
第一種是 Session 級的 Querycache,主要是緩存用戶 SQL 語句指紋對應的 Memo 樹數據結構,減少同一 Session 的 SQL 語句多次構建邏輯計劃的開銷。SQL 語句指紋含有 SQL 語句的相關 Catalog 信息和權限等校驗信息。
在重用 Memo 之前,會對 Memo 是否過期進行檢查:解析元數據所依賴的每個數據源和 schema,以便檢查完全限定的對象名是否仍解析為相同對象的相同版本,檢查和時間相關的類型的構造和比較方式,以及用戶是否仍有足夠的權限訪問這些對象。如果依賴項不再是最新的,則判定該 Memo 過期,需要重新構建。
第二種是集群級别的元數據相關 Cache。其中 Catalog 信息包含了數據庫常用的 scheme 信息和元數據路由信息。元數據路由信息由 Dist Catalog service 提供。通過元數據路由信息集群任意節點可以訪問到所有需要的元數據或者數據。
5.分布式執行服務 Dist Execution Service
ZNBase 的 SQL 引擎整體設計模型參考了 Volcano 模型[1],Volcano 模型的提出者是 Goetz Graefe,其 1994 年發表此文,并于 2017 年獲得 Edgar F. Codd(關系模型奠基人)創新獎。
ZNBase 的分布式執行提出了一些與 Map-Reduce 類似,但與 Map-Reduce 的執行模型又完全不同的概念。
ZNBase 的邏輯計劃由優化後的 Memo 自底而上構建出一個 Plan node 樹狀結構,為後續構建物理計劃添加一些額外的表信息,列信息等。
分布式執行的關鍵思想是如何從邏輯執行計劃到物理執行計劃,這裡主要涉及兩方面的處理,一個是計算的分布式處理,一個是數據的分布式處理。
一旦生成了物理計劃,系統就需要将其拆分并分布到各個 node 之間進行運行。每個 node 負責本地調度數據處理器 data processors 和輸入同步器 synchronizers。node還需要能夠彼此通信以将輸出 output Router 連接到 input synchronizer。特别是,需要一個 streaming interface 來連接這些組件。為了避免額外的同步成本,需要足夠靈活的執行環境以滿足上面的所有這些操作,以便不同的 node 除了執行計劃初始的調度之外,可以相對獨立的啟動相應的數據處理工作,而不會受到 gateway 節點的其他編排影響。
ZNBase 的集群中的 Gateway node 創建一個 Scheduler 調度器,它接受一組 flow,設置輸入和輸出相關的信息,創建本地 processor 并開始執行。在 node 對輸入和輸出數據進行處理的時候,我們需要對 flow 進行一些控制,通過這種控制,我們可以拒絕 request 中的某些請求。
執行 Flow 示意圖
每個 Flow 表示整個物理計劃中跨節點執行的一個完整片段,由 processors 和 streams 組成,可以完成該片段的數據拉取、數據計算處理和最終得數據輸出。如下圖所示:
計劃執行示意圖
對于跨節點的執行,Gateway node 首先會序列化對應的 FlowSpec 為 SetupFlowRequest,并通過 grpc 發送到遠端 node,遠端 node 接收後,會先還原 flow,并創建其包含的 processor 和交互使用的 stream(TCP 通道),完成執行框架的搭建,之後開始由網關節點發起驅動的多節點計算。Flow 之間通過 box 緩存池進行異步調度,實現整個分布式框架的并行執行。
對于本地執行,就是并行執行,每個 processor,synchronizer 和 router 都可以作為 goroutine 運行,它們之間由 channel 互聯。這些 channel 可以緩沖信道以使生産者和消費者同步。
為實現分布式并發執行,ZNBase 在執行時引入了 Router 的概念,對于 JOIN 和AGGREGATOR 等複雜算子根據數據分布特征,實現了三種數據再分布方式,mirror_router、hash_router 和 range_router,通過數據再分布實現 processor 算子内部拆分為兩階段執行,第一階段在數據所在節點做部分數據的處理,處理後結果,根據算子類型會進行再分布後,第二階段彙集處理,從而實現了單個算子多節點協作執行。
小結
本文介紹了基于谷歌 Spanner 論文設計的分布式 NewSQL 數據庫 ZNBase 的 SQL 引擎架構,并詳細介紹了每個節點中的連接服務、編譯服務、緩存服務,以及系統中的分布式目錄服務、分布式執行服務五大服務組件的技術原理與工作流程。下期文章我們将介紹在原有 SQL 引擎架構的基礎上,ZNBase 團隊針對編譯服務、分布式執行服務等組件進行的一系列優化改進工作。
更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!