1. 程式人生 > >2.0解析系列 | OceanBase 2.0——第一款支援“儲存過程”的原生分散式資料庫

2.0解析系列 | OceanBase 2.0——第一款支援“儲存過程”的原生分散式資料庫

OB君:本文是 “ OceanBase 2.0 技術解析系列” 的第八篇文章,今天我們來說說2.0版本最標誌性、最不得不提的新特性——儲存過程。在為數不多的原生分散式資料庫中,OceanBase 2.0是第一款支援儲存過程功能的產品。本文將為你深入剖析2.0中儲存過程的功能特性和實現機制。更多精彩歡迎關注OceanBase公眾號持續訂閱本系列內容!

引言

PL/SQL(儲存過程)是一種程式語言,叫做過程化SQL語言(Procedural Language/SQL),從Ada語言發展而來。PL/SQL是關係資料庫對SQL語句的擴充套件,在普通SQL語句的基礎上增加了程式語言的特點,把資料操作和查詢語句組織在PL/SQL的過程化程式碼中,通過邏輯判斷、迴圈等操作實現複雜的功能。

使用PL/SQL可以編寫具有很多高階功能的程式,能夠把業務邏輯封裝在資料庫內部,提供更好的抽象和安全性,同時減少了網路的互動,並且呼叫更快,從而提升整體效能。

目前無論是商業資料庫還是開源產品幾乎都在一定程度上支援類似PL的功能,但是採用的規範標準不盡相同。使用最廣泛的是Oracle的PL/SQL,最早在1989年釋出,語法基於Ada語言。

除此之外還有SQL Server的T-SQL,PostgreSQL的PL/pgSQL等。SQL標準中的SQL/PSM(SQL/Persistent Stored Modules)定義了儲存過程中使用的PL,但是Oracle的PL/SQL已經成為了事實上的規範。MySQL採用的是SQL/PSM標準,但是並非100%相容。OceanBase 2.0當前的PL以相容MySQL為主體,MySQL沒有的功能參照Oracle實現。

MySQL和PostgreSQL的PL都採用解釋執行方式,從實現角度來說,解釋執行比編譯執行更容易實現,也更易於控制。但是理所當然的,解釋執行比編譯執行效能相對較差。

Oracle 9.x之前的PL也是解釋執行(Interpreted Compilation)的,從9.x開始,Oracle提供了編譯執行(Native Compilation),SQL/PL首先被翻譯為C語言程式碼,然後呼叫C編譯器編譯為機器碼,編譯後的程式存在動態連結庫中,執行時執行器直接裝載呼叫動態連結庫中編譯好的函式。

根據Oracle自己的說明,編譯後的程式比解釋執行效能提升1.05到2.4倍。具體提升的程度取決於程式的特性。因為SQL語句本身還是解釋執行的,所以如果PL的主體是程式控制邏輯,那麼提升效果會很明顯,而如果PL的主體是SQL語句,那麼PL的效能提升不會顯著。另外Oracle的PL除錯功能只支援解釋執行方式。

編譯執行是一個趨勢,目前除了PL之外,很多資料庫也紛紛在嘗試把SQL引擎改寫為編譯執行,包括MemSQL、HANA、PostgreSQL等。OceanBase PL採用編譯執行的方式,使用LLVM生成native code,並直接把機器碼裝載到程式段執行,無需依賴外部C編譯器和生成動態連結庫。

無論解釋執行還是編譯執行,當前的商業資料庫都只支援單機,OceanBase在分散式環境下在關係資料庫裡支援了完整的PL/SQL功能,這在業界尚屬首次。

價值和意義

1. 降低RT

PL對於業務最直接的價值就是降低業務的RT。假如某個業務邏輯裡面一條完整的執行鏈路平均有200條SQL,也就是應用需要和資料庫互動200次。在同機房的情況下網路開銷大約需要0.5ms,如果把200次互動省掉,那麼就可以節約100ms的RT。當然,事實上因為業務有自身的邏輯,不可能全部邏輯都可以用PL/SQL來實現,所以這200次互動不可能全部省掉,但是即便省下一半,也會有大約50ms的RT提升。

