作優化的數據庫工程師請參考!CynosDB的計算層設計優化揭祕

本文由雲+社區發表node

本文做者:孫旭,騰訊數據庫開發工程師,9年數據庫內核開發經驗;熟悉數據庫查詢處理,併發控制,日誌以及存儲系統;熟悉PostgreSQL(Greenplum,PGXC等)、Teradata等數據庫內核實現機制。數據庫

CynosDB 是騰訊數據庫研發團隊推出的自研數據庫,有PostgreSQL和MySQL兩個版本。本文以兼容PostgreSQL版CynosDB爲例,介紹咱們的架構設計和優化思路。數組

一、概述

PostgreSQL是世界上最早進的開源數據庫,始於1986年,有30多年的社區演進歷史。其先進的架構、可靠性以及豐富的功能已經得到業界高度承認。同時,PostgreSQL可以在多種操做系統上運行,支持多種索引類型和擴展,特別是對PostGIS擴展的支持,可讓PostgreSQL輕鬆的處理地理信息數據。性能優化

兼容PostgreSQL版CynosDB做爲PostgreSQL在NewSQL領域的一個產品,也具備良好的擴展性。由其架構特色帶來的資源池化,可讓用戶付出更少的成本而得到同等的性能,而且不損失PostgreSQL數據庫原有的功能特性。網絡

二、基礎架構

現有共有云上的數據庫存在一些不足:架構

1.網絡IO重。傳統雲上的主備架構下,會有大量數據須要寫到磁盤,主要包括:WAL LOG、髒頁數據、防止頁部分寫的Double Write或者Full Page Write。併發

2.主從實例不共享數據。一方面浪費了大量存儲,另外一方面進一步加劇了網絡IO。這樣會致使磁盤利用率低、CPU閒置等問題。異步

而CynosDB能夠經過日誌下沉、共享存儲來解決上述問題,以實現共有云數據庫的高性價比、高可用性以及彈性擴展。其基礎架構以下:分佈式

img

架構中的組件:性能

\1. master是數據庫的主實例,負責接收應用的讀寫事務請求。

\2. slave是數據庫的只讀實例,負責處理應用的讀請求,能夠支持多個slave實例。

\3. CynosStore Client提供訪問分佈式存儲(CynosStore)的接口。DB引擎經過這些接口訪問存儲,完成數據文件的讀寫等操做。

\4. CynosStore是一個分佈式存儲系統,存放數據庫的數據和日誌,並負責日誌到數據頁面的轉換。

\4. 集羣管理服務負責整個系統的管理,例如:存儲擴容,實例建立等。

\5. 冷備存儲用來存儲系統的日誌。

master實例將數據的變動以日誌方式發送到存儲系統(CynosStore)中,同時CynosStore會按期將日誌合併到數據頁面上。所以,CynosDB無需將髒頁寫入到存儲中,這點與傳統數據庫是不一樣的。slave數據庫實例沒有寫事務,不會向存儲發送日誌,可是會從存儲中讀取頁面,也會接收master實例的日誌來刷新內存中的數據頁面;若是收到的日誌所對應的頁面沒有在slave的內存中,則會丟棄這些日誌。

從架構上看,CynosDB實現了存儲和計算分離,並把資源進行池化,所以適合雲上部署。並且計算和存儲傳輸數據的僅有日誌流,無需寫髒頁面,所以也減小了系統中的網絡量。總的來講,CynosDB具備以下優點:

1.計算能力彈性擴展。能夠快速增長slave節點來擴展讀能力,而沒必要進行全量的數據拷貝。

\2. 存儲能力彈性擴展。不像傳統數據庫那樣受單機存儲能力的限制。

\3. 充分利用硬件資源。緩解傳統主備架構中的CPU閒置、磁盤利用率不高等問題。

\4. 備份容易。備份徹底由後臺持續進行,用戶無需干預。

三、兼容PostgreSQL版CynosDB的計算層架構

