共計(jì) 4133 個(gè)字符,預(yù)計(jì)需要花費(fèi) 11 分鐘才能閱讀完成。
自動(dòng)寫代碼機(jī)器人,免費(fèi)開(kāi)通
這篇文章給大家分享的是有關(guān) MongoDB 是怎樣存儲(chǔ)數(shù)據(jù)的的內(nèi)容。丸趣 TV 小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨丸趣 TV 小編過(guò)來(lái)看看吧。
前言
想要深入了解 MongoDB 如何存儲(chǔ)數(shù)據(jù)之前,有一個(gè)概念必須清楚,那就是 Memeory-Mapped Files。
Memeory-Mapped Files
下圖展示了數(shù)據(jù)庫(kù)是如何跟底層系統(tǒng)打交道的。
內(nèi)存映射文件是 OS 通過(guò) mmap 在內(nèi)存中創(chuàng)建一個(gè)數(shù)據(jù)文件,這樣就把文件映射到一個(gè)虛擬內(nèi)存的區(qū)域。
虛擬內(nèi)存對(duì)于進(jìn)程來(lái)說(shuō),是一個(gè)物理內(nèi)存的抽象,尋址空間大小為 2^64
操作系統(tǒng)通過(guò) mmap 來(lái)把進(jìn)程所需的所有數(shù)據(jù)映射到這個(gè)地址空間 (紅線),然后再把當(dāng)前需要處理的數(shù)據(jù)映射到物理內(nèi)存 (灰線)
當(dāng)進(jìn)程訪問(wèn)某個(gè)數(shù)據(jù)時(shí),如果數(shù)據(jù)不在虛擬內(nèi)存里,觸發(fā) page fault,然后 OS 從硬盤里把數(shù)據(jù)加載進(jìn)虛擬內(nèi)存和物理內(nèi)存
如果物理內(nèi)存滿了,觸發(fā) swap-out 操作,這時(shí)有些數(shù)據(jù)就需要寫回磁盤,如果是純粹的內(nèi)存數(shù)據(jù),寫回 swap 分區(qū),如果不是就寫回磁盤。
MongoDB 的存儲(chǔ)模型
有了內(nèi)存映射文件,要訪問(wèn)的數(shù)據(jù)就好像都在內(nèi)存里面,簡(jiǎn)單化了 MongoDB 訪問(wèn)和修改數(shù)據(jù)的邏輯
MongoDB 讀寫都只是和虛擬內(nèi)存打交道,剩下都交給 OS 打理
虛擬內(nèi)存大小 = 所有文件大小 + 其他一些開(kāi)銷 (連接,堆棧)
如果 journal 開(kāi)啟,虛擬內(nèi)存大小差不多翻番
使用 MMF 的好處 1:不用自己管理內(nèi)存和磁盤調(diào)度 2:LRU 策略 3:重啟過(guò)程中,Cache 依然在。
使用 MMF 的壞處 1:RAM 使用會(huì)受磁盤碎片的影響,高預(yù)讀也會(huì)影響 2:無(wú)法自己優(yōu)化調(diào)度算法,只能使用 LRU
磁盤上的文件是有 extent 構(gòu)成,分配集合空間的時(shí)候也是以 extent 為單位進(jìn)行分配的
一個(gè)集合有一個(gè)或者多個(gè) etent
ns 文件里面命名空間記錄指向那個(gè)集合的第一個(gè) extent
數(shù)據(jù)文件與空間分配
當(dāng)創(chuàng)建數(shù)據(jù)庫(kù)時(shí) (其實(shí) MongoDB 沒(méi)有顯式創(chuàng)建數(shù)據(jù)庫(kù)的方法,在向數(shù)據(jù)庫(kù)中的集合寫入數(shù)據(jù)時(shí)會(huì)自動(dòng)創(chuàng)建該數(shù)據(jù)庫(kù)),MongoDB 會(huì)在磁盤上分配一組數(shù)據(jù)文件,所有集合,索引和數(shù)據(jù)庫(kù)的其他元數(shù)據(jù)都保存在這些文件里。數(shù)據(jù)文件被放在啟動(dòng)時(shí)指定的 dbpath 里,默認(rèn)放入 /data/db 下面。典型的一個(gè)文件組織結(jié)構(gòu)如下:
$ 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 中存儲(chǔ)了服務(wù)器的進(jìn)程 ID,是一個(gè)進(jìn)程鎖定文件。數(shù)據(jù)文件是依據(jù)所屬的數(shù)據(jù)庫(kù)命名的。
test.ns 是第一個(gè)生成的文件 (ns 擴(kuò)展名就是 namespace 的意思),數(shù)據(jù)庫(kù)中的每個(gè)集合和索引都有自己的命名空間,每個(gè)命名空間的元數(shù)據(jù)都存放在這個(gè)文件里。默認(rèn)情況下,.ns 文件大小固定在 16MB,大約可以存儲(chǔ) 24000 個(gè)命名空間。也就是說(shuō)數(shù)據(jù)庫(kù)中的索引和集合總數(shù)不能超過(guò) 24000,該值可以通過(guò) mongod 的–nssize 選項(xiàng)進(jìn)行定制。
像 test.0 這樣以 0 開(kāi)始的整數(shù)結(jié)尾的文件就是集合和索引數(shù)據(jù)文件。剛開(kāi)始的時(shí)候,即使只有一條數(shù)據(jù),MongoDB 也會(huì)預(yù)分配幾個(gè)文件,這種預(yù)分配的做法,能讓數(shù)據(jù)盡可能連續(xù)存儲(chǔ),減少磁盤碎片。在像數(shù)據(jù)庫(kù)添加數(shù)據(jù)時(shí),MongoDB 會(huì)分配更多的數(shù)據(jù)文件。每個(gè)新數(shù)據(jù)文件的大小都是上一個(gè)已分配文件的兩倍 (64M- 128M- 256M),直到預(yù)分配文件大小的上限 2G。此處基于一個(gè)假設(shè),如果總數(shù)據(jù)大小呈恒定速率增長(zhǎng),應(yīng)該逐漸增加數(shù)據(jù)文件分配的空間。當(dāng)然這個(gè)預(yù)分配策略也是可以通過(guò)–noprealloc 關(guān)掉,但是不建議在 production 環(huán)境下使用。
默認(rèn)的 local 數(shù)據(jù)庫(kù),該數(shù)據(jù)庫(kù)不參與 replication。當(dāng) mongod 是一個(gè)副本集的成員時(shí),在 local 數(shù)據(jù)庫(kù)中就有一個(gè)叫做 oplog.rs 的預(yù)分配的 capped 集合,預(yù)分配的大小為磁盤空間的 5%。這個(gè)大小可以通過(guò)–oplogSize 進(jìn)行調(diào)整。oplog 主要用于副本集 Primary 和 Secondary 成員見(jiàn)的 replication,它的大小限制了兩個(gè)副本集之間,在重新完全同步之前,允許多長(zhǎng)時(shí)間不同步。
journal 目錄,journal 功能 2.4 版本默認(rèn)是開(kāi)啟的。
可以使用 db.stats() 來(lái)確認(rèn)已使用空間和已分配空間。
{
db : test ,
collections : 37,
objects : 317894523, # 文檔總個(gè)數(shù)
avgObjSize : 232.3416429039893, # 單位是字節(jié)
dataSize : 73860135744, # 集合中所有數(shù)據(jù)實(shí)際大小 (包括 padding factor 為每個(gè)文檔分配的額外空間以允許文檔增長(zhǎng))。該值在文檔 size 變小的時(shí)候,這個(gè)值不會(huì)減少,除非文檔被刪除,或者執(zhí)行 compact 或者 repairDatabase 操作
storageSize : 97834319392, # 分配給集合的空間大小 (包括為集合增長(zhǎng)預(yù)留的額外空間和未分配的已刪除空間,即不會(huì)因?yàn)槲臋n size 變小或者刪除而減小),實(shí)際上從數(shù)據(jù)文件中分配給集合的空間是以塊為單位,也稱之為 extents,即分配的 extents 的大小
numExtents : 385,
indexes : 86,
indexSize : 58687466992,
fileSize : 182380920832, # 所有數(shù)據(jù)文件大小之和,不包括命名空間文件 (ns 文件)
nsSizeMB : 16,
dataFileVersion : {
major : 4,
minor : 5
},
ok : 1
}
使用 db.accesslog.stats() 確認(rèn)某個(gè)集合的使用量
{
ns : test.accesslog ,
count : 145352932,
size : 37060264352, #實(shí)際數(shù)據(jù)大小,不包括索引
avgObjSize : 254.967435758365,
storageSize : 45794676448, # 預(yù)分配的數(shù)據(jù)存儲(chǔ)空間
numExtents : 42,
nindexes : 4,
lastExtentSize : 2146426864,
paddingFactor : 1, # 當(dāng)文檔因更新 size 增長(zhǎng)時(shí)事先 padding 可以提速,減少碎片的產(chǎn)生
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
}
感謝各位的閱讀!關(guān)于“MongoDB 是怎樣存儲(chǔ)數(shù)據(jù)的”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!
向 AI 問(wèn)一下細(xì)節(jié)