文章目錄
今天下載了《MongoDB The Definitive Guide》電子版,瀏覽了裡面的內容,還是挺豐富的。是官網文檔實際應用方面的一個補充。和官方文檔類似,介紹MongoDB的內部原理是少之又少,只有在附錄的一個章節中介紹了相關內容。
對於大多數的MongoDB的使用者來說,MongoDB就像是一個大黑盒,但是如果你能夠瞭解到MongoDB內部一些構造的話,將有利於你更好地理解和使用MongoDB。
BSON
在MongoDB中,文檔是對資料的抽象,它被使用在Client端和Server端的互動中。所有的Client端(各種語言的Driver)都會使用這種抽象,它的表現形式就是我們常說的BSON(Binary JSON )。
BSON是一個輕量級的位元據格式。MongoDB能夠使用BSON,並將BSON作為資料的儲存存放在磁碟中。
當Client端要將寫入文檔,使用查詢等等操作時,需要將文檔編碼為BSON格式,然後再發送給Server端。同樣,Server端的返回結果也是編碼為BSON格式再放回給Client端的。
使用BSON格式出於以下3種目的:
效率
BSON是為效率而設計的,它只需要使用很少的空間。即使在最壞的情況下,BSON格式也比JSON格式再最好的情況下儲存效率高。
傳輸性
在某些情況下,BSON會犧牲額外的空間讓資料的傳輸更加方便。比如,字串的傳輸的首碼會標識字串的長度,而不是在字串的末尾打上結束的標記。這樣的傳輸形式有利於MongoDB修改傳輸的資料。
效能
最後,BSON格式的編碼和解碼都是非常快速的。它使用了C風格的資料表現形式,這樣在各種語言中都可以高效地使用。
更多關於BSON的介紹,可以參考:http://www.bsonspec.org。
寫入協議
Client端訪問Server端使用了輕量級的TCP/IP寫入協議。這種協議在MongoDB Wiki中有詳細介紹,它其實是在BSON資料上面做了一層簡單的封裝。比如說,寫入資料的命令中包含了1個20位元組的訊息頭(由訊息的長度和寫入命令標識組成),需要寫入的Collection名稱和需要寫入的資料。
資料檔案
在MongoDB的資料檔案夾中(預設路徑是/data/db)由構成資料庫的所有檔案。每一個資料庫都包含一個.ns檔案和一些資料檔案,其中資料檔案會隨著資料量的增加而變多。所以如果有一個資料庫名字叫做foo,那麼構成foo這個資料庫的檔案就會由foo.ns,foo.0,foo.1,foo.2等等組成。
資料檔案每新增一次,大小都會是上一個資料檔案的2倍,每個資料檔案最大2G。這樣的設計有利於防止資料量較小的資料庫浪費過多的空間,同時又能保證資料量較大的資料庫有相應的空間使用。
MongoDB會使用預分配方式來保證寫入效能的穩定(這種方式可以使用--noprealloc關閉)。預分配在後台進行,並且每個預分配的檔案都用0進行填充。這會讓MongoDB始終保持額外的空間和空餘的資料檔案,從而避免了資料增長過快而帶來的分配磁碟空間引起的阻塞。
名字空間和盤區
每一個資料庫都由多個名字空間組成,每一個名字空間儲存了相應類型的資料。資料庫中的每一個Collection都有各自對應的名字空間,索引檔案同樣也有名字空間。所有名字空間的中繼資料都儲存在.ns檔案中。
名字空間中的資料在磁碟中分為多個區間,這個叫做盤區。在中,foo這個資料庫包含3個資料檔案,第三個資料檔案屬於空的預分配檔案。頭兩個資料檔案被分為了相應的盤區對應不同的名字空間。
顯示了名字空間和盤區的相關特點。每一個名字空間可以包含多個不同的盤區,這些盤區並不是連續的。與資料檔案的增長相同,每一個名字空間對應的盤區大小的也是隨著分配的次數不斷增長的。這樣做的目的是為了平衡名字空間浪費的空間與保持某一個名字空間中資料的連續性。中還有一個需要注意的名字空間:$freelist,這個名字空間用於記錄不再使用的盤區(被刪除的Collection或索引)。每當名字空間需要分配新的盤區的時候,都會先查看$freelist是否有大小合適的盤區可以使用。
記憶體映射儲存引擎
MongoDB目前支援的儲存引擎為記憶體映射引擎。當MongoDB啟動的時候,會將所有的資料檔案映射到記憶體中,然後作業系統會託管所有的磁碟操作。這種儲存引擎有以下幾種特點:
* MongoDB中關於記憶體管理的代碼非常精簡,畢竟相關的工作已經有作業系統進行託管。
* MongoDB伺服器使用的虛擬記憶體將非常巨大,並將超過整個資料檔案的大小。不用擔心,作業系統會去處理這一切。
* MongoDB無法控制資料寫入磁碟的順序,這樣將導致MongoDB無法實現writeahead日誌的特性。所以,如果MongoDB希望提供一種durability的特性(這一特性可以參考我寫的關於Cassandra文章:http://www.cnblogs.com/gpcuster/tag/Cassandra/),需要實現另外一種儲存引擎。
* 32位系統的MongoDB伺服器每一個Mongod執行個體只能使用2G的資料檔案。這是由於地址指標只能支援32位。
其他
在《MongoDB The Definitive Guide》中介紹的MongoDB內部構造只有這麼多,如果真要把它說清楚,可能需要另外一本書來專門講述了。比如內部的JS解析,查詢的最佳化,索引的建立等等。有興趣的朋友可以直接參考原始碼:)