CynosDB實現了計算與存儲分離,系統也所以被分紅兩大塊:計算層和存儲層。計算層負責SQL解析、日誌生成等;存儲層負責數據存儲、日誌歸檔以及日誌合併等。本節以CynosDB的PostgreSQL兼容版本爲例來介紹計算層架構。其計算層架構以下圖所示。爲了實現這種NewSQL架構,咱們對PostgreSQL內核作了新設計:

img

灰色部分是PostgreSQL內核原生模塊:

\1. SQL:PostgreSQL的SQL引擎,包括詞法/語法分析、語義分析、查詢重寫/優化和查詢執行。CynosDB的設計不涉及SQL層改動,所以它兼容PostgreSQL原來的SQL語法和語義。

\2. Access:數據庫的訪問層,定義了對象的組織方式和訪問方法。其中包括:

lHeap:表實現以及訪問方法,包括掃描、更新、插入、刪除等。

lbtree/gin/gist/spgist/hash/brin:索引實現,包括各類索引的實現和操做方式,如索引掃描、插入等。

lCLOG/MultiXACT:與事務提交狀態以及併發等。

Access是設計和優化的重點模塊。當表和索引等數據庫對象被修改時,原生的PostgreSQL會生成XLog,並寫入到日誌文件中。在CynosDB中,這些對象修改時也會生成日誌,可是這些日誌不會寫本地的日誌文件,而是發送到CynosStore中。

\3. storage/buffer:buffer pool和存儲管理,調用文件接口對數據文件進行讀寫。在CynosDB中使用CynosStore Client對CynosStore中的文件進行操做。

\5. CynosStore Client提供訪問CynosStore的接口,以完成數據庫對數據文件的操做。包括數據頁面讀取接口、日誌發送接口等。

\6. 分佈式存儲CynosStore是一個基於日誌的分佈式的塊存儲,在本文中不作重點介紹。

CynosDB的計算層把數據文件修改所生成的日誌,經過CynosStore Client發送到分佈式存儲CynosStore中,而CynosStore會將日誌定時合併到數據頁面上。這裏比較重要的一點是,計算層寫出日誌並非PostgreSQL原生的XLog,而是咱們本身從新設計的日誌系統和日誌格式。所以CynosDB不依賴於PostgreSQL的原生日誌系統,這種設計也可讓咱們有機會在CynosDB上作更多的性能優化。具體能夠參見下節。

四、架構優化

CynosDB計算層的架構設計遵循了以下思路:

1.「極簡IO」。即,下降網絡/磁盤IO

\2. 高效的系統設計。異步的日誌設計、下降計算層CPU負載

經過這些設計,使CynosDB的性能比雲上的同等配置性能要高。本節主要介紹計算層所作的優化手段。

4.1 日誌系統

兼容PostgreSQL版CynosDB的底層存儲CynosStore是一個支持日誌寫的、能夠提供多版本讀的、分佈式的塊設備,DB引擎對存儲中文件的修改,都是以日誌的方式發送到存儲中。其日誌格式是:<頁面號,頁面偏移,修改內容,修改長度>,含義是:在頁面的哪一個偏移作了什麼內容的修改。這樣設計的日誌是冪等的。

以表插入元組爲例,PostgreSQL原來的XLog日誌格式多是:

<relfilenode, pageno, offsetnum,informask2,infomask,hoff,tuple_data>:表明在頁面(由relfilenode和pageno來肯定一個頁面)的offsetnum位置插入一條元組,插入的元組是在恢復時由informask2, infomask, hoff, tuple_data等信息進行重構。

一樣的操做,在CynosDB中生成的日誌可能以下。假設在頁面號爲n的頁面上插入元組tuple:

<n,10,(char *) &pd_flag,2> -- 保存頁面頭pd_flag到日誌

<n,12,(char *) &pd_lower,2> -- 保存頁面頭pd_lower到日誌

<n,14,(char *) &pd_upper,2> -- 保存頁面頭pd_upper到日誌

<n,36,(char *) &ItemIdData,4> -- 保存ItemIdData數組的第3個元素到日誌

<n,7488,(char *) tuple,172> -- 保存tuple到日誌

