概述
X-Engine是阿裡自研的資料庫存儲引擎,以插件的方式接入到MySQL生态,支援行鎖,事務,MVCC等OLTP場景的核心功能。X-Engine的核心優勢是低成本,高成本效益,尤其适用于曆史庫場景,目前阿裡巴巴内部的核心交易曆史庫(原來是Hbase),釘釘消息曆史庫(原來是MySQL(InnoDB)),淘寶商家的圖檔空間等業務均通過X-Engine解決了成本問題。同時,X-Engine也賦能阿裡雲資料庫服務,作為雲上RDS-MySQL的存儲引擎,對外售賣,讓更多的使用者享受到新技術帶來的紅利,有關X-Engine的詳細介紹,請移步
2019年10月的資料庫核心月報。本文主要介紹X-Engine引擎的一個核心功能,OnlineDDL。
OnlineDDL毫無疑問是MySQL生态的一個重要的功能,想當初MySQL 5.6以前,DBA執行DDL變更時,為了保證7*24小時服務,隻能采用最老土的主備切換的方式來進行。資料庫存儲引擎差別于NoSQL引擎的一種重要名額就是是否支援SQL,是否有schema(資料字典)。有了schema,還需靈活地支援線上變更,這樣才能從容應對業務快速變化的需求。MySQL生态中這麼多存儲引擎隻有InnoDB完整地支援了OnlineDDL,X-Engine作為MySQL生态的新成員,雖然采用了完全不同于InnoDB的存儲架構,但OnlineDDL給使用者的體驗是一樣的 。
整體流程
X-Engine采用類LSM的分層架構,資料按照時序邏輯分成多層,每一層資料有序,新資料在較高的層次,最老的曆史資料在最底層。對于X-Engine來說,每個主表和二級索引資料都是一棵分層的LSM-tree結構,内部稱之為Subtable。每個Subtable分為4層,Memtable,L0,L1和L2,每一層都保持有序,資料按新舊順序依次往更深的層次遷移,其中Memtable在記憶體中,其它幾層按需可以在不同的存儲媒體上。OnlineDDL功能實作充分利用了X-Engine的資料組織特點,将新build資料分為兩部分,基線資料和增量資料。基線資料是指變更開始時,通過拿snapshot能周遊得到的資料;增量資料是指,變更開始後,使用者寫入的新資料。拿Snapshot過程需要短時間禁寫,因為我們強依賴這個一緻性位點,確定基線+增量資料的完整性。
OnlineDDL總共包括了4個階段,包括Prepare階段,Inplace-build階段,Commit階段和Post-ddl階段。
1. Prepare階段,這個階段主要是準備資料字典,建構底層存儲資料的Subtable,為後續的增量寫入做準備。
2. Inplace-build階段,這個階段OnlineDDL的核心階段,一方面通過Snapshot擷取基線,另一方面還需要實時維護增量資料,利用X-Engine的資料組織的append-only特性,将基線和增量合并,即完成了OnlineDDL新資料建構的過程。這個過程的詳細邏輯會在下一個小節詳細介紹。
3. Commit階段,這個階段是OnlineDDL引擎層變更生效階段,如果整個OnlineDDL過程中沒有出現異常或錯誤,那麼Commit階段會生效新的資料字典,生效新的資料。
4. Post-ddl階段,這個階段是OnlineDDL真正生效階段,這個階段完成後,才會傳回給使用者DDL成功。這個階段的引入,主要是因為MySQL通過Server層+引擎層這樣的一個二層結構實作擴充,而每一層都有自己的資料字典,在Commit階段隻能保證引擎層的資料和資料字典是完整的,為了保證DDL變更的原子性(Server層和引擎層資料字典保持一緻),引入Post-ddl階段做清理和善後工作,有關DDL原子性的讨論會在下面的章節詳細介紹。
核心邏輯
OnlineDDL的核心邏輯在于如何做到執行DDL變更時,不堵塞使用者對該表的DML和SELECT操作。X-Engine實作OnlineDDL有兩個關鍵點,第1,利用X-Engine的資料組織append-only特點,增量維護在Memtable,L0,L1中,而基線資料維護在L2中;第2,維護增量時,采用雙寫,同時維護old-table和new-table中的資料。與InnoDB引擎類似,根據DDL是否涉及到資料記錄格式變更,将DDL變更分為Inplace-rebuild和Inplace-norebuild兩種類型。對于X-Engine來說,兩者本質是一樣的,差別在于維護的索引個數。Inplace-rebuild類型的DDL需要同時維護new-table中所有索引;而Inplace-norebuild類型的DDL隻需要維護new-table的新增的索引。

