天天看點

MongoDB之父:MongoDB勝過BigTableMongoDB與CouchDB全方位對比Mongodb GridFS 介紹MongoDB:下一代MySQL?MongoDB安全性初探白話MongoDB(一)MongoDB調查總結

MongoDB之父:MongoDB勝過BigTable

Dwight Merriman和他的團隊,包括ShopWiki的創始人Eliot Horowitz參加了在紐約10gen啟動MongoDB的儀式。現在該公司除了擔任該開源項目的主要營運者之外,還提供支援、教育訓練和咨詢服務。10gen在舊金山舉辦了第二屆開發者大會,Merriman在上午的大會做了主題演講,主要介紹了MongoDB的起源,并解釋了為何要建立這樣的資料庫。

“在2007年底,當時的想法是建構一個用于開發、托管并具有自動縮放Web應用程式的線上服務”,談到MongoDB誕生之目的時,Merriman介紹道。“但是不同于Google App Engine的是,這項服務完全建立在一個開放源代碼的軟體平台之上。”是以,在關注了Google Bigtable架構很長一段時間後,Merriman和他的團隊注意到,尚沒有一個開源的資料庫平台适合這種服務,這興許是個機會。

“我們意識到很多現有的資料庫并不真正具備‘雲計算’的特性。例如彈性、可擴充性以及易管理性。這些特性能夠為開發者和營運者帶來便利,而MySQL還不完全具備這些特點。

是以,Dwight Merriman以及他的團隊的目标是建構一個全新的資料庫。新的資料庫将會放棄大家所熟悉的關系資料庫模型,且是适合現代網絡應用并基于分布式的平台。高度事務性的系統可以幫助解決一些棘手的問題,同時還支援雲計算架構的伸縮性。Merriman解釋到。經過一年的不斷努力,這個資料庫已經比較完善。他們将它設計為具有為“雲計算服務”潛力的資料庫。而且還會不斷的完善,因為MongoDB本身就是一個開源資料庫。

在開源的、面向文檔的資料庫中,MongoDB經常被譽為具有RDBMS功能的NoSQL資料庫。MongoDB還帶有互動式shell,這使得通路其資料存儲變得簡單,且其對于分塊的即裝即用的支援能夠使高可伸縮性跨多個節點。

據悉,MongoDB的API是JSON對象和JavaScript函數的本地混合物。通過shell程式開發人員可與MongoDB進行互動,即允許指令行參數,或通過使用語言驅動程式來通路資料存儲執行個體。這裡不存在類JDBC驅動程式,這意味着開發人員不必處理ResultSet或PreparedStatement。

而速度是 MongoDB 的另外一個優勢,主要是由于它處理寫入的方式:它們存儲在記憶體中,然後通過背景線程寫入磁盤。

“由于使用者不容易在大規模環境下作分布式的連結,并且在分布式環境下很難做快速的大規模部署,是以,使用者需要一些輔助的東西”,Memmiman解釋道。

最後他表示同樣重要的是為了限制資料庫的事務語義你可以使用分布式事務。但當你在1000台機器上運作時它不會那麼快。例如銀行或會計系統。傳統的關系型資料庫目前還是更适用于需要大量原子性複雜事務的應用程式。(李智/譯)

MongoDB與CouchDB全方位對比

本文見于MongoDB官方網站,MongoDB與CouchDB很相似,他們都是文檔型存儲,資料存儲格式都是JSON型的,都使用Javascript進行操作,都支援Map/Reduce。但是其實二者有着很多本質的差別,本文透過現象追尋本質,讓你更好的了解MongoDB與CouchDB。

1.MVCC(Multiversionconcurrency control)

MongoDB與CouchDB的一大差別就是CouchDB是一個MVCC的系統,而MongoDB是一個update-in-place的系統。這二者的差別就是,MongoDB進行寫操作時都是即時完成寫操作,寫操作成功則資料就寫成功了,而CouchDB一個支援多版本控制的系統,此類系統通常支援多個結點寫,而系統會檢測到多個系統的寫操作之間的沖突并以一定的算法規則予以解決。

2.水準擴充性

在擴充性方面,CouchDB使用replication去做,而MongoDB的replication僅僅用來增強資料的可靠性,MongoDB在實作水準擴充性方面使用的是Sharding。(據說CouchDB也有開發分片功能的計劃)

3.資料查詢操作

