GaussDB(DWS)基本IO框架
概述
數據庫的IO結構一直是影響性能的關鍵部分,數據庫的操作最終還是要體現在最后的物理文件上。我們平常總是聽到各種緩存,這都是為了減小IO開銷而設計的。
對于數據庫來說,因為要保證一致性的問題,那么IO模型的設計就更為復雜,既要保證減少IO的讀寫,又要保證突然斷電時,已提交事務的內容不能丟失等意外情況。此外,采用不同的索引結構設計的IO開銷也不一樣,理解IO模型對數據庫的調優也有一定的指導作用。
本篇博文分別從讀取和寫入兩個方面講解了GaussDB(DWS)中的行存,列存基本IO模型。
行存IO基本框架
存儲結構
在了解行存的整個IO框架之前,首先需要對行存的文件結構有一定的了解。那么我們平常操作的表都是怎么樣存儲在我們的文件系統中呢?
就跟我們平常用的身份證號一樣,在GaussDB(DWS)中,也有對應的ID號來標識各個對象:
OID(Object identifiers):對象的唯一標識。
每個表存在對應數據庫的文件夾中,用relfilenode標識。
通過各種ID,我們就可以查看每個表對應的文件了。
例如表row1,可以直接查詢對應的文件:
test=# select pg_relation_filepath('row1'); pg_relation_filepath ---------------------- base/16385/55984 (1 row)
對于行存來說,我們常有的印象是以行為單位進行讀取和寫入的,但是這個對于IO開銷就過于嚴重了,因此GaussDB(DWS)采用和操作系統的思路,以頁為基本單位進行讀取和寫入。
每個表的讀取寫入以頁(文件塊)為基本單位,頁的大小是一個BLCKSZ,默認8KB,其結構如下:
Tuple保存了當前一行的數據,分為Header和Data兩塊,頭部保存元組的相關信息(列數,事務信息,是否有Toast表等)。
每個Tuple最大為2kb,若Data過大無法壓縮至2KB,則采用額外的Toast表存儲,此時Tuple內的Data保存Toast表的相關信息。
GaussDB 行存框架:
行存無論在讀取還是寫入上,都采用了大量的緩存用來減少IO開銷。
在外存方面,針對數據庫的特點,也單獨設計了外存管理器。整個框架如下:
這里面涉及到幾個比較大的內核機制:
本地緩存:
這里面的本地緩存介紹了三個比較常用的緩存結構,這里直接引用了官方的英文解釋。
temp_buffers: Sets the maximum number of temporary buffers used by each database session. These are session-local buffers used only for access to temporary tables.
work_mem: Specifies the amount of memory to be used by internal sort operations and hash tables before writing to temporary disk files.
maintenance_work_mem: Specifies the maximum amount of memory to be used by maintenance operations, such as VACUUM, CREATE INDEX, and ALTER TABLE ADD FOREIGN KEY.
共享內存:可由整個Gaussdb共享
包括shared_buffer和wal_buffer, 分別用來存放Page和Clog,Wal Segment。
WalWriter,BgWriter:
主要是將共享內存的內容落盤,WalWriter一般是在事務提交時就需要落盤,但是有時候可以放棄一定的事務一致性原則,從而讓WalWriter異步落盤加快速度。BgWriter負責將shared_buffer中的內容落盤。
外存管理:
負責上層與外存之間的文件交互。
IO管理框架:讀取
讀取的過程相對簡單,就是從物理文件先裝到shared_buffer中,然后從shared_buffers返回相關的結果。
shared_buffers中就是以Page為單位進行存儲的,因為每個Page的大小是固定的,所以shared_buffers能存放的page個數也就是確定的。這里面就需要考慮一個問題,因為這個資源是共享的,如果一個線程讀取了大量的文件,這樣勢必會使得其他線程的緩存命中率下降。
GaussDB在這里引入了Ringbuffer的機制,可以限制一個線程所使用的shared_buffers的大小,從而解決掉這個問題。
IO管理框架:寫入
寫入操作是增加的新的元組,Update操作相當于先Delete, Insert。
INSERT
增加一個新的元組和對應的line pointer的標記。
UPDATE
刪除舊的元組,可以看見Tuple1的HEAD標記了Delete, Data在圖中標記為了Delete只是為了說明這個Tuple被刪除了。然后增加新的元組
將舊元組標記為Dead,然后插入新的元組,由Vacuum負責清理。當然,這里面Data變為DELETE只是用來描述刪除的是此Tuple,實際上Data當中的值是不變的。
寫入的整體邏輯:
GaussDB行存在寫入時,將元組信息先寫入到shared_buffers,然后用bgwriter刷入磁盤,這樣在事務提交時就可以避免磁盤的IO開銷,提升性能,為了保證一致性和恢復,使用wal日志和checkpoints可以實現日志先落盤(也可以異步)和redo等操作。
列存的IO管理框架
列存的存儲單元
列存的存儲結構并沒有像orc或parquet的結構方式,采用了一種真正的以列存儲的結構方式。主要的特性如下:
列存的存儲單元為CU(CStore Unit)
CU的大小為8k對齊
適合大批量導入的場景
同一列的CU存在一個新文件中,大于1GB時,切換到新文件中。
列存用一個CUDesc的行存表描述CU的相關信息,可以理解成為一個Toast表。
CUDesc:行存表,記錄CU的相關信息, 主要屬性如下:
col_id,cu_id: 第col_id列,第cu_id個CU
min, max, row_count, size
cu_mode: information mask(RLE,LZ4,Delta表等)
cu_pointer:指向每一個CU,記錄delete bitmap
magic:和CU頭部的magic相同,校驗使用
CU結構
和傳統的文件結構類似,也是以頭和壓縮后的數據為主要結構。
列存索引
這里介紹兩個索引,C-Btree和Psort索引。這也是各大數據庫常用的兩個索引,主要涉及的是IO相關的內容。
C-Btree
列存的Btree原理上并不是基于普通的Btree,而更像是一種B+樹。
索引結構和行存無差別,同樣以行存形式存儲
C-Btree可以提升點查效率
存儲key->ctid(cu_id, offset)
過程:
根據B-tree索引找到ctid集合
對集合進行批量排序(減少IO開銷)
在CUDesc找到對應的cu_id,根據offset找到數據
舉例,等值查詢 n=49, 范圍查詢 23 PSort PSort是一個聚簇索引,對索引進行排序,然后將排序后的索引和行號存入一個新的表,用單獨的列存表存儲。 簡單示意如下,圖片來源:https://www.modb.pro/db/108155 IO管理框架:讀取 列存的讀取和行存一樣,也是設計了緩存,這樣在重復查詢的時候可以顯著減少IO開銷,提高性能。 讀取過程: 根據where條件,做MIN/MAX過濾的謂詞條件 加載CUDesc MIN/MAX過濾 讀取CU到CU Cache中 解析并填充 CacheMgr: 用來緩存CU到內存中,可以提高重復查詢的性能。 CU的物理文件: 1. CStore_1.0: 當前基本不怎么實用 2. CStore_2.0: 重整了CU的文件結構,避免列數過多導致文件結構復雜。 IO管理框架:寫入 列存的插入要分兩種情況,少量的插入和大量的插入,列存主要是對大批量數據設計的,因此為了彌補小量插入的打包CU性能開銷,設計了一個delta行存表,用來記錄插入結果,可以減少膨脹和提升性能,最后定期的整理。 寫入框架如下 列存的刪除比較簡單,如果是delta表,先從delta表中刪除滿足謂詞條件的記錄,然后在CUDesc表中更新待刪除CU的delete_bitmap。 總結 以上的相關內容只是整個IO框架的大體描述。可以看出因為涉及的場景不同,列存和行存的模型還是有區別的。尤其是列存的寫入不通過緩存,直接進入磁盤,這點與行存有著很大的區別,行存因為首先寫入shared_buffers,就需要很多額外的機制來保證一致性問題。而列存則相對簡單,誰好誰好都不是絕對的,這與使用場景有很深的關系。 這其中還有很多細小的點可以仔細分析,以后的博客也會針對其中某些內容深入講解,比如說,OS緩存和GaussDB(DWS)之間的緩存交互,以及OS緩存和磁盤之間的交互邏輯,這對于一致性的實現是很重要的。 希望本篇博客能夠幫助到各位讀者! EI企業智能 Gauss AP 數據倉庫服務 GaussDB(DWS)
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。