2. 節省資源

減少網路互動除了減少RT,另一個直接的效果是減少了網路的資料傳輸和網路開銷。假如某個網際網路業務的網路開銷平均是30%,也就是說30%的CPU都花在了網路的收發和解析上。如果說幾十個ms的RT對整個鏈路來說比例不那麼顯著的話,30%的CPU資源節省縮省下的機器可是以億計的真金白銀,而把這些機器資源換算成系統處理能力也將是驚人的。

3. 提高吞吐率

事實上利用PL/SQL帶來的網路開銷的節省只是表面,更深層次的是,因為每個事務的RT縮短,每個事務在資料庫核心所搶佔臨界區的時間縮短,使得系統的CPU利用率獲得大幅提升,整個吞吐量也隨之提高。這種提升不止在資料庫核心存在,對業務的應用邏輯同樣有幫助。CPU利用率的提升所獲得價值同樣也是億級規模的。

4. 提升穩定性和可靠性

當前的網際網路分散式業務多是單元化部署,應用和資料庫部署在同機房,並且在大多數情況下都是機房內訪問,一旦發生故障導致某個資料庫的資料不可訪問,OceanBase會自動切換訪問其他副本,與此同時應用也必須隨之切走,否則同機房的資料庫訪問將變成跨機房甚至跨城訪問,網路開銷也將由原來的每次0.5ms變成2ms,甚至達到7ms~30ms。對於單次來說這不算什麼,但是在幾百條SQL的加成下就可觀了。

巨大的網路延遲會對整個業務系統造成嚴重影響,甚至拖垮整個系統。而利用了PL/SQL之後,這些問題都將不復存在,業務將不再和資料庫強繫結,計算和計算的分離成為可能,整個系統的可靠性獲得提升。

同時,OceanBase的設計對於網路要求相對比較高,叢集內部通訊以及內部流程邏輯也都可以利用PL/SQL實現,這不僅提升能夠內部通訊的效率,同時也使得資料庫核心的核心程式碼充分簡化,減少出錯路徑,提升穩定性。

並且部分業務邏輯改為PL後,業務的程式碼將會減少,業務開發流程也會相對簡化,同時提供更好的抽象和安全性。

實現機制

1. 框架結構

圖1給出了OceanBase PL Engine工作的呼叫關係圖。PL引擎(PL Engine)和SQL引擎(SQL Engine)可以互相互動,SQL可以直接訪問PL引擎,比如在一個SQL語句中使用了使用者自定義函式。PL引擎可以通過SPI介面訪問SQL引擎,比如在PL裡進行表示式計算和執行SQL語句。

                                                                               圖1:PL Engine工作呼叫關係

2. PL Engine

PL Engine由六個模組組成:Parser、Resolver、Code Generator、Compiler、Executor和PL Cache,其中Parser、Resolver、Code Generator和Compiler構成了一個完整的PL編譯流程。如圖2所示。

  • Parser

語法解析器,用於分析PL語法生成語法樹(ParseTree)。PL引擎和SQL引擎各自實現了單獨的Parser,但是兩個Parser儘量不做冗餘的工作。一個查詢串進入Observer首先進入PL Parser解析,如果發現是SQL語句則交由SQL引擎解析。

  • Resolver

Resolver用於進行語義分析,例如檢查變數作用域、靜態SQL中資料物件的Schema等,併為每一條PL語句生成對應的AST結構以及全域性的FunctionAST結構。FunctionAST儲存了PL定義的基本資訊和生成的全域性符號表、全域性標籤表、全域性異常表等資訊。每一條語句的AST裡面則記錄了指向這些全域性表的邏輯資訊。

  • Code Generator

對於解釋執行來說,AST已經足夠。但是對於編譯執行,需要對AST進行進一步的翻譯,這一步是使用LLVM提供的介面,把AST樹翻譯成IR中間碼的過程。IR碼可以輸出,以核對檢驗翻譯過程是否正確。

  • Compiler