這個差別在使用者接口上了,MongoDB與傳統的資料庫系統類似,支援動态查詢,即使在沒有建立索引的行上,也能進行任意的查詢。而CouchDB不同,CouchDB不支援動态查詢,你必須為你的每一個查詢模式建立相應的view,并在此view的基礎上進行查詢。

4.原子性

這一點上兩者比較一緻,都支援針對行的原子性修改(concurrentmodifications of single documents),但不支援更多的複雜事務操作。

5.資料可靠性

CouchDB是一個”crash-only”的系統,你可以在任何時候停掉CouchDB并能保證資料的一緻性。而MongoDB在不正常的停掉後需要運repairDatabase()指令來修複資料檔案,在1.7.5版本後支援單機可靠的–dur指令。

6.Map/Reduce

MongoDB和CouchDB都支援Map/Reduce,不同的是MongoDB隻有在資料統計操作中會用到,而CouchDB在變通查詢時也是使用Map/Reduce。

7.使用 javascript

MongoDB和CouchDB都支援javascript,CouchDb用javascript來建立view。MongoDB使用JSON作為普通資料庫操作的表達式。當然你也可以在操作中包含javascript語句。MongoDB還支援服務端的javascript腳本(running arbitrary javascript functions server-side),當然,MongoDB的Map/Reduce函數也是javascript格式的。

8.REST

CouchDB是一個RESTFul的資料庫,其操作完全走HTTP協定,而MongoDB是走的自己的二進制協定。MongoDB Server在啟動時可以開放一個HTTP的接口供狀态監控。

9.性能

此處主要列舉了MongoDB自己具有高性能的原因

采用二進制協定,而非CouchDB REST的HTTP協定

使用Momary Map記憶體映射的做法

collection-oriented,面向集合的存儲,同一個collection的資料是連續存儲的

update-in-place直接修改,而非使用MVCC的機制

使用C++編寫

10.适用場景

如果你在建構一個 Lotus Notes型的應用,我們推薦使用CouchDB,主要是由于它的MVCC機制。另外如果我們需要master-master的架構,需要基于地理位置的資料分布,或者在資料結點可能不線上的情況下,我們推薦使用CouchDB。

如果你需要高性能的存儲服務,那我們推薦MongoDB,比如用于存儲大型網站的使用者個人資訊,比如用于建構在其它存儲層之上的Cache層。

如果你的需求中有大量update操作,那麼使用MongoDB吧。就像我們在例子updating real time analytics counters中的一樣,對于那種經常變化的資料,比如浏覽量,通路數之類的資料存儲。

Mongodb GridFS 介紹

MongoDB GridFS 是MongoDB用于檔案存儲的子產品,本文簡單介紹了期用法。

mongodb GridFS 性能

性能, 網評還不錯.

不過在生産環境中,國外有用于存儲視訊流的.

GridFS的一個優點是可以存儲上百萬的檔案而無需擔心擴容性.

通過同步複制,可以解決分布式檔案的備份問題.

通過ARP-ping可以實作一個雙機熱備切換,類mysql的mysql master master replic

使用Nginx module

http://github.com/mdirolf/nginx-gridfs

這是gridfs的nginx module. 可以通過nginx直接通路讀取mongo gridfs中的檔案.

和nginx對應的mogilefs module類似.

優點: 由于直接通過nginx,速度是最快的.

缺點: 隻能通過file_path來查找,目前不支援_id來查找.是以必須在file_path上

建立索引.

其他一些資訊:

1.通過runcommand可以直接在mongodb端運作處理腳本. 比如像mapreduce,或者一

些需要讀取資料然後進行處理的.

這些command則是使用javascript方式來編寫的,很容易. 好處就是避免了資料在服

務端和用戶端之間的讀取和傳輸,

提高效率.

2. sharding

sharding在目前開發版中已經具備,但還不成熟. 但是可以自己實作sharding比較

好.因為目前的sharding還是比較硬性的.

3.靈活使用magic操作符和upsert,比如$inc,$all,$in 等等

MongoDB:下一代MySQL?

MongoDB的特性

  • 簡單的查詢語句,沒有Join操作
  • 文檔型存儲,其資料是用二進制的Json格式Bson存儲的。其資料就像Ruby的hashes,或者Python的字典,或者PHP的數組
  • Sharding,MongoDB提供auto-sharding實作資料的擴充性
  • GridFS,MongoDB的提供的檔案存儲API
  • 數組索引,你可以對文檔中的某個數組屬性建立索引
  • MapReduce,可以用于進行複雜的統計和并行計算
  • 高性能,通過使用mmap和定時fsync的方法,避免了頻繁IO,使其性能更高