整個Inplace-Build按照時間序有3個關鍵節點,t0時刻是擷取快照的時間點,t1時刻是build基線完成的時間點,t2時刻是唯一限制檢查完成的時間點。那麼兩個階段的主要邏輯如下:
t0-->t1主要工作是在build新表的基線,通過将old-table的資料結合new-table的資料字典生成新的記錄,最終寫入新表對應的L2層;在build新表基線的過程中,産生的增量寫入到新表的(Mem,L0,L1)。DDL過程中,需要對背景的Compaction任務做一定的控制,確定不執行合并到L2的Compaction任務。
t1-->t2是唯一性校驗階段,確定新增的主鍵或者唯一索引的唯一性,t2時刻将(Mem,L0,L1,L2)中的資料合并,最終得到new-table的全量資料。
記錄轉換的過程如下:
其中,DDL事務表示DDL線程,它的任務是掃描基線,生成新表的基線資料;DML事務表示DDL過程中,并發的DML事務,它們的任務是,通過雙寫機制同時維護新表和老表的增量。
對比InnoDB實作邏輯
雖然X-Engine與InnoDB的OnlineDDL都是采用基線+增量的方式實作,但具體邏輯是不同的,主要是因為InnoDB采用的的是原地更新操作并且通過row-log機制來維護增量,而X-Engine是一個append-only的存儲引擎,天然地支援資料的多版本存儲,可以實時維護增量資料,在基線建立完成後隻需要将基線與增量資料合并,即使基線中的資料在增量中被修改,但增量中資料的版本比基線資料版本更新,進而在合并時會覆寫基線中老版本的資料。下圖是InnoDB引擎OnlineDDL過程。
可以看到InnoDB引擎的OnlineDDL也包括3個關鍵時間點,與X-Engine引擎的差別在于,t1-->t2 是InnoDB追row-log過程,而對應X-Engine是唯一限制檢查的過程。當然對于X-Engine來說,t1-->t2不是必需的,因為DDL變更可能并不涉及唯一索引操作。
Instant-DDL
與MySQL8.0(InnoDB)類似,X-Engine同樣也支援Instant-DDL。在所有支援的OnlineDDL中,若DDL操作隻涉及修改表的屬性資訊,或隻是做了加列操作,不需要修改記錄格式,也不需要新增索引,那麼這些OnlineDDL操作可以優化成Instant-DDL。這些DDL操作可以“極速”完成,使用者基本無感覺。
由于Instant-DDL執行時,并沒有真正涉及引擎資料的修改,為了後續查詢結果和DDL操作的正确性,需要對于引擎的記錄格式做一定的調整,加一些控制元資訊。新增一個1位元組來标示生成這個記錄時,表是否執行過instant-ddl。同時,生成記錄時,還需要記錄有多少個列是已有的,以及有多少個null列等;在讀取解析記錄時,根據字典資訊,就能知道有多少個列是需要根據instant列資訊來補充,確定instant-DDL後,傳回查詢結果的正确性。
DDL原子性保證
從OnlineDDL的整體流程中我們了解到,OnlineDDL最後一個階段是Post-ddl階段。MySQL8.0以前,Server層的中繼資料都是通過檔案來存儲,比如frm檔案,par檔案以及trg檔案等。一個DDL操作修改,涉及到檔案修改,引擎資料修改以及引擎字典的修改,這些操作無法做成一個事務,必然導緻整個DDL操作無法做到原子性。若DDL過程中出現異常,就可能會導緻Server層和引擎層資料不一緻,以及殘餘的垃圾沒有清理等問題。MySQL8.0将Server層的所有字典資訊統一存儲在DD(DataDictionary)中,并且通過InnoDB引擎存儲,那麼DDL過程中,我們隻要保證Server層資料字典的修改,以及引擎層資料字典的修改封裝成一個事務即可。
對于InnoDB引擎而言,DD資料字典操作,InnoDB引擎資料字典操作都是通過InnoDB引擎存儲,通過InnoDB事務特征來保證原子性。對于X-Engine引擎而言,DD資料字典操作,X-Engine引擎資料字典操作分别采用InnoDB引擎和X-Engine引擎,除了依賴于InnoDB和X-Engine自身是事務引擎特征,還需要借助于内部的2PC協定來保證整個事務的原子性。如果MySQL開啟了binlog,那麼就是binlog,X-Engine,InnoDB三者一起通過2PC協定保證事務的原子性。而Post-ddl階段就是做善後和清理工作,如果最終整個事務送出,Post-ddl階段負責真正清理old-table資料;如果最終整個事務復原,那麼Post-ddl階段負責清理臨時産生的new-table資料,確定DDL變更前後,資料庫的狀态是一緻的。
使用體驗
X-Engine作為MySQL的一個新引擎,在文法使用層面完全與MySQL(InnoDB)相同,通過algorithm_option指定Online類型,通過lock_option指定DDL過程中,是否允許其它并發的DML和SELECT操作。通常情況下,這兩個選項都不用特别指定,采用預設值即可,MySQL内部會優先選擇Instant類型和Inplace類型,對于不支援Online的DDL操作,選擇Copy類型。在功能層面也與MySQL(InnoDB)相同,目前X-Engine暫時還不支援全文索引,虛拟列,外鍵等功能,是以與這些功能相關的DDL操作會不支援,其它DDL操作與MySQL(InnoDB)相同。常用的DDL操作分類如下:
後續工作
X-Engine作為一個新的資料庫存儲引擎,通過集團業務場景的打磨,已經展現了它的價值,我們希望通過雲上RDS場景,讓更多使用者享受到新技術帶來的紅利。當然,目前X-Engine還有一些不足,尤其是相對于傳統成熟的MySQL(InnoDB)和Oracle,是以X-Engine引擎在優化自身的穩定性和性能同時,會持續不斷地豐富資料庫功能,包括支援外鍵,全文索引,虛拟列等。除了公有雲的RDS輸出,基于X-Engine的一體化分布式資料庫PolarDB-X也是一個重要方向,我們會以專有雲形式輸出,服務更多對分布式資料庫有強需求的使用者。