天天看點

《MongoDB管理與開發精要》——2.1節體系結構

2.1 體系結構

一個運作着的mongodb資料庫可以看作一個mongodb server,該server由執行個體和資料庫組成。一般情況下,一個mongodb server機器上包含一個執行個體和多個與之對應的資料庫,但是在特殊情況下,如硬體投入成本有限或特殊的應用需求,也允許一個server機器上有多個執行個體和多個資料庫。

mongodb中一系列實體檔案(資料檔案、日志檔案等)的集合或與之對應的邏輯結構(集合、文檔等)稱為資料庫。簡單來說,資料庫是由一系列與磁盤有關的實體檔案組成的。

2.1.1 資料邏輯結構

mongodb資料邏輯結構是面向使用者的,使用者使用mongodb開發應用程式使用的就是邏輯結構。mongodb邏輯結構是一種層次結構,如圖2-1所示,主要由文檔(document)、集合(collection)、資料庫(database)組成。

文檔、集合、資料庫三部分的關系如下:

mongodb的文檔相當于關系資料庫中的一條記錄。

多個文檔組成一個集合,相當于關系資料庫的表。

多個集合邏輯上組織在一起就是資料庫。

一個mongodb執行個體支援多個資料庫。

《MongoDB管理與開發精要》——2.1節體系結構

2.1.2 資料存儲結構

mongodb存儲資料的預設目錄是/data/db,這個目錄負責存儲所有mongodb的資料檔案。在mongodb内部,每個資料庫都包含一個ns檔案和一些資料檔案,這些資料檔案會随着資料量的增加而變得越來越多。例如,系統中有一個名為kon的資料庫,那麼構成kon資料庫的檔案就由kon.ns、kon.0、kon.1、kon.2 等組成,如下面的代碼所示:

mongodb内部有預配置設定空間的機制,每個預配置設定的檔案都用0進行填充,這使mongodb始終保持額外的空間和空餘的資料檔案,有效避免了由于資料暴增而帶來的磁盤壓力過大的問題。如果想避免預配置設定,可以在mongod啟動時,加上參數“--noprealloc”,這樣,系統的預配置設定機制就失效了。

由于表中資料量的增加,資料檔案每配置設定一次,它的大小都會是上一個資料檔案大小的2倍,每個資料檔案最大2gb,這樣的機制有利于防止較小的資料庫浪費過多的磁盤空間,同時又能保證較大的資料庫有相應的預留白間使用。

資料庫的每張表都對應一個命名空間,每個索引也有對應的命名空間,這些命名空間的中繼資料都集中在“*.ns”檔案中。

圖2-2是預配置設定機制的示意圖,kon資料庫包含3個檔案,用于存儲表和索引資料,kon.2檔案屬于預配置設定的空檔案。kon.0和kon.1這兩個資料檔案分為相應的盤區對應不同的命名空間。

《MongoDB管理與開發精要》——2.1節體系結構

圖2-2顯示了命名空間和盤區的關系。每個命名空間可以包含多個不同的盤區,這些盤區并不是連續的。與資料檔案的增長相同,每一個命名空間對應的盤區大小也是随着配置設定的次數不斷增長的,這樣做的目的不僅僅是為了平衡命名空間浪費的磁盤空間,也是為了保持某一個命名空間中資料的連續性。

圖2-2中還有一個需要注意的命名空間:$freelist,這個命名空間用于記錄不再使用的盤區(被删除的collection或索引)。每當命名空間需要配置設定新的盤區的時候,都會先檢視$freelist是否有大小合适的盤區可以使用,這樣就能回收空閑的磁盤空間。

2.1.3 日志系統

任何一種資料庫都有各種各樣的日志,mongodb也不例外。mongodb中有幾種日志,分别是系統日志、journal日志、oplog主從日志、慢查詢日志等。這些日志記錄着mongodb資料庫不同方面的蹤迹。下面分别介紹這4種日志。

系統日志

系統日志在mongodb資料庫中很重要,它記錄着mongodb啟動和停止的操作,以及伺服器在運作過程中發生的任何異常資訊。

配置系統日志的方法比較簡單,隻需要在啟動mongod時指定一個logpath參數即可,例如:

系統日志會向logpath指定的檔案中持續追加。

journal日志

journal日志通過預寫式的redo日志為mongodb增加了額外的可靠性保障。開啟該功能時,資料的更新會先寫入journal日志,定期集中送出(目前是每100ms送出一次),然後在真實資料上執行這些變更。如果伺服器安全關閉,日志會被清除。在伺服器啟動時,如果存在 journal日志,則會執行送出。這保證了那些已經寫入journal日志但在伺服器崩潰前還沒有送出的操作能在使用者連接配接伺服器前被執行,兩次送出之間的 100ms時間視窗,在未來的版本中有望被縮小。

啟用資料庫的journal功能非常簡單,隻需在mongod後面指定journal參數即可,例如:

這樣,系統的journal資訊都會放到資料庫目錄(預設是/data/db/)的journal檔案夾中。

oplog主從日志

mongodb的高可用複制政策中有一種叫做replica sets。replica sets複制過程中一個伺服器充當主伺服器,而一個或多個伺服器充當從伺服器,主伺服器将更新寫入一個本地的collection中,這個collection記錄着發生在主伺服器的更新操作,并将這些操作分發到從伺服器上。

這個日志是一個capped collection(第5章會專門講解這個概念)且有大小之分,是以最好在mongod啟動時配置好大小(機關:mb)。例如以下語句:

慢查詢日志

慢查詢日志記錄了執行時間超過所設定時間門檻值的操作語句。慢查詢日志對于發現性能有問題的語句很有幫助,建議開啟此功能并經常分析該日志的内容。

要想配置這個功能隻需要在mongod啟動時指定profile參數即可。例如,想要将超過5秒的操作都記錄,可以使用如下語句:

mongod --profile=1 --slowms=5

系統運作一段時間後, 可以通過檢視db.system.profile這個collection來擷取慢日志資訊。

2.1.4 中繼資料的存儲

中繼資料是一個預留白間,在對資料庫或應用程式結構執行修改時,其内容可以由資料庫自動更新。中繼資料是系統中各類資料描述的集合,是執行詳細的資料收集和資料分析的主要途徑。

中繼資料最重要的作用是作為分析階段的工具。任何字典最重要的用途都是查詢,在結構化分析中,中繼資料的作用是給資料流圖上的每個節點加以定義和說明。換句話說,資料流圖上所有節點的定義和解釋的集合就是中繼資料,而且在中繼資料中建立嚴密一緻的定義有助于提高需求分析人員和使用者溝通的效率。

mongodb跟其他資料庫一樣,有專門存儲中繼資料的系統表。.system.* namespaces是一個特殊的對象,其中存儲資料庫的系統資訊,通過這些表使用者可以大概了解系統中資料庫對象的情況,例如:

system.namespaces (存儲命名空間資訊)

system.indexes (存儲索引資訊)

system.profile (存儲優化器資訊)

system.users (存儲使用者資訊)

local.sources (存儲複制集的配置資訊和狀态資訊)

其他的命名空間和索引資訊都存儲在database.ns檔案中,并且對使用者是封裝的。

注意 “$”是一個保留字元,不要在命名空間和列名中使用它。

2.1.5 資料類型

mongodb中的文檔可以了解為json 類型的對象。json的格式很簡單,隻支援6種資料類型,容易了解、解析和記憶。

mongodb在采取了json鍵值對的同時,還支援很多額外的資料類型。雖然不同的語言支援的類型有所不同,但還是有很多共同的類型,如表2-2所示。

表2-2 mongodb支援的資料類型

《MongoDB管理與開發精要》——2.1節體系結構

盡管這些類型在一般場合下是足夠的,但還是存在其他很多的資料類型json是不支援的。例如json 沒有日期類型,對日期的處理要煩瑣一些;它有數字類型,但無法區分浮點型和整型的數值,更不用說嚴格區分32位和64位了;此外,正規表達式和函數類型也無法表現。

接下來将介紹mongodb的主要資料類型。

number

javascript 有一個number 類型,對應的mongodb 有3個資料類型(4位元組整數、8位元組整數、8位元組浮點數)。shell 中的數字預設為浮點數。這意味着,如果從資料庫取出一個4位元組整數存進去,即使沒有改變它,也會變成8位元組浮點數。是以,建議不要把整個document插入到mongodb中。

另外的一個問題是,一個8位元組的整數是不能用8位元組的浮點數來表示的。是以,如果儲存一個8位元組整數,要在shell裡檢視它,shell 将會顯示為一個嵌套的document來精确地描述它。在shell 裡面檢視的代碼如下:

這個數字在資料庫裡不會改變,這個嵌套的文檔隻是用shell顯示一個8位元組整數的浮點近似值,并且隻有一個key。

如果插入一個不能用浮點數來精确表示的8位元組整數,shell會加上2個key:top 和bottom,分别代表高位和低位的32位值。例如9223372036854775807,如下面的代碼所示:

date

javascript的資料類型中,date 對象用來表示mongodb 的日期類型。建立日期對象要用 new date(),而不是用date(),後者隻是傳回一個字元串,并不是一個date對象,如下面的代碼所示:

這不是mongodb的問題,因為javascript就是這樣處理的,如果不注意就會弄混字元串和日期類型,在删除、更新查詢時造成問題。

shell裡用本地區域設定來顯示日期,但在資料庫裡隻是記錄從紀元開始到現在所過去的毫秒數,是以并沒有把區域設定儲存進去。

array

數組的值可以進行有序處理,類似于清單、堆棧、隊列;也可以無序處理,類似于集合。如下面的代碼所示:

{"things" : ["pie", 3.14]}

這裡看到,數組成員類型是允許不一樣的,可以是任意的類型,包括嵌套的數組。

mongodb的一個好處是,它了解數組裡的結構并知道怎麼進入内部執行操作,是以可以執行查詢操作和索引操作。例如上例中,mongodb可以查詢所有文檔中things包括3.14的文檔,也可以為things建立索引以提高查詢速度。mongodb還允許數組内部元素的原子更新,例如把pie改為pi。

embedded document

嵌套文檔就是将一個key 的值表示為另外一個文檔,這樣可以讓document 看起來比一個平面的結構更自然。

例如,用一個文檔表示一個人,其中有他的位址資訊,嵌套表示如下面的代碼所示:

跟數組一樣,mongodb也了解嵌套文檔的結構,可以執行内部的查詢和更新。

如上所示,嵌套文檔改變了處理資料的方式。傳統資料庫中這兩個資訊将會存放在兩個表的兩條記錄中,但mongodb可以用一個文檔來表示。從另一方面來看,這種方式不是很正規,會造成資料備援。假設一個位址兩個人使用,那麼關系資料庫裡可以用一條記錄表示,通過join來關聯,但mongodb隻能分别存放、分别更新。