MongoDB的優點

  • 高性能,速度非常快(如果你的記憶體足夠的話)
  • 沒有固定的表結構,不用為了修改表結構而進行資料遷移
  • 查詢語言簡單,容易上手
  • 使用Sharding實作水準擴充
  • 部署友善

使用MongoDB,你得記住以下幾點:

  • MongoDB 假設你有大磁盤空間
  • MongoDB 假設你的記憶體也足夠大于放下你的熱資料
  • MongoDB 假設你是部署在64位系統上的(32位有2G的限制,試用還可以)
  • MongoDB 假設你的系統是little-endian的
  • MongoDB 假設你有多台機器(并不專注于單機可靠性)
  • MongoDB 假設你希望用安全換性能,同時允許你用性能換安全

MongoDB在下面領域不太擅長

  • 不太穩定,特别是auto-sharding目前還有很多問題
  • 不支援SQL,這意味着你很多通過SQL接口的工具不再适用
  • 持久化,MongoDB單機可靠性不太好,當機可能丢失一段時間的資料
  • 相關文檔比較少,新功能都有這個問題
  • 相關人才比較難找,這也是新功能的問題之一

MongoDB安全性初探

本文是一篇轉載文章,文章主要介紹了MongoDB 安全性方面的知識,包括 MongoDB 安全配制、認證機制及認證的網絡流程,也簡單介紹了可能利用JavaScript引擎執行腳本攻擊的可能。

MongoDB,這麼火的玩意其實早就想好好研究一下了。之前一直沒空仔細學學新的東西,總是感覺精力不足。這次趁着買了一本書,就零零散散地在VPS上搭建、測試、看實作代碼。感覺也蠻有意思的一個資料庫。雖然感覺它非常簡單,尤其是看代碼的時候更是感覺如此。但這不也是另一個KISS的典範麼,還是簡單但是實用的東西最能流行。

既然都看了其實作,也不能不産出點什麼。正好多年沒更新博文,就簡單分析一下 MongoDB 的安全性,湊個數先。

預設配置的安全情況

在預設情況下,mongod是監聽在0.0.0.0之上的。而任何用戶端都可以直接連接配接27017,且沒有認證。好處是,開發人員或dba可以即時上手,不用擔心被一堆配置弄的心煩意亂。壞處是,顯而易見,如果你直接在公網伺服器上如此搭建MongoDB,那麼所有人都可以直接通路并修改你的資料庫資料了。

預設情況下,mongod也是沒有管理者賬戶的。是以除非你在admin資料庫中使用db.addUser()指令添加了管理者帳号,且使用–auth參數啟動mongod,否則在資料庫中任何人都可以無需認證執行所有指令。包括delete和shutdown。

此外,mongod還會預設監聽28017端口,同樣是綁定所有ip。這是一個mongod自帶的web監控界面。從中可以擷取到資料庫目前連接配接、log、狀态、運作系統等資訊。如果你開啟了–rest參數,甚至可以直接通過web界面查詢資料,執行mongod指令。

我試着花了一個晚上掃描了國内一個B段,國外一個B段。結果是國外開了78個MongoDB,而國内有60台。其中我随意挑選了10台嘗試連接配接,而隻有一台機器加了管理者賬戶做了認證,其他則全都是不設防的城市。可見其問題還是比較嚴重的。

其實MongoDB本身有非常詳細的安全配置準則,顯然他也是想到了,然而他是将安全的任務推給使用者去解決,這本身的政策就是偏向易用性的,對于安全性,則得靠邊站了。

使用者資訊儲存及認證過程

類似MySQL将系統使用者資訊儲存在mysql.user表。MongoDB也将系統使用者的username、pwd儲存在admin.system.users集合中。其中pwd =md5(username + “:mongo:” + real_password)。這本身并沒有什麼問題。username和:mongo:相當于對原密碼加了一個salt值,即使攻擊者擷取了資料庫中儲存的md5 hash,也沒法簡單的從彩虹表中查出原始密碼。

