前言
本文主要介紹了關于MongoDB存儲數據的相關內容,分享出來供大家參考學習,下面來一起看看詳細的介紹:
想要深入了解MongoDB如何存儲數據之前,有一個概念必須清楚,那就是Memeory-Mapped Files。
Memeory-Mapped Files
下圖展示了數據庫是如何跟底層系統打交道的。
- 內存映射文件是OS通過mmap在內存中創建一個數據文件,這樣就把文件映射到一個虛擬內存的區域。
- 虛擬內存對于進程來說,是一個物理內存的抽象,尋址空間大小為2^64
- 操作系統通過mmap來把進程所需的所有數據映射到這個地址空間(紅線),然后再把當前需要處理的數據映射到物理內存(灰線)
- 當進程訪問某個數據時,如果數據不在虛擬內存里,觸發page fault,然后OS從硬盤里把數據加載進虛擬內存和物理內存
- 如果物理內存滿了,觸發swap-out操作,這時有些數據就需要寫回磁盤,如果是純粹的內存數據,寫回swap分區,如果不是就寫回磁盤。

MongoDB的存儲模型

- 有了內存映射文件,要訪問的數據就好像都在內存里面,簡單化了MongoDB訪問和修改數據的邏輯
- MongoDB讀寫都只是和虛擬內存打交道,剩下都交給OS打理
- 虛擬內存大小=所有文件大小+其他一些開銷(連接,堆棧)
- 如果journal開啟,虛擬內存大小差不多翻番
- 使用MMF的好處1:不用自己管理內存和磁盤調度2:LRU策略3:重啟過程中,Cache依然在。
- 使用MMF的壞處1:RAM使用會受磁盤碎片的影響,高預讀也會影響2:無法自己優化調度算法,只能使用LRU