通過JIT把IR碼生成機器碼的過程,輸出為PLFunction結構。

  • Executor

PL的執行器,根據編譯出的PLFunction,和輸入引數構造執行環境,呼叫函式指標,得到函式結果。

  • PL Cache

PL Cache存在的目的是為了避免每一次都重新編譯PL,提升PL的執行效率。所以對於匿名塊(Anonymous Block)沒有Cache的必要。

PL Cache是一個hash表,通過Key(Procedure或Function的ID)查詢到Value(PLFunction),並通過訪問Schema檢查PLFunction的有效性,如果失效則趁機刪除。

PL Cache是PL Engine的內部機制,PL Engine對外提供統一的通過ID執行Procedure或Function的介面,外部不必關心PL的快取機制,只需通過PL Engine物件執行PL即可。

                                                                           圖2:PL Engine模組組成

PL Engine根據ID在PL Cache查詢是否有編譯好的PLFunction,如果有則進一步檢查Version是否可用。如果PL Cache中沒有可用的PLFunction,則呼叫編譯流程進行編譯,編譯後的結果快取在PL Cache,並交給Executor執行。

最終編譯出的結果是一段二進位制程式碼的記憶體地址,Executor將這段記憶體地址轉成一個函式指標,並傳入執行引數和執行環境執行得到結果。

3. 編譯執行

編譯執行比解釋執行的優勢毋庸贅言,OceanBase 也是採用把儲存過程編譯為機器碼的方式進行執行,但是和Oracle實現不同的是,OceanBase採用JIT技術,無需依賴外部C編譯器和生成動態連結庫。採用這一技術方案,有如下優點:

  1. 無需研究體系結構相關的複雜的機器碼生成,就可以獲得編譯執行的效果;生成LLVM IR比生成彙編簡單很多,且自然擁有了考慮跨平臺能力;
  2. LLVM提供的成熟的優化模組都是基於LLVM IR的,clang等專案中對優化器的改進都可以直接被我們受益;
  3. 用JIT技術在Observer內直接控制生成編譯後的程式碼,比Oracle採用的在資料庫外部編譯器編譯結合動態連結庫裝載的方式在可控性,效能,可維護性各方面都有優勢;
  4. PL的編譯執行可以和SQL表示式及部分physical operator甚至是整個查詢計劃採用編譯執行相結合,獲取整體效能的提升。

圖3給出了PL 編譯的工作流程。Parser、Resolver和Code Generator三個模組完成了編譯器的前端(Frontend)工作,實現從PL文字到中間碼(LLVM IR)的轉換過程。Compiler模組完成了Pass和後端(Backend)的工作,把中間碼經過Pass流程優化,並生成實際的機器碼。

                                                                              圖3:PL編譯工作流程

這種架構下,對於實現PL/SQL語言來說,大量的工作是實現一個前端,即Parser、Resolver和Code Generator三個模組,而對於Compiler可以呼叫LLVM提供的介面實現。

相容性

各大資料庫支援的PL都各有不同。目前最廣泛使用的Oracle PL/SQL語言最早在1989年釋出,語法基於Ada語言。PostgreSQL的PL/pgSQL,SQL Server的T-SQL等語言都各不相同。SQL標準中的SQL/PSM (SQL/Persistent Stored Modules)定義了儲存過程中使用的PL,但遺憾的是主流資料庫廠商並沒有全心支援。

像PL/pgSQL一樣,MySQL採用了SQL/PSM標準,但是並非100%相容。OceanBase 提供MySQL和Oracle兩種相容模式,PL/SQL也同樣既可以使用Mysql的用法,也可以選擇Oracle相容模式,基於Mysql或者Oracle的PL的程式碼可以一行不改的遷移到OceanBase執行。

分散式

OceanBase天然的分散式特性決定PL的執行也是分散式的,PL的解析、編譯和執行都在某一個Observer上完成,當PL裡涉及到SQL互動時,會通過SPI呼叫SQL Engine,由SQL Engine執行SQL語句,如果該SQL語句是一個分散式的,那麼自然而然會進行分散式執行。