我們再來看看MongoDB對用戶端的認證互動是如何實作的。mongo client和server互動都是基于明文的,是以很容易被網絡嗅探等方式抓取。這裡我們使用資料庫自帶的mongosniff,可以直接dump出用戶端和服務端的所有互動資料包:

[[email protected] bin]# ./mongosniff --source NET lo      
sniffing 27017      
...//省略開頭的資料包,直接看看認證流程。以下就是當使用者輸入db.auth(username, real_passwd)後發生的互動。      
127.0.0.1:34142  -->> 127.0.0.1:27017 admin.  62 bytes  id:8        8      
        query: { getnonce: 1.0 }  ntoreturn: -1 ntoskip: 0      
127.0.0.1:27017  <<--  127.0.0.1:34142   81 bytes  id:7 7 - 8      
        reply n:1 cursorId: 0      
        { nonce: "df97182fb47bd6d0", ok: 1.0 }      
127.0.0.1:34142  -->> 127.0.0.1:27017 admin.  152 bytes  id:9       9      
        query: { authenticate: 1.0, user: "admin", nonce: "df97182fb47bd6d0", key: "3d839522b547931057284b6e1cd3a567" }  ntoreturn: -1 ntoskip: 0      
127.0.0.1:27017  <<--  127.0.0.1:34142   53 bytes  id:8 8 - 9      
        reply n:1 cursorId: 0      
        { ok: 1.0 }      
  • 第一步,client向server發送一個指令getnonce,向server申請一個随機值nonce,server傳回一個16位的nonce。這裡每次傳回的值都不相同。
  • 第二步,client将使用者輸入的明文密碼通過算法生成一個key,即 key = md5(nonce + username + md5(username + “:mongo:” + real_passwd)),并将之連同使用者名、nonce一起傳回給server,server收到資料,首先比對nonce是否為上次生成的nonce,然後比對 key == md5(nonce + username + pwd)。如果相同,則驗證通過。

由于至始至終沒有密碼hash在網絡上傳輸,而是使用了類似挑戰的機制,且每一次nonce的值都不同,是以即使攻擊者截取到key的值,也沒用辦法通過重播攻擊通過認證。

然而當攻擊者擷取了資料庫中儲存的pwd hash,則認證機制就不會起到作用了。即使攻擊者沒有破解出pwd hash對應的密碼原文。但是仍然可以通過發送md5(nonce + username + pwd)的方式直接通過server認證。這裡實際上server是将使用者的pwd hash當作了真正的密碼去驗證,并沒有基于原文密碼驗證。在這點上和我之前分析的mysql的認證機制其實沒什麼本質差別。當然或許這個也不算是認證機制的弱點,但是畢竟要擷取MongoDB的username和pwd的可能性會更大一些。

然而在Web的監控界面的認證中則有一些不同。當client來源不是localhost,這裡的使用者認證過程是基于HTTP 401的。其過程與mongo認證大同小異。但是一個主要差別是:這裡的nonce并沒有随機化,而是每次都是預設為”abc”。

利用這個特點,如果攻擊者抓取了管理者一次成功的登入,那麼他就可以重放這個資料包,直接進入Web監控頁面。

同樣,攻擊者還可以通過此接口直接暴力破解 mongo 的使用者名密碼。實際上27017和28017都沒有對密碼猜解做限制,但Web由于無需每次擷取nonce,是以将會更為簡便。

JavaScript的執行與保護

MongoDB 本身最大的特點之一,就是他是使用 JavaScript 語言作為指令驅動的。黑客會比較關注這一點,因為其指令的支援程度,就是擷取 MongoDB 權限之後是否能進一步滲透的關鍵。

JavaScript 本身的标準庫其實相當弱。無論是 spidermonkey 或者是 v8 引擎,其實都沒有系統操作、檔案操作相關的支援。對此,MongoDB做了一定的擴充。可以看到,ls/cat/cd/hostname 甚至 runProgram 都已經在 JavaScript 的上下文中有實作。看到這裡是不是已經迫不及待了?mongoshell 中試一下輸入ls(“./”),看看傳回。

等等?結果怎麼這麼熟悉?哈哈,沒錯,其實這些 api 都是在 client 的上下文中實作的。一個小小玩笑。

那麼在server端是否可以執行js呢?答案是肯定的。利用 db.eval(code) ——實際上底層執行的是db.$cmd.findOne({$eval: code}) —— 可以在server端執行我們的js代碼。

