MongoDB技術分享:WiredTiger儲存引擎

IT大咖說發表於2018-11-28

內容來源:2018 年 10 月 27 日,MongoDB中文社群聯席主席郭遠威在“2018年MongoDB中文社群 廣州大會”進行《WiredTiger儲存引擎介紹》的演講分享。IT 大咖說作為獨家視訊合作方,經主辦方和講者審閱授權釋出。

閱讀字數:2969 | 8分鐘閱讀

獲取嘉賓演講視訊及PPT,請點選:t.cn/ELK5siB

MongoDB技術分享:WiredTiger儲存引擎摘要

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

外掛式儲存引擎架構

MongoDB技術分享:WiredTiger儲存引擎

這個圖最下層是儲存引擎的最底層,中間還有一個記憶體的儲存引擎。這些儲存引擎的上面是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機制後的典型寫操作流程

MongoDB技術分享:WiredTiger儲存引擎

引入checkpoint後整個流程會發生相應的變化,主要是圖中圈出來的地方。Checkpoint會產生在兩個地方,一個是在預設情況下每60秒重新整理磁碟的時候,將記憶體裡面的髒資料刷到磁碟的時間點上,會在對應的資料檔案上產生。另外一個時機是開啟journal日誌功能後,當日志檔案達到2gb的時候,也會發生一次checkpoint。

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

WiredTiger對記憶體的使用情況

MongoDB技術分享:WiredTiger儲存引擎

wiredTiger對記憶體使用會分為兩大部分,一部分是內部記憶體,另外一部分是檔案系統的快取。內部記憶體預設值有一個計算公式{ 50% of(RAM-1GB) ,or256MB },索引和集合的記憶體都被載入到內部記憶體,索引是被壓縮的放在內部記憶體,集合則沒有壓縮。wiredTiger會通過檔案系統快取,自動使用其他所有的空閒記憶體,放在檔案系統快取裡面的資料,與磁碟上的資料格式一致,可以有效減少磁碟I/O。

internal Cache的內部結構

MongoDB技術分享:WiredTiger儲存引擎

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

與internal cache相關的幾個資料結構

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

案例:應用程式開發連線池問題

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

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

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

編者:IT大咖說,轉載請標明版權和出處


相關文章