WiredTiger存儲引擎知多少?

尋夢新聞LINE@每日推播熱門推薦文章,趣聞不漏接❤️

加入LINE好友

摘要

本次分享的主題是WiredTiger的存儲引擎,主要包含四部分內容,首先介紹MongoDB的插件式存儲引擎的架構,然後是WiredTiger的事物,第三部分將介紹Checkpoint機制,最後通過一個案例,分析WiredTiger的cache分配和壓縮特性。

插件式存儲引擎架構

這個圖最下層是存儲引擎的最底層,中間還有一個記憶體的存儲引擎。這些存儲引擎的上面是MongoDB的文檔數據模型,因此不管採用什麼樣的存儲引擎,對於上層的應用程序開發者來說都是透明的。最上層是通過MongoDB數據庫支撐的各種應用。可以看到總體的架構,實際上與Mysql有點類似,都是插件式的存儲引擎架構。

事務特性與快照隔離級別

關係數據庫中的事務是有隔離性的,而MongoDb也支持事務,且符合ACID事務的標準特性。通常事物會有寫提交、讀未提交、快照等隔離級別,MongoDB默認使用的是快照形式的隔離級別,任何事物開始的時候,先會對記憶體里面所有寫操作但是還未完成的事務做一個拍照,然後記錄這些寫操作未完成事務的一個狀態信息。

對於寫操作事務,在寫入之前先需要判斷操是否與之前其他未完成的事務是否有衝突,如果有衝突的話就會執行失敗,過一段時間後再重新提交事務,這里關鍵的在於能夠判斷寫操作是否與其它的事務發生衝突。

MVCC做到事物的衝突檢測與並發

多版本並發控制機制的引入,讓我們可以檢測是否衝突,它實際上是通過記錄每一個事物開始的時候所操作的這條記錄的版本號來做到的,這種方式在其他數據庫里面同樣存在。

比如我們有AB這兩個寫操作的事務。A事務首先從表中讀取到要修改的行數據,讀取到庫存值為100,行記錄的版本號為1。B事務也從中讀取到要修改的相同行數據,讀取值為100,行記錄版本號為1。A事務修改庫存值都提交,同時行記錄版本號加1,大於一開始讀取到的版本號1,因此A事務可以提交。但B事務提交時發現此時行記錄版本號已經為2,產生了衝突,所以B事務會提交失敗。接著B事務會嘗試重新提交,在讀取的版本號基礎上加1,這樣就不會再產生衝突,正常提交了。通過這種多版本並發控制的機制就可以防止B事物修改錯誤的數據。

典型操作事務執行流程

寫操作事務開始執行之前,會對所有正在執行的還未提交事務進行快照。然後將本次寫操作的動作保存到Operation_array中,可以從中提取出動作進行回滾,其次將修改的數據以日志形式記錄下來,記錄到日志緩存區域。寫操作事務提交,首先會將日志緩沖區中的數據刷到磁盤上,寫入到log文件,數據庫意外宕機恢復時需要讀取這個文件,重演文件里面的動作。

寫操作引起的數據變化,首先寫入到WiredTiger存儲引擎的cache中,cache中的數據以btree的結構組織,btree的葉子節點是真正存放數據的page,當數據發生更改時page就變未「臟頁」(在記憶體中);存儲引擎默認從每60s將「臟頁」中的數據寫到物理磁盤上進行持久化。

引入checkpoint機制後的典型寫操作流程

引入checkpoint後整個流程會發生相應的變化,主要是圖中圈出來的地方。Checkpoint會產生在兩個地方,一個是在默認情況下每60秒刷新磁盤的時候,將記憶體里面的臟數據刷到磁盤的時間點上,會在對應的數據文件上產生。另外一個時機是開啟journal日志功能後,當日志文件達到2gb的時候,也會發生一次checkpoint。

checkpoint有兩個重要的作用,一個是恢復數據庫的時候,讓我們只需要從最新的checkpoint時間點進行恢復,有效的縮減數據庫恢復的時間。另一方面由於checkpoint完成以後,就可以認為記憶體里面在checkpoint時間點之前的數據都已經安全完整的寫到磁盤上了,因此可以釋放記憶體「臟頁」所占的記憶體空間,達到節省記憶體空間的目的。

WiredTiger對記憶體的使用情況

wiredTiger對記憶體使用會分為兩大部分,一部分是內部記憶體,另外一部分是文件系統的緩存。內部記憶體默認值有一個計算公式{ 50% of(RAM-1GB) ,or256MB },索引和集合的記憶體都被加載到內部記憶體,索引是被壓縮的放在內部記憶體,集合則沒有壓縮。wiredTiger會通過文件系統緩存,自動使用其他所有的空閒記憶體,放在文件系統緩存里面的數據,與磁盤上的數據格式一致,可以有效減少磁盤I/O。

internal Cache的內部結構

在記憶體中數據是以btree的結構形式進行存儲的,任何數據在寫之前,都會先讀取到internal cache里面。如上圖第一步操作是調用塊管理器,塊管理器會將磁盤上的數據讀取到記憶體。第二步修改數據的的時候,會重新分配一個新的page,在此基礎上進行修改,修改完成後,原來page就會變成「臟頁」,接著通過wiredTiger的內部機制將這個「臟頁」重新通過塊管理器刷到磁盤里面。

與internal cache相關的幾個數據結構

首先是原始的page,通過列表形式把所有的數據給串起來。如果有修改動作,會再維護一個修改的page,在修改的page里面又會維護兩個鏈表,保存的是鏈表的頭,插入鏈表和修改鏈表的時候分別對應著兩個數據結構,這樣wiredTiger就不會將每一次的修改和插入操作直接寫到磁盤上。當修改操作或插入操作累積到一定程度以後,在記憶體里面會將這些操作進行規整,整理以後,然後同時一次性的寫入到的磁盤里面去。

案例:應用程序開發連接池問題

最後我們看一下與應用程序開發者比較相關的連接池的問題。當時我們有很多應用都用到了MongoDB,所有應用都創建了Mongo Client,這些應用經常會做些增刪改查的動作,但是由於我們的服務器配置集成人員可能對分片集群的部署不是很熟悉,所以有些參數也沒有關注到,導致了大量連接超時的的一個問題。

後續我們對此進行了分析,找到了具體原因。對於MongoDB來說,它的連接分為有兩個部分,一個是驅動程序的連接詞,另外一個是在服務器上,其中有一個參數決定了該服務器所能支持的最大的並發連接數。如果驅動程序的連接池遠大於服務器所能支持的並發連接數,那麼即使客戶端程序沒有出現連接問題,服務端也會出現連接拒絕的錯誤。為解決這方面的問題,我們可以分別從客戶端和服務端的層面修改他們的默認連接池大小。

以上為今天的分享內容,謝謝大家!

本文轉載自:IT大咖說

About 尋夢園
尋夢園是台灣最大的聊天室及交友社群網站。 致力於發展能夠讓會員們彼此互動、盡情分享自我的平台。 擁有數百間不同的聊天室 ,讓您隨時隨地都能找到志同道合的好友!