OceanBase選擇儲存過程裡訪問的第一張表的資料所在的節點編譯和執行PL,這是為了儘量使得PL對資料的訪問都是LOCAL的。如果無法確定所訪問資料所在的節點,則隨機選取一個節點。

當分散式執行的SQL呼叫了PL函式時,PL函式可能會在多個Observer上編譯執行,每個Observer上保證在相同的環境引數下進行編譯,從而編譯出的PL具有相同的行為。

除錯

除錯是程式語言的基本需求,所以事實上Mysql這樣不支援除錯的PL/SQL是不具備大規模應用的基礎的。

業界實現PL的除錯功能都只在解釋執行模式支援,Oracle的編譯執行模式不支援除錯。OceanBase只有一種編譯執行模式,支援在編譯模式進行除錯,並且是在分散式的環境下進行除錯。目前支援的除錯功能包括設定斷點(b)、檢視斷點(info b)、檢視變數(p)、檢視堆疊(bt)、單步執行(s)、進入函式(s)、繼續(c)等等,通訊方式採用類似Oracle的方式,建立一個數據庫連線來除錯另一個連線,除錯指令用文字指令,不發明新的通訊協議,並通過包的形式對外提供介面。

分散式除錯是分散式環境下實現PL/SQL的難點,當PL分散式執行時,使用者的除錯執行緒連到其中一個節點,該節點需要再和其他分散式執行節點建立除錯連線並傳輸指令和資料。

Mysql沒有包(Package),OceanBase提供和Oracle完全相容的包機制,使用者在Oracle上建立的包可以一行不改的遷移到OceanBase上建立和執行。

但是Oracle的系統包目前OceanBase還沒有全部支援,這也將成為今後一段時間我們要做的工作之一。在有了PL/SQL的基礎能力支援和Package的機制之後,其餘的系統包可以根據需要快速實現。

總結和展望

從OceanBase誕生的第一天起,團隊的目標就不是想做一個數據庫只給自己用,而是要做一個通用資料庫真的去推動整個社會的進步,能夠讓整個社會的生產力發生變化。

隨著螞蟻金服的開放賦能,OceanBase也開始服務外部客戶,金融行業的很多客戶以前都有很大一部分業務是使用Oracle開發,並且大量使用了PL/SQL,這種現狀在非金融行業中更為普遍,而這也成為了Oracle綁在客戶身上最重要的一條鎖鏈。OceanBase要為客戶提供比Oracle更可靠、更高性價比的服務,PL/SQL是必須邁過去的一道門檻。這道門檻很難邁,而一旦邁過去,就會形成OceanBase的重要優勢。

另一方面,雖然網際網路公司目前的現狀是普遍都不使用PL/SQL進行業務開發,但是難掩其對業務的巨大價值,PL不僅能夠降低RT,提高資源利用率,提升系統吞吐率、穩定性和可靠性,同時也是服務使用者,尤其是傳統行業客戶的重要基礎。在這一方面螞蟻金服走在網際網路行業前列,已經開始在內部嘗試利用PL/SQL的優勢來解決業務的問題。

OceanBase提供了同時相容Mysql和Oracle兩種模式的PL/SQL,並利用LLVM實現其編譯執行的核心引擎,使得PL控制邏輯本身效能能夠達到Oracle相當的水平。而且OceanBase是業界第一個真正意義上支援分散式PL的商業產品,並提供完善和相容的除錯機制。與此同時OceanBase還提供了完備的包機制。

未來除了進一步完善Oracle相容的系統包之外,還需要繼續優化PL/SQL的效能。與此同時,我們也會在更多內部業務中推廣使用PL/SQL,為業務創造巨大的價值,並在提供給外部客戶使用之前做好技術沉澱和產品錘鍊。

加入OceanBase 2.0技術交流群

— 想了解更多OceanBase 2.0新特性?

— 想與螞蟻金服OceanBase的一線技術專家深入交流?

掃描下方二維碼聯絡小編,快速加入OceanBase技術交流群!

2.0解析系列文章