現在你應該有感覺,何時何地把 MongoDB 融入你現有的系統(tǒng)是最棒的了。這有超多的新的類似的存儲技術,肯定會讓你在選擇的時候暈頭轉向。
對我來說,最重要的教訓,跟 MongoDB 無關,是說你不用再依賴單一的解決案來處理你的數據了。毫無疑問,一個單一的解決案有明顯的優(yōu)勢,對于許多項目來說 - 或者說大多數 - 單一解決案是一個明智的選擇。意思不是說你?必須?使用不同的技術,而是說你?可以。 只有你自己才知道,引進新技術是否利大于弊。
說了那么多,我希望你到目前為止學到知識讓你覺得 MongoDB 是一個通用的解決案。我們已經提到很多次了,面向文檔的數據庫和關系型數據庫有很多方面類似。因此,與其繞開這些相同點,不如我們可以簡單的這樣認為, MongoDB 是關系型數據庫的一個代替案。比如說用 Lucene 作為關系型數據庫的全文檢索索引的加強,或者用 Redis 作為持久型 key-value 存儲,MongoDB 就是用來保存你的數據的。
注意,我沒有說用 MongoDB?取代?關系型數據庫,而是?代替?案。它能做的有很多工具也能做。有些事情 MongoDB 可以做的更好,另外一些 MongoDB 做得差點。我們來進一步來討論一下。
面向文檔數據庫經常吹噓的一個好處就是,它不需要一個固定的模式。這使得他們比傳統(tǒng)的數據庫表要靈活得多。我同意無模式是一個很不錯的特性,但不是大多數人說的那樣。
人們講到無模式的時候,好像你就會把一堆亂七八糟的數據統(tǒng)統(tǒng)存起來一樣。確實有些領域有些數據用關系型數據庫來建模很痛苦,不過我覺得這些都是不常見的特例。無模式是酷,可是大多數情況下你的數據結構還是應當好好設計的。真正需要處理混亂時是不錯,比如當你添加一個新功能的時候,不過事實是,大多數情況下,一個空列基本可以解決問題。
對我來說,動態(tài)模式的真正好處在于無需很多設置以及可以降低在 OOP 中使用的阻力。這在你使用靜態(tài)語言的時候尤其明顯。我在 C# 和 Ruby 中用過 MongoDB ,差異非常明顯。Ruby 的動態(tài)特性以及它的流行的 ActiveRecord 實現,已經大幅降低面向對象/關系開發(fā)之間差異所帶來的阻力。這不是說 MongoDB 和 Ruby 不配,而是是說它們太配了。真的,我覺得許多 Ruby 開發(fā)者眼中的的 MongoDB 只是有些許改進而已,而在 C# 或者 Java 開發(fā)者眼中,MongoDB 帶來的是處理數據交互方式的翻天覆地變化。
假設從驅動開發(fā)者角度來看這個問題。你想保存一個對象?把它串行化成 JSON (嚴格來說是 BSON, 不過差不多) 然后把它傳給 MongoDB。不需要做任何屬性映射或者類型映射。這種簡單性的好處就這樣傳遞給了你,終端開發(fā)者。
MongoDB 可以勝任的一個特殊角色是在日志領域。有兩點使得 MongoDB 的寫操作非??臁J紫?,你可以選擇發(fā)送了寫操作命令之后立刻返回,而無須等到操作完成。其次,你可以控制數據持久性的寫行為。這些設置,加上,可以定義一個成功的提交,需要在多少臺服務器上成功拿到你的數據之后才算成功,并且每個寫操作都是可設置, 這就給予你很高的權限用以控制寫性能和數據持久性。
除了這些性能因素,日志數據還是這樣一種數據集,用無模式集合更有優(yōu)勢。最后,MongoDB 還提供了?受限集合(capped collection)。到目前為止,所有我們默認創(chuàng)建的集合都是普通集合。我們可以通過?db.createCollection
?命令來創(chuàng)建一個受限集合并標記它的限制:
//limit our capped collection to 1 megabyte
db.createCollection('logs', {capped: true,
size: 1048576})
當我們的受限集合到達 1MB 上限的時候,舊文檔會被自動清除。另外一種限制可以基于文檔個數,而不是大小,用?max
標記。受限集合有一些非常有趣的屬性。比如說,你可以更新文檔但是你不能改變它的大小。插入順序是被設置好了的,因此不需要另外提供一個索引來獲取基于時間的排序,你可以 "tail" 一個受限集合,就和你在 Unix 中通過?tail -f
?來處理文件一樣,獲取最新的數據,如果存在數據的話,而不需要重新查詢它。
如果想讓你的數據 "過期" ,基于時間而不是整個集合的大小,你可以用?TTL 索引?,所謂 TTL 是 "time-to-live" 的縮寫。
在 1.8 之前的版本,MongoDB 不支持單服務器持久性。就是說,如果一個服務器崩潰了,可能會導致數據的丟失或者損壞。解決案是在多服務器上運行 MongoDB 副本 (MongoDB 支持復制)。日志(Journaling)是 1.8 版追加的一個非常重要的功能。從 2.0 版的 MongoDB 開始,日志是默認啟動的,該功能允許快速恢復服務器,比如遭遇到了服務器崩潰或者停電的情況。
持久性在這里只是提一下,因為圍繞 MongoDB 過去缺乏單服務器持久的問題,人們取得了眾多成果。這個話題在以后的 Google 檢索中也許還會繼續(xù)出現。但是關于缺少日志功能這一缺點的信息,都是過時了的。
真正的全文檢索是在最近加入到 MongoDB 中的。它支持十五國語言,支持詞形變化(stemming)和干擾字(stop words)。除了原生的 MongoDB 的全文檢索支持,如果你需要一個更強大更全面的全文檢索引擎的話,你需要另找方案。
MongoDB 不支持事務。這有兩個代替案,一個很好用但有限制,另外一個比較麻煩但靈活。
第一個方案,就是各種原子更新操作。只要能解決你的問題,都挺不錯。我們已經看過幾個簡單的了,比如?$inc
?和$set
。還有像?findAndModify
?命令,可以更新或刪除文檔之后,自動返回修改過的文檔。
第二個方案,當原子操作不能滿足的時候,回到兩段提交上來。對于事務,兩段提交就好像給鏈接手工解引用。這是一個和存儲無關的解決方案。兩段提交實際上在關系型數據庫世界中非常常用,用來實現多數據庫之間的事務。 MongoDB 網站?有個例子?演示了最典型的場合 (資金轉賬)。通常的想法是,把事務的狀態(tài)保存到實際的原子更新的文檔中,然后手工的進行 init-pending-commit/rollback 處理。
MongoDB 支持內嵌文檔以及它靈活的 schema 設計,讓兩步提交沒那么痛苦,但是它仍然不是一個好處理,特別是當你剛開始接觸它的時候。
在2.2 版本之前的 MongoDB 依賴 MapReduce 來解決大部分數據處理工作。在 2.2 版本,它追加了一個強力的功能,叫做aggregation framework or pipeline,因此你只要對那些尚未支持管道的,需要使用復雜方法的,不常見的聚合使用 MapReduce。下一章我們將看看聚合管道和 MapReduce 的細節(jié)?,F在,你可以把他們想象成功能強大的,用不同方法實現的?group by
?(打個比方)。對于非常大的數據的處理,你可能要用到其他的工具,比如 Hadoop。值得慶幸的是,這兩個系統(tǒng)是相輔相成的,這里有個?MongoDB connector for Hadoop。
當然,關系型數據庫也不擅長并行數據處理。MongoDB 有計劃在未來的版本中,改善增加處理大數據集的能力。
一個很強大的功能就是 MongoDB 支持?geospatial 索引。這允許你保存 geoJSON 或者 x 和 y 坐標到文檔,并查詢文檔,用如?$near
?來獲取坐標集,或者?$within
?來獲取一個矩形或圓中的點。這個特性最好通過一些可視化例子來演示,所以如果你想學更多的話,可以試試看?5 minute geospatial interactive tutorial。
你應該已經知道這個問題的答案了,MongoDB 確實比大多數的關系型數據要年輕很多。這個問題確實是你應當考慮的,但是到底有多重要,這取決于你要做什么,怎么做。不管怎么說,一個好的評估,不可能忽略 MongoDB 年輕這一事實,而可用的工具也不是很好 (雖然成熟的關系型數據庫工具有些也非常渣!)。舉個例子,它缺乏對十進制浮點數的支持,在處理貨幣的系統(tǒng)來說,明顯是一個問題 (盡管也不是致命的) 。
積極的一方面,它為大多數語言提供了驅動,協議現代而簡約,開發(fā)速度相當快。MongoDB 被眾多公司用到了生產環(huán)境中,雖然有所擔心,但經過驗證后,擔心很快就變成了過去。
本章要說的是,MongoDB,大多數情況下,可以取代關系型數據庫。它更簡單更直接;更快速并且通常對應用開發(fā)者的約束更少。不過缺乏事務支持也許值得慎重考慮。當人們說起?MongoDB 在新的數據庫陣營中到底處在什么位置??時,答案很簡單:?中庸(2)。
更多建議: