使用MongoDB一段時間的同學肯定會發現,MongoDB往往會佔用比實際資料大小多不少空間的問題。如果利用db.stats()命令去查看,會發現MongoDB會報告幾種不同的空間大小資訊,如dataSize, storageSize以及fileSize。這些大小到底指的是什麼意思呢。讓我們來通過瞭解MongoDB的儲存機制來解析這幾個數值的含義。 資料庫檔案類型
MongoDB的資料庫檔案主要有3種: journal 記錄檔 namespace 表名檔案 data 資料及索引檔案
記錄檔
跟一些傳統資料庫不同,MongoDB的記錄檔只是用來在系統出現宕機時候恢複尚未來得及同步到硬碟的記憶體資料。記錄檔會存放在一個分開的目錄下面。啟動時候MongoDB會自動預先建立3個每個為1G的記錄檔(初始為空白)。除非你真的有持續海量資料並發寫入,一般來說3個G已經足夠。
命名檔案 dbname.ns
這個檔案用來儲存整個資料庫的集合以及索引的名字。這個檔案不大,預設16M,可以儲存24000個集合或者索引名以及那些集合和索引在資料檔案中得具體位置。通過這個檔案MongoDB可以知道從哪裡去開始尋找或插入集合的資料或者索引資料。這個值可以通過參數調整至2G。
資料檔案 dbname.0, dbname.1,… dbname.n
MongoDB的資料以及索引都存放在一個或者多個MongoDB資料檔案裡。第一個資料檔案會以“資料庫名.0”命名,如 my-db.0。這個檔案預設大小是64M,在接近用完這個64M之前,MongoDB 會提前產生下一個資料檔案如my-db.1。資料檔案的大小會2倍遞增。第二個資料檔案的大小為128M,第三個為256M。一直到了2G以後就會停止,一直按這個2G這個大小增加新的檔案。
當然MongoDB還會產生一些臨時檔案如 _tmp 和 mongod.lock等, 不過他們跟我們的討論都沒有太大相關性。 資料檔案結構
Extent
在每一個資料檔案內,MongoDB把所儲存的BSON文檔的資料和B樹索引組織到邏輯容器“Extent”裡面。如下圖所示(my-db.1和my-db.2 是資料庫的兩個資料檔案):
一個檔案可以有多個Extent 每一個Extent只會包含一個集合的資料或者索引 同一個集合的資料或索引可以分布在多個Extent內。這幾個Extent也可以分步於多個檔案內 同一個Extent不會又有資料又有索引
Record 記錄
在每個Extent裡面存放有多個”Record“, 每一個記錄裡包含一個記錄頭以及MongoDB的BSON文檔,以及一些額外的padding空間。Padding是MongoDB在插入記錄時額外分配一些未用空間,這樣將來文檔變大的時候不至於需要把文檔遷移到別處。 記錄頭以整個記錄的大小開始,包括該記錄自己的位置以及前一個記錄和後一個記錄的位置。可以想象成一個Double Linked List。 資料庫大小參數
在之前的基礎上,我們可以來理解一下db.stats()裡面關於空間大小參數的含義。
dataSize
dataSize是最接近真實資料大小的一個參數。你可以用來檢查你的資料有多少。這個大小包括了資料庫(或者集合)的每條記錄的總和。注意每條記錄除了BSON文檔外還有header及padding這些額外開銷。所以實際大小會比真正資料所佔空間會稍大。
當刪除文檔的時候,這個參數會相應變小因為它是所有文檔數的大小總和。如果你的文檔沒有刪除,只是文檔內部的欄位被刪除或縮小,則不會對dataSize 有影響。原因就是因為文檔所在記錄還在,並且整條記錄所佔空間並無改動,只不過記錄內的未用空間變多了而已。
storageSize
這個參數等於資料庫或者某個集合所有用到的Data Extents的總和。注意這個數字會大於dataSize因為Extent裡面會有一些刪除文檔之後留下來的片段(deleted)。及時你的storageSize大出dataSize很多,這個也不一定就是很糟糕的情況。 如果有新插入的文檔小於或等於片段的大小,MongoDB會重新利用這個片段來儲存新的文檔。不過在這之前這些片段將一直會被保留在那裡佔用空間。由於這個原因,你刪除文檔的時候這個參數不會變小。
片段問題會因為啟動並執行時間變長而變得嚴重。你可以通過 compact 命令來進行片段清理或者通過新架一台從機複製所有資料,然後變成主節點的方式來解決這些片段。
fileSize
這個參數只在資料庫上有效,指的是實際檔案系統中用到的檔案的大小。它包括所有的資料Extents的總和,索引Extent的總和,以及一些未被分配的空間。之前提到MongoDB會對資料庫檔案建立時候進行預分配,例如最小就是64M,哪怕你只有幾百個KB的資料。所以這個參數可能會比實際的資料大小會大不少。 這些額外未用空間是用來保證MongoDB可以在新的資料寫入時候快速的分配新的Extent,避免引起磁碟空間分配引起的延遲。
值得注意的是,當你刪除文檔,或甚至集合和索引,這個參數不會變小。換句話說,資料庫所使用的硬碟空間只會上升(或者不變),而不會因為刪除資料而變小。當然需要知道的是這並不就意味著浪費,只是說有很多預留空間而已。
此文根據http://blog.mongolab.com/2014/01/how-big-is-your-mongodb/ 改編而來。
--本篇文章轉自:http://www.mongoing.com/blog/file-storage