當然在server端也有js的上下文擴充。顯然 mongod 考慮到了安全問題(也可能是其他原因),是以在這裡并沒有提供client中這麼強大的功能。當然 MongoDB 還在不斷更新,長期關注這個list,說不定以後就有類似 load_file/exec 之類的實作。

一勞永逸解決服務端js執行帶來的問題可以使用noscripting參數。直接禁止server-side的js代碼執行功能。

白話MongoDB(一)

按照官方的說法,MongoDB是一種可擴充的高性能的開源的面向文檔(document-oriented )的資料庫,采用C++開發。注意mongo不是mango(芒果),這個詞是從humongous中截取出來的,其野心不言而明,直指海量資料存儲。和其他很多NoSQL不太一樣,MongoDB背後有一個專門的商業公司在提供支援和推廣,有點類似MySQL AB的模式。這一系列文章,是為入門者寫的,已經對NoSQL和MongoDB有一定研究和經驗的,可以略過,或者看看如有疏漏,請留言指出。

面向文檔,那麼什麼是文檔呢?很明顯這不是我們常見的word文檔。這裡說的文檔,是一種可以嵌套的資料集合。從關系資料庫的範式的概念來說,嵌套是明顯的反範式設計。範式設計的好處是消除了依賴,但是增加了關聯,查詢需要通過關聯兩張或者多張表來獲得所需要的全部資料,但是更改操作是原子的,隻需要修改一個地方即可。反範式則是增加了資料備援來提升查詢性能,但更新操作可能需要更新備援的多處資料,需要注意一緻性的問題。

一個典型的例子,如blog,關系資料庫中一般可以把文章設計為一張表,評論設計為一張表,那麼在頁面需要展示一篇文章和其對應的評論的時候,就需要關聯查詢文章表和評論表。但是面向文檔的設計,可以将評論作為文章的一個嵌套文檔存放在一起,這不但省去了關聯查詢,由于存儲在一起,查詢的性能也可以做到更好。

MongoDB的面向文檔采用的是BSON,一種類似JSON的格式,但是是二進制序列化的。如上面提到的blog的文章和評論,可以做如下設計:

{ 'id':1, 'author':'NinGoo', 'title':'白話MongoDB(一)', 'content':'按照官方的說法,此處省略一萬字',

    comment:[ {'comment-author':'宋兵甲', 'comment-content':'有木有' } ,

              {'comment-author':'尼瑪','comment-content':'傷不起啊' }

            ]

}

1. 相關資料存放在一起,針對性的查詢可以消除join,性能比分散存儲要高且友善。

2. 整個結構清晰自解析。所有字段名和值都存儲,是以不需要提前設計結構,key的名字和數目可以任意指定,也就是所謂的schema-free。

3. 由于字段名在每一行每一列都需要重複存在,會帶來一些額外的存儲消耗,這在海量資料及字段較多的時候也需要考慮。

4. 一個document的長度有限,1.7.2之前是4MB,目前是8MB,以後可能增長到32MB。如果有更大的資料,可以使用MongoDB底層的GridFS直接作為檔案存儲。

5. 如果需要查找某個評論者的所有評論,則相對困難。當然,MongoDB支援任意key的索引,這也不是什麼大問題。

像上面的一個結構,為一個文檔(document),相當于關系資料庫中的一行記錄,多個文檔組成一個集合(collection),相當于關系資料庫的表。多個集合(collection),邏輯上組織在一起,就是資料庫(database),一個MongoDB執行個體支援多個資料庫(database)。

大部分的NoSQL産品,為追求性能,一緻性等,一般隻能支援簡單的基于row-key的單條或者範圍查詢,但是MongoDB可以針對任意列的key建立索引,甚至是内嵌文檔裡的key,從支援的查詢的靈活性上來看,更接近傳統的關系資料庫,同時還能在性能上向NoSQL看齊,加上支援複制,自動分片和Map/Reduce等功能,非常的吸引眼球,正在成為一款熱門的海量存儲産品。其背後的商業支援公司10gen,也正在不遺餘力的推廣,前不久還在北京專門組織了一場技術交流會。在其首頁列舉的典型客戶裡,包括foursquare,sourceforge,github等知名網際網路公司和應用,當然,也包括淘寶網。

MongoDB調查總結

與關系型資料庫相比,MongoDB的優點:

①弱一緻性(最終一緻),更能保證使用者的通路速度:

舉例來說,在傳統的關系型資料庫中,一個COUNT類型的操作會鎖定資料集,這樣可以保證得到“目前”情況下的精确值。這在某些情況下,例如通過ATM檢視賬戶資訊的時候很重要,但對于Wordnik來說,資料是不斷更新和增長的,這種“精确”的保證幾乎沒有任何意義,反而會産生很大的延遲。他們需要的是一個“大約”的數字以及更快的處理速度。

但某些情況下MongoDB會鎖住資料庫。如果此時正有數百個請求,則它們會堆積起來,造成許多問題。我們使用了下面的優化方式來避免鎖定:

每次更新前,我們會先查詢記錄。查詢操作會将對象放入記憶體,于是更新則會盡可能的迅速。在主/從部署方案中,從節點可以使用“-pretouch”參數運作,這也可以得到相同的效果。

使用多個mongod程序。我們根據通路模式将資料庫拆分成多個程序。

②文檔結構的存儲方式,能夠更便捷的擷取資料。

對于一個層級式的資料結構來說,如果要将這樣的資料使用扁平式的,表狀的結構來儲存資料,這無論是在查詢還是擷取資料時都十分困難。

舉例1:

就拿一個“字典項”來說,雖然并不十分複雜,但還是會關系到“定義”、“詞性”、“發音”或是“引用”等内容。大部分工程師會将這種模型使用關系型資料庫中的主鍵和外鍵表現出來,但把它看作一個“文檔”而不是“一系列有關系的表”豈不更好?使用“dictionary.definition.partOfSpeech='noun'”來查詢也比表之間一系列複雜(往往代價也很高)的連接配接查詢友善且快速。

舉例2:在一個關系型資料庫中,一篇部落格(包含文章内容、評論、評論的投票)會被打散在多張資料表中。在MongoDB中,能用一個文檔來表示一篇部落格,評論與投票作為文檔數組,放在正文主文檔中。這樣資料更易于管理,消除了傳統關系型資料庫中影響性能和水準擴充性的“JOIN”操作。

CODE↓

> db.blogposts.save({ title : "My First Post", author: {name :"Jane", id :1},

  comments : [{ by: "Abe", text: "First" },

             { by : "Ada", text : "Good post" }]

})

>db.blogposts.find( { "author.name" : "Jane" } )

>db.blogposts.findOne({ title : "My First Post","author.name": "Jane",

  comments : [{ by: "Abe", text: "First" },

             { by : "Ada", text : "Good post" } ]

})

> db.blogposts.find( { "comments.by" : "Ada" } )

>db.blogposts.ensureIndex( { "comments.by" : 1 } );

舉例③:

MongoDB是一個面向文檔的資料庫,目前由10gen開發并維護,它的功能豐富,齊全,完全可以替代MySQL。在使用MongoDB做産品原型的過程中,我們總結了MonogDB的一些亮點:

  使用JSON風格文法,易于掌握和了解:MongoDB使用JSON的變種BSON作為内部存儲的格式和文法。針對MongoDB的操作都使用JSON風格文法,用戶端送出或接收的資料都使用JSON形式來展現。相對于SQL來說,更加直覺,容易了解和掌握。

  Schema-less,支援嵌入子文檔:MongoDB是一個Schema-free的文檔資料庫。一個資料庫可以有多個Collection,每個Collection是Documents的集合。Collection和Document和傳統資料庫的Table和Row并不對等。無需事先定義Collection,随時可以建立。

  Collection中可以包含具有不同schema的文檔記錄。 這意味着,你上一條記錄中的文檔有3個屬性,而下一條記錄的文檔可以有10個屬性,屬性的類型既可以是基本的資料類型(如數字、字元串、日期等),也可以是數組或者散列,甚至還可以是一個子文檔(embeddocument)。這樣,可以實作逆規範化(denormalizing)的資料模型,提高查詢的速度。

圖1 MongoDB是一個Schema-free的文檔資料庫

  圖2是一個例子,作品和評論可以設計為一個collection,評論作為子文檔内嵌在art的comments屬性中,評論的回複則作為comment子文檔的子文檔内嵌于replies屬性。按照這種設計模式,隻需要按照作品id檢索一次,即可獲得所有相關的資訊了。在MongoDB中,不強調一定對資料進行Normalize ,很多場合都建議De-normalize,開發人員可以扔掉傳統關系資料庫各種範式的限制,不需要把所有的實體都映射為一個Collection,隻需定義最頂級的class。MongoDB的文檔模型可以讓我們很輕松就能将自己的Object映射到collection中實作存儲。