- 磁盤上的文件是有extent構成,分配集合空間的時候也是以extent為單位進行分配的
- 一個集合有一個或者多個etent
- ns文件里面命名空間記錄指向那個集合的第一個extent
數據文件與空間分配
當創建數據庫時(其實MongoDB沒有顯式創建數據庫的方法,在向數據庫中的集合寫入數據時會自動創建該數據庫),MongoDB會在磁盤上分配一組數據文件,所有集合,索引和數據庫的其他元數據都保存在這些文件里。數據文件被放在啟動時指定的dbpath里,默認放入/data/db下面。典型的一個文件組織結構如下:
$ cat /data/db
$ ls -al
-rw------- 1 root root 16777216 09-18 00:54 local.ns
-rw------- 1 root root 67108864 09-18 00:54 local.0
-rw------- 1 root root 2146435072 09-18 00:55 local.1
-rw------- 1 root root 2146435072 09-18 00:56 local.2
-rw------- 1 root root 2146435072 09-18 00:57 local.3
-rw------- 1 root root 2146435072 09-18 00:58 local.4
-rw------- 1 root root 2146435072 09-18 00:59 local.5
-rw------- 1 root root 2146435072 09-18 01:01 local.6
-rw------- 1 root root 2146435072 09-18 01:02 local.7
-rw------- 1 root root 2146435072 09-18 01:03 local.8
-rw------- 1 root root 2146435072 09-18 01:04 local.9
-rw------- 1 root root 2146435072 09-18 01:05 local.10
-rw------- 1 root root 16777216 09-18 01:06 test.ns
-rw------- 1 root root 67108864 09-18 01:06 test.0
-rw------- 1 root root 134217728 09-18 01:06 test.1
-rw------- 1 root root 268435456 09-18 01:06 test.2
-rw------- 1 root root 536870912 09-18 01:06 test.3
-rw------- 1 root root 1073741824 09-18 01:07 test.4
-rw------- 1 root root 2146435072 09-18 01:07 test.5
-rw------- 1 root root 2146435072 09-18 01:09 test.6
-rw------- 1 root root 2146435072 09-18 01:11 test.7
-rw------- 1 root root 2146435072 09-18 01:13 test.8
...
-rwxr-xr-x 1 root root 6 09-18 13:54 mongod.lock
drwxr-xr-x 2 root root 4096 11-13 18:39 journal
drwxr-xr-x 2 root root 4096 11-13 19:02 _tmp
- mongod.lock中存儲了服務器的進程ID,是一個進程鎖定文件。數據文件是依據所屬的數據庫命名的。
- test.ns是第一個生成的文件(ns擴展名就是namespace的意思),數據庫中的每個集合和索引都有自己的命名空間,每個命名空間的元數據都存放在這個文件里。默認情況下,.ns文件大小固定在16MB,大約可以存儲24000個命名空間。也就是說數據庫中的索引和集合總數不能超過24000,該值可以通過mongod的–nssize選項進行定制。
- 像test.0這樣以0開始的整數結尾的文件就是集合和索引數據文件。剛開始的時候,即使只有一條數據,MongoDB也會預分配幾個文件,這種預分配的做法,能讓數據盡可能連續存儲,減少磁盤碎片。在像數據庫添加數據時,MongoDB會分配更多的數據文件。每個新數據文件的大小都是上一個已分配文件的兩倍(64M->128M->256M),直到預分配文件大小的上限2G。此處基于一個假設,如果總數據大小呈恒定速率增長,應該逐漸增加數據文件分配的空間。當然這個預分配策略也是可以通過–noprealloc關掉,但是不建議在production環境下使用。
- 默認的local數據庫,該數據庫不參與replication。當mongod是一個副本集的成員時,在local數據庫中就有一個叫做oplog.rs的預分配的capped集合,預分配的大小為磁盤空間的5%。這個大小可以通過–oplogSize進行調整。oplog主要用于副本集Primary和Secondary成員見的replication,它的大小限制了兩個副本集之間,在重新完全同步之前,允許多長時間不同步。
- journal目錄,journal功能2.4版本默認是開啟的。
- 可以使用
db.stats()
來確認已使用空間和已分配空間。
{
"db" : "test",
"collections" : 37,
"objects" : 317894523, #文檔總個數
"avgObjSize" : 232.3416429039893, #單位是字節
"dataSize" : 73860135744, #集合中所有數據實際大小(包括padding factor為每個文檔分配的額外空間以允許文檔增長)。該值在文檔size變小的時候,這個值不會減少,除非文檔被刪除,或者執行compact或者repairDatabase操作
"storageSize" : 97834319392, #分配給集合的空間大小(包括為集合增長預留的額外空間和未分配的已刪除空間,即不會因為文檔size變小或者刪除而減小),實際上從數據文件中分配給集合的空間是以塊為單位,也稱之為extents,即分配的extents的大小
"numExtents" : 385,
"indexes" : 86,
"indexSize" : 58687466992,
"fileSize" : 182380920832, #所有數據文件大小之和,不包括命名空間文件(ns文件)
"nsSizeMB" : 16,
"dataFileVersion" : {
"major" : 4,
"minor" : 5
},
"ok" : 1
}
使用db.accesslog.stats()
確認某個集合的使用量
{
"ns" : "test.accesslog",
"count" : 145352932,
"size" : 37060264352, #實際數據大小,不包括索引
"avgObjSize" : 254.967435758365,
"storageSize" : 45794676448, #預分配的數據存儲空間
"numExtents" : 42,
"nindexes" : 4,
"lastExtentSize" : 2146426864,
"paddingFactor" : 1, #當文檔因更新size增長時事先padding可以提速,減少碎片的產生
"systemFlags" : 1,
"userFlags" : 0,
"totalIndexSize" : 31897944512,
"indexSizes" : {
"_id_" : 6722168208,
"action_1_time_1" : 8606482752,
"gz_id_1_action_1_time_1" : 10753778336,
"time_1" : 5815515216
},
"ok" : 1
}
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
您可能感興趣的文章:- MongoDB系列教程(八):GridFS存儲詳解
- PHP操作MongoDB GridFS 存儲文件的詳解
- PHP MongoDB GridFS 存儲文件的方法詳解
- Spring Boot集成Shiro并利用MongoDB做Session存儲的方法詳解
- Nodejs使用Mongodb存儲與提供后端CRD服務詳解
- python將MongoDB里的ObjectId轉換為時間戳的方法
- python根據時間生成mongodb的ObjectId的方法
- 深究從MongoDB的ObjectId中獲取時間信息
- MongoDB批量將時間戳轉為通用日期格式示例代碼
- MongoDB存儲時間時差問題的解決方法