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能夠編寫具備不少高級功能的程序,可以把業務邏輯封裝在數據庫內部,提供更好的抽象和安全性,同時減小了網絡的交互,而且調用更快,從而提高總體性能。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解析系列文章

相關文章
相關標籤/搜索