圖2 MongoDB支援嵌入子文檔

③内置GridFS,支援大容量的存儲。

  GridFS是一個出色的分布式檔案系統,可以支援海量的資料存儲。

  内置了GridFS了MongoDB,能夠滿足對大資料集的快速範圍查詢。

④内置Sharding。

提供基于Range的Auto Sharding機制:一個collection可按照記錄的範圍,分成若幹個段,切分到不同的Shard上。

Shards可以和複制結合,配合Replica sets能夠實作Sharding+fail-over,不同的Shard之間可以負載均衡。查詢是對用戶端是透明的。用戶端執行查詢,統計,MapReduce等操作,這些會被MongoDB自動路由到後端的資料節點。這讓我們關注于自己的業務,适當的時候可以無痛的更新。MongoDB的Sharding設計能力最大可支援約20 petabytes,足以支撐一般應用。

這可以保證MongoDB運作在便宜的PC伺服器叢集上。PC叢集擴充起來非常友善并且成本很低,避免了“sharding”操作的複雜性和成本。

⑤第三方支援豐富。(這是與其他的NoSQL相比,MongoDB也具有的優勢)

現在網絡上的很多NoSQL開源資料庫完全屬于社群型的,沒有官方支援,給使用者帶來了很大的風險。

而開源文檔資料庫MongoDB背後有商業公司10gen為其提供供商業教育訓練和支援。

而且MongoDB社群非常活躍,很多開發架構都迅速提供了對MongDB的支援。不少知名大公司和網站也在生産環境中使用MongoDB,越來越多的創新型企業轉而使用MongoDB作為和Django,RoR來搭配的技術方案。

⑥性能優越:

在使用場合下,千萬級别的文檔對象,近10G的資料,對有索引的ID的查詢不會比mysql慢,而對非索引字段的查詢,則是全面勝出。mysql實際無法勝任大資料量下任意字段的查詢,而mongodb的查詢性能實在讓我驚訝。寫入性能同樣很令人滿意,同樣寫入百萬級别的資料,mongodb比我以前試用過的couchdb要快得多,基本10分鐘以下可以解決。補上一句,觀察過程中mongodb都遠算不上是CPU殺手。

與關系型資料庫相比,MongoDB的缺點:

①mongodb不支援事務操作。

  是以事務要求嚴格的系統(如果銀行系統)肯定不能用它。(這點和優點①是對應的)

②mongodb占用空間過大。

  關于其原因,在官方的FAQ中,提到有如下幾個方面:

1、空間的預配置設定:為避免形成過多的硬碟碎片,mongodb每次空間不足時都會申請生成一大塊的硬碟空間,而且申請的量從64M、128M、256M那樣的指數遞增,直到2G為單個檔案的最大體積。随着資料量的增加,你可以在其資料目錄裡看到這些整塊生成容量不斷遞增的檔案。

2、字段名所占用的空間:為了保持每個記錄内的結構資訊用于查詢,mongodb需要把每個字段的key-value都以BSON的形式存儲,如果value域相對于key域并不大,比如存放數值型的資料,則資料的overhead是最大的。一種減少空間占用的方法是把字段名盡量取短一些,這樣占用空間就小了,但這就要求在易讀性與空間占用上作為權衡了。我曾建議作者把字段名作個index,每個字段名用一個位元組表示,這樣就不用擔心字段名取多長了。但作者的擔憂也不無道理,這種索引方式需要每次查詢得到結果後把索引值跟原值作一個替換,再發送到用戶端,這個替換也是挺耗費時間的。現在的實作算是拿空間來換取時間吧。

3、删除記錄不釋放空間:這很容易了解,為避免記錄删除後的資料的大規模挪動,原記錄空間不删除,隻标記“已删除”即可,以後還可以重複利用。

4、可以定期運作db.repairDatabase()來整理記錄,但這個過程會比較緩慢

③MongoDB沒有如MySQL那樣成熟的維護工具,這對于開發和IT營運都是個值得注意的地方。

################################

Wordnik的MongoDB使用經驗

http://news.cnblogs.com/n/80856/

視覺中國的NoSQL之路:從MySQL到MongoDB

http://news.cnblogs.com/n/77959/