這些條目記錄了頁面在插入元組時的全部修改,它們最終會在CynosStore Client中造成一個MTR(mini-transaction record:多條日誌的集合,表明對數據庫存儲結構的一次原子修改,例如:btree結構、頁面結構的修改;在日誌重放的時候須要將一個MTR的全部日誌都應用完畢,不然會致使數據庫存儲結構的破壞),並放到日誌流中發送到存儲。當存儲須要將這個MTR合併到頁面時,要保證MTR中的全部日誌應用完畢,任何不徹底的應用都會致使頁面結構不正確。

利用日誌特色,咱們對PostgreSQL 的內核進行了優化,而優化以後的日誌大小開銷與PostgreSQL的原生XLOG差很少。這些優化和設計包括:

\1. 移除本來PostgreSQL中full page write(FPW)特性。爲了保證系統crash再重啓以後,那些部分寫的頁面(torn page)能夠被正確恢復,PostgreSQL在Checkpoint以後,對頁面執行第一次被修改時,會將整個頁面記錄到日誌中,這種特性就是FPW,相似MySQL的double write。當crash recovery時,系統會以這個全頁做爲基頁面進行日誌回放,並將恢復好的頁面寫到存儲,而沒必要關心存儲頁面中的頁面是不是半頁。因爲CynosDB日誌的冪等性,當出現半頁寫時,系統直接從新在此頁面上直接進行日誌回放,便可將頁面修復到一致狀態。所以CynosDB中無需原生的FPW,從而減小了日誌量。

\2. 移除系統中髒頁面刷盤操做。CynosDB經過日誌保存頁面的修改,而且能夠經過在基頁上合併日誌而獲得最新頁面,所以無需本來系統的刷髒操做,僅僅刷日誌就足夠。

經過如上優化,能夠很大程度上減小網絡IO和日誌量。

\3. 除了以上對PostgreSQL內核的優化,CynosDB對日誌的記錄方式也進行了精簡和壓縮。CynosDB的日誌都有日誌頭(LogHeader),若是修改同一個頁面的多條日誌共享一個日誌頭,則能夠省去多個日誌頭的開銷,以下圖所示:

img

LH表明LogHeader,Log Element表明對頁面的頁一次修改。如上圖,有兩條對Block1的修改日誌,而且每一個修改都有一個日誌頭(LH),通過日誌頭合併優化後,造成新的MTR中,修改Block1的那些日誌共享了同一個日誌頭。

若是修改同一個頁面的兩條日誌是相鄰的,那麼能夠將兩條日誌進一步合併成一條日誌。這種方式減小了日誌條目,從而能夠提升日誌合併和頁面生成速度。

4.2 頁面CRC

在PostgreSQL中,頁面在刷盤前會計算並填充頁面的CRC屬性,而在CynosDB中,若是爲CRC也生成了一條日誌寫入到存儲中的話,會增長計算節點的CPU負擔和日誌條數。爲了解決這個問題,咱們將CRC的計算任務下放到存儲中,從而減輕了計算層的CPU負擔,以及日誌條數。

4.3 異步表擴展

原生的PostgreSQL數據庫使用的是本地文件系統存儲數據,其文件擴展操做同步並實時的反映到磁盤文件上。可是CynosDB的擴展操做是經過日誌實現,若是每次擴展都對日誌作一次flush操做,讓擴展實時的反應到存儲上,勢必會影響系統的性能。所以,咱們實現了文件的異步擴展,即文件擴展的日誌先保留在系統的日誌buffer中,而不是每次擴展都實時的刷新到存儲中,當事務提交的時候再把這些日誌刷到存儲上,對數據批量導入的性能提高很明顯。另外,擴展操做能夠一次性在文件中擴展出多個頁面,減小調用擴展操做的次數。

後續

後續咱們會在新硬件、多Master架構等領域做更多探索,爲雲上的數據庫產品形態帶來更多驚喜和亮點。

此文已由做者受權騰訊雲+社區發佈

相關文章
相關標籤/搜索