該論文詳細介紹了opengauss記憶體庫的工程實作,原理請參考《Speedy Transactions in Multicore In-Memory Databases》 https://ata.alibaba-inc.com/articles/216581
ABSTRACT
GaussDB和開源版本的openGauss是TP型資料庫,本文展示了其面向main memory和多核的優化,在TaiShan伺服器上TPCC有2.5倍的提升。
1. INTRODUCTION
2012年研發OLAP,2015年釋出,FusionInsight MPPDB,GaussDB200
2017年研發下一代OLTP,為了滿足來自高端使用者的5個需求:
- 基于share-nothing架構的scale-out能力;
- 多核的scale-up能力;
- 大記憶體;
- SQL相容;
- 高可用;
政策是基于GaussDB研發一款記憶體資料庫,可以服用GaussDB的SQL相容和HA能力。
基于PostgreSQL9.2,繼承了MPPDB的線程模型。
本文要讨論GaussDB的記憶體資料庫:Memory-Optimized Tables,下文簡稱為mot。
1.1 System Architecture
GaussDB的整體架構如下圖所示,典型的sharenothing系統:單機DB+2PC和全局事務管理。mot做為單機的存儲引擎,是以可以完整複用已有的SQL,執行器,分布式事務,HA等。
mot的記憶體管理:感覺NUMA的内管管理,2MB chunk
1.2 Internal Architecture
mot底層使用無鎖的masstree,并發控制協定使用Silo,并對進行了工程上的增強。Silo的論文參考《Speedy Transactions in Multicore In-Memory Databases》
mot在使用masstree時key的長度從29位元組增加到了45位元組。
mot并發控制協定的選擇考慮如下因素:
- OCC:Silo和TicToc分3個階段。并發事務無需等待,僅僅在validation階段做檢測,适當的abort;
- Encounter time locking (ETL):樂觀讀,寫者上鎖。是以,并發的寫者能互相感覺并做abort。ETC和相比OCC:一方面能提前檢測沖突,減少無用功;另一方面能加速Read-after-writes;
- Pessimistic concurrency control (2PL):
結論:OCC更加适合多核(參考《Staring into the abyss: An evaluation of concurrency control with one thousand cores》)。mot選擇了Silo的算法,相比于TicToc,Silo算法比較簡潔而且大部分負載情況下性能表現差不多。
mot表大小受限于内容大小,當然可以進一步優化來提升表大小,比如:anti-caching和tiering。
2. ADJUSTING THE ENGINE
2.1 Indexing and Storage
引入類似HOT機制,在更新一個行時不用每次都更新索引樹,而是跟新這一行的sentinels(類似BTree索引中的IndexTuple)。
2.1.1 Optimistic inserts優化
在Silo基礎上,mot完善了基于OCC的insert優化。
2.1.1.1 Motivation.
OCC的3個階段中,insert先在本地操作僅僅在commit時檢測沖突。是以需要優化:
- 并發事務insert相同的key,如何保證唯一性;
- insert的事務最終abort;
- 同一個事務插入相同的key;
- 如何insert多個索引樹;
2.1.1.2 Implementation Details.
Silo處理插入key為K流程:
- 如果K已經對應一個已送出record,本事務abort;
- 否則,生成record為R,狀态為ABSENT,索引樹中插入K->R;
- 如果發現已存在ABSENT的record,則直接複用(先成功插入者為準);
mot對Silo插入流程的改進:
- DoubleRow:同一行插入到在不同索引樹上,導緻部分索引樹沖突;
- Self Inserted:事務需要識别索引樹上哪些ABSENT狀态的record是自己插入的;
2.1.2 Non-unique indexes
在key之後增加字尾:8個位元組的row指針。
2.2 Concurrency Control
read after write hazard:occ實作的事務中,如何讀取本事務剛剛寫入的資料。
mot的優化:實作了一個access-set結構,記錄本事務read,update,insert,deleted集合。
維護每個key的狀态的狀态轉換。送出時從access-set上提取出write-set和insert-set。
和Silo不同的是,mot支援了RC隔離級别:不對read-set做校驗。
read-set:如果高于RC級别,對read-set做沖突檢測;
write-set:對row上鎖;
insert-set:對sentinel上鎖;
3. INTEGRATION WITH GAUSSDB
由于GaussDB是基于早起PostgreSQL做的開發,并沒有storage engine的概念,是以mot是通過FDW機制來實作。同時,也需要對原有FDW做相應的擴充,比如:在create table/index時在本地觸發對mot的DDL操作。
3.1 Tables and Indexes Created and Used
建立FDW函數:ValidateTableDef
fdwroutine->AddForeignUpdateTargets = MOTAddForeignUpdateTargets;
fdwroutine->GetForeignRelSize = MOTGetForeignRelSize;
fdwroutine->GetForeignPaths = MOTGetForeignPaths;
fdwroutine->GetForeignPlan = MOTGetForeignPlan;
fdwroutine->PlanForeignModify = MOTPlanForeignModify;
fdwroutine->ExplainForeignScan = MOTExplainForeignScan;
fdwroutine->BeginForeignScan = MOTBeginForeignScan;
fdwroutine->IterateForeignScan = MOTIterateForeignScan;
fdwroutine->ReScanForeignScan = MOTReScanForeignScan;
fdwroutine->EndForeignScan = MOTEndForeignScan;
fdwroutine->AnalyzeForeignTable = MOTAnalyzeForeignTable;
fdwroutine->AcquireSampleRows = MOTAcquireSampleRowsFunc;
fdwroutine->ValidateTableDef = MOTValidateTableDef;
fdwroutine->PartitionTblProcess = NULL;
fdwroutine->BuildRuntimePredicate = NULL;
fdwroutine->BeginForeignModify = MOTBeginForeignModify;
fdwroutine->ExecForeignInsert = MOTExecForeignInsert;
fdwroutine->ExecForeignUpdate = MOTExecForeignUpdate;
fdwroutine->ExecForeignDelete = MOTExecForeignDelete;
fdwroutine->EndForeignModify = MOTEndForeignModify;
fdwroutine->IsForeignRelUpdatable = MOTIsForeignRelationUpdatable;
fdwroutine->GetFdwType = MOTGetFdwType;
fdwroutine->TruncateForeignTable = MOTTruncateForeignTable;
fdwroutine->VacuumForeignTable = MOTVacuumForeignTable;
fdwroutine->GetForeignRelationMemSize = MOTGetForeignRelationMemSize;
fdwroutine->GetForeignMemSize = MOTGetForeignMemSize;
fdwroutine->GetForeignSessionMemSize = MOTGetForeignSessionMemSize;
fdwroutine->NotifyForeignConfigChange = MOTNotifyForeignConfigChange;
3.1.1 Index Usage for Planning and Execution
優化器中新增GetForeignPaths。
3.2 Integrating MOT with HA
- Logging:複用GaussDB的XLOG來記錄WAL日志,GaussDB并行寫日志,多個并發backend程序插入WAL slot,在commit時接管WAL并flush;
- Checkpointing:提供checkpoint的callback函數;
- Recovery:提供recover的callback函數,并行recover,每個線程負責一個datasegment;
3.3 VACUUM and DROP
3.3.1 Deleting Pools
基于epoch的gc,新配置設定記憶體區域,将live的資料拷貝到新記憶體區域,老的記憶體區域直接回收掉。
3.3.2 GC and Pools Deletion
3.4 JIT for Query Acceleration
GaussDB已經支援了JIT:
- 表達式,比如WHERE子句;
- Inline函數;
上述兩種JIT優化是通用的,但近支援了SQL的部分JIT優化,對加速CPU-bound查詢效果顯著,比如OLAP。
而mot選擇對特定OLTP查詢場景進行優化,一旦進入這種場景就是全JIT優化,面向OLTP常用負載:點查、簡單的範圍查詢。
GaussDB的JIT仍然是火山模型的pull-model,mot對特性查詢的sql進行了全JIT支援,是以一旦命中就不需要使用火山模型。
mot并不支援複雜agg函數,比如:groupby,count distinct
4. EXPERIMENTAL RESULTS
4.1 Hardware
環境1:
Huawei ARM64:
TaiShan
Kunpeng920-4826和6426
1TB記憶體
4TB NVMe 3.5GB/s
– 2-sockets of 48 cores, adding to 96 cores.
– 2-sockets of 64 cores, adding to 128 cores.
– 4-sockets of 64 cores, adding to 256 cores.
環境2:
Intel x86:
2socket,每個socket上18實體核,2個超線程,總共72核
4.2 Benchmark and Configuration
client端和server之間10Gb網絡
所有的測試中,原GaussDB的存儲引擎的資料全部能在記憶體中buffer住,是以測試結果可以忽略IO的影響。
4.3 Results
使用TPCC測試性能和正确性。
結論:ARM單核性能是x86的0.75倍,和主頻成比例,96個ARM核和72個x86核性能相當。
上圖測試擴充性,結論:
- mot随着并發增加吞吐增加,大概250并發達到峰值;
- 而GaussDB原存儲在并發100時達到峰值;
單條query的加速比
建構表且僅有2個整數,其中一個整數做為primary key。
結論:
- insert提升2倍多:原Disk-based的插入需要在page内定位行指針,插入B-Tree也需要定位node,而mot使用masstree;
- lookup提升2倍多:原因同上;
- delete提升1.5到2倍:mot執行了實體删除,而原Disk-based僅僅是标記,後續vacuum負擔會更大;
- update提升3.5倍多:masstree查找更快。
- 所有測試中ARM平台提升比x86更加明顯:ARM的relaxed memory對原Disk-based的2PL并發控制不優化,而MOT OCC在這種優化更明顯;
JIT加速
- stocklevel無提升:包含mot不支援的複雜agg,同時sql中包含pipeline breaker需要物化;
- 其他場景均提升30%;
- 在并發300個連接配接時提升更高,OCC允許reader在本地并發執行,減少cache miss;
存在abort時
OCC中事務執行期間不會被阻塞,但是當有競争時需要abort。
上圖中,12個warehouse,120個并發來模拟高比例的競争場景。
- 随着并發增加,abort比例上升;
- mot整體性能仍然有2倍提升;
Replication對性能的影響
開啟replication時,結論:
- mot有7%損耗;
- Disk-based有20%損耗;
5. RELATED WORK
- Prototypes and Frameworks: DBX提供了對各種并發控制協定算法進行比較的架構:2PL,OCC,Silo。經過測試在華為的機器上Silo性能表現最好;
- Microsoft’s Hekaton: SQL的Hekaton是記憶體引擎,也是在commit是進行alidation,類似Silo。不同點是它使用Bw-tree作為索引,read-lock會阻塞寫,雖然能減少abort,但是也降低了并發度,因為需要原子的對共享記憶體區域進行++來實作原子鎖,雖然都是樂觀,Silo更加樂觀;
- PostgreSQL Storage Engine:也是用FDW來實作記憶體引擎,功能不完善,缺少二級索引,DDL等;
- Mot:相容SQL,工業級記憶體引擎;
6. CONCLUSION
MOT是為衆核和大記憶體設計的記憶體引擎,記憶體管理,并發控制協定,GC都進行了工程上的優化,通過FDW嵌入到GaussDB中,無縫相容SQL引擎,友善使用者使用。