MongoDB 基礎
MongoDB 是什么?
MongoDB 是一個基于 分布式文件存儲 的開源 NoSQL 數據庫系統,由 C++ 編寫的。MongoDB 提供了 面向文檔 的存儲方式,操作起來比較簡單和容易,支持“無模式”的數據建模,可以存儲比較復雜的數據類型,是一款非常流行的 文檔類型數據庫 。
在高負載的情況下,MongoDB 天然支持水平擴展和高可用,可以很方便地添加更多的節點/實例,以保證服務性能和可用性。在許多場景下,MongoDB 可以用于代替傳統的關系型數據庫或鍵/值存儲方式,皆在為 Web 應用提供可擴展的高可用高性能數據存儲解決方案。
MongoDB 的存儲結構是什么?
MongoDB 的存儲結構區別于傳統的關系型數據庫,主要由如下三個單元組成:
- 文檔(Document):MongoDB 中最基本的單元,由 BSON 鍵值對(key-value)組成,類似于關系型數據庫中的行(Row)。
- 集合(Collection):一個集合可以包含多個文檔,類似于關系型數據庫中的表(Table)。
- 數據庫(Database):一個數據庫中可以包含多個集合,可以在 MongoDB 中創建多個數據庫,類似于關系型數據庫中的數據庫(Database)。
也就是說,MongoDB 將數據記錄存儲為文檔 (更具體來說是BSON 文檔),這些文檔在集合中聚集在一起,數據庫中存儲一個或多個文檔集合。
SQL 與 MongoDB 常見術語對比:
SQL | MongoDB |
---|---|
表(Table) | 集合(Collection) |
行(Row) | 文檔(Document) |
列(Col) | 字段(Field) |
主鍵(Primary Key) | 對象 ID(Objectid) |
索引(Index) | 索引(Index) |
嵌套表(Embedded Table) | 嵌入式文檔(Embedded Document) |
數組(Array) | 數組(Array) |
文檔
MongoDB 中的記錄就是一個 BSON 文檔,它是由鍵值對組成的數據結構,類似于 JSON 對象,是 MongoDB 中的基本數據單元。字段的值可能包括其他文檔、數組和文檔數組。
文檔的鍵是字符串。除了少數例外情況,鍵可以使用任意 UTF-8 字符。
- 鍵不能含有
\0
(空字符)。這個字符用來表示鍵的結尾。 .
和$
有特別的意義,只有在特定環境下才能使用。- 以下劃線
_
開頭的鍵是保留的(不是嚴格要求的)。
BSON [bee·sahn] 是 Binary JSON的簡稱,是 JSON 文檔的二進制表示,支持將文檔和數組嵌入到其他文檔和數組中,還包含允許表示不屬于 JSON 規范的數據類型的擴展。有關 BSON 規范的內容,可以參考 bsonspec.org,另見BSON 類型。
根據維基百科對 BJSON 的介紹,BJSON 的遍歷速度優于 JSON,這也是 MongoDB 選擇 BSON 的主要原因,但 BJSON 需要更多的存儲空間。
與 JSON 相比,BSON 著眼于提高存儲和掃描效率。BSON 文檔中的大型元素以長度字段為前綴以便于掃描。在某些情況下,由于長度前綴和顯式數組索引的存在,BSON 使用的空間會多于 JSON。
集合
MongoDB 集合存在于數據庫中,沒有固定的結構,也就是?無模式?的,這意味著可以往集合插入不同格式和類型的數據。不過,通常情況下,插入集合中的數據都會有一定的關聯性。
集合
MongoDB 集合存在于數據庫中,沒有固定的結構,也就是?無模式?的,這意味著可以往集合插入不同格式和類型的數據。不過,通常情況下,插入集合中的數據都會有一定的關聯性。
?
集合不需要事先創建,當第一個文檔插入或者第一個索引創建時,如果該集合不存在,則會創建一個新的集合。
集合名可以是滿足下列條件的任意 UTF-8 字符串:
- 集合名不能是空字符串
""
。 - 集合名不能含有
\0
(空字符),這個字符表示集合名的結尾。 - 集合名不能以"system."開頭,這是為系統集合保留的前綴。例如
system.users
這個集合保存著數據庫的用戶信息,system.namespaces
集合保存著所有數據庫集合的信息。 - 集合名必須以下劃線或者字母符號開始,并且不能包含
$
。
數據庫
數據庫用于存儲所有集合,而集合又用于存儲所有文檔。一個 MongoDB 中可以創建多個數據庫,每一個數據庫都有自己的集合和權限。
MongoDB 預留了幾個特殊的數據庫。
- admin : admin 數據庫主要是保存 root 用戶和角色。例如,system.users 表存儲用戶,system.roles 表存儲角色。一般不建議用戶直接操作這個數據庫。將一個用戶添加到這個數據庫,且使它擁有 admin 庫上的名為 dbAdminAnyDatabase 的角色權限,這個用戶自動繼承所有數據庫的權限。一些特定的服務器端命令也只能從這個數據庫運行,比如關閉服務器。
- local : local 數據庫是不會被復制到其他分片的,因此可以用來存儲本地單臺服務器的任意 collection。一般不建議用戶直接使用 local 庫存儲任何數據,也不建議進行 CRUD 操作,因為數據無法被正常備份與恢復。
- config : 當 MongoDB 使用分片設置時,config 數據庫可用來保存分片的相關信息。
- test : 默認創建的測試庫,連接 mongod 服務時,如果不指定連接的具體數據庫,默認就會連接到 test 數據庫。
數據庫名可以是滿足以下條件的任意 UTF-8 字符串:
- 不能是空字符串
""
。 - 不得含有
' '
(空格)、.
、$
、/
、\
和\0
(空字符)。 - 應全部小寫。
- 最多 64 字節。
數據庫名最終會變成文件系統里的文件,這也就是有如此多限制的原因。
MongoDB 有什么特點?
- admin : admin 數據庫主要是保存 root 用戶和角色。例如,system.users 表存儲用戶,system.roles 表存儲角色。一般不建議用戶直接操作這個數據庫。將一個用戶添加到這個數據庫,且使它擁有 admin 庫上的名為 dbAdminAnyDatabase 的角色權限,這個用戶自動繼承所有數據庫的權限。一些特定的服務器端命令也只能從這個數據庫運行,比如關閉服務器。
- local : local 數據庫是不會被復制到其他分片的,因此可以用來存儲本地單臺服務器的任意 collection。一般不建議用戶直接使用 local 庫存儲任何數據,也不建議進行 CRUD 操作,因為數據無法被正常備份與恢復。
- config : 當 MongoDB 使用分片設置時,config 數據庫可用來保存分片的相關信息。
- test : 默認創建的測試庫,連接 mongod 服務時,如果不指定連接的具體數據庫,默認就會連接到 test 數據庫。
數據庫名可以是滿足以下條件的任意 UTF-8 字符串:
- 不能是空字符串
""
。 - 不得含有
' '
(空格)、.
、$
、/
、\
和\0
(空字符)。 - 應全部小寫。
- 最多 64 字節。
數據庫名最終會變成文件系統里的文件,這也就是有如此多限制的原因。
MongoDB 適合什么應用場景?
MongoDB 的優勢在于其數據模型和存儲引擎的靈活性、架構的可擴展性以及對強大的索引支持。
選用 MongoDB 應該充分考慮 MongoDB 的優勢,結合實際項目的需求來決定:
- 隨著項目的發展,使用類 JSON 格式(BSON)保存數據是否滿足項目需求?MongoDB 中的記錄就是一個 BSON 文檔,它是由鍵值對組成的數據結構,類似于 JSON 對象,是 MongoDB 中的基本數據單元。
- 是否需要大數據量的存儲?是否需要快速水平擴展?MongoDB 支持分片集群,可以很方便地添加更多的節點(實例),讓集群存儲更多的數據,具備更強的性能。
- 是否需要更多類型索引來滿足更多應用場景?MongoDB 支持多種類型的索引,包括單字段索引、復合索引、多鍵索引、哈希索引、文本索引、 地理位置索引等,每種類型的索引有不同的使用場合。
- ……
MongoDB 存儲引擎
MongoDB 支持哪些存儲引擎?
存儲引擎(Storage Engine)是數據庫的核心組件,負責管理數據在內存和磁盤中的存儲方式。
與 MySQL 一樣,MongoDB 采用的也是 插件式的存儲引擎架構 ,支持不同類型的存儲引擎,不同的存儲引擎解決不同場景的問題。在創建數據庫或集合時,可以指定存儲引擎。
插件式的存儲引擎架構可以實現 Server 層和存儲引擎層的解耦,可以支持多種存儲引擎,如 MySQL 既可以支持 B-Tree 結構的 InnoDB 存儲引擎,還可以支持 LSM 結構的 RocksDB 存儲引擎。
在存儲引擎剛出來的時候,默認是使用 MMAPV1 存儲引擎,MongoDB4.x 版本不再支持 MMAPv1 存儲引擎。
現在主要有下面這兩種存儲引擎:
- WiredTiger 存儲引擎:自 MongoDB 3.2 以后,默認的存儲引擎為 WiredTiger 存儲引擎 。非常適合大多數工作負載,建議用于新部署。WiredTiger 提供文檔級并發模型、檢查點和數據壓縮(后文會介紹到)等功能。
- In-Memory 存儲引擎:In-Memory 存儲引擎在 MongoDB Enterprise 中可用。它不是將文檔存儲在磁盤上,而是將它們保留在內存中以獲得更可預測的數據延遲。
此外,MongoDB 3.0 提供了 可插拔的存儲引擎 API ,允許第三方為 MongoDB 開發存儲引擎,這點和 MySQL 也比較類似。
WiredTiger 基于 LSM Tree 還是 B+ Tree?
目前絕大部分流行的數據庫存儲引擎都是基于 B/B+ Tree 或者 LSM(Log Structured Merge) Tree 來實現的。對于 NoSQL 數據庫來說,絕大部分(比如 HBase、Cassandra、RocksDB)都是基于 LSM 樹,MongoDB 不太一樣。
上面也說了,自 MongoDB 3.2 以后,默認的存儲引擎為 WiredTiger 存儲引擎。在 WiredTiger 引擎官網上,我們發現 WiredTiger 使用的是 B+ 樹作為其存儲結構:
WiredTiger maintains a table's data in memory using a data structure called a B-Tree ( B+ Tree to be specific), referring to the nodes of a B-Tree as pages. Internal pages carry only keys. The leaf pages store both keys and values.
此外,WiredTiger 還支持 LSM(Log Structured Merge) 樹作為存儲結構,MongoDB 在使用 WiredTiger 作為存儲引擎時,默認使用的是 B+ 樹。
如果想要了解 MongoDB 使用 B+ 樹的原因,可以看看這篇文章:【駁斥八股文系列】別瞎分析了,MongoDB 使用的是 B+ 樹,不是你們以為的 B 樹。
使用 B+ 樹時,WiredTiger 以 page 為基本單位往磁盤讀寫數據。B+ 樹的每個節點為一個 page,共有三種類型的 page:
- root page(根節點):B+ 樹的根節點。
- internal page(內部節點):不實際存儲數據的中間索引節點。
- leaf page(葉子節點):真正存儲數據的葉子節點,包含一個頁頭(page header)、塊頭(block header)和真正的數據(key/value),其中頁頭定義了頁的類型、頁中實際載荷數據的大小、頁中記錄條數等信息;塊頭定義了此頁的 checksum、塊在磁盤上的尋址位置等信息。
其整體結構如下圖所示:
如果想要深入研究學習 WiredTiger 存儲引擎,推薦閱讀 MongoDB 中文社區的?WiredTiger 存儲引擎系列