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
    }

     

--EOF--app

相關文章
相關標籤/搜索