第五章 - MongoDB 適用場景

2018-02-24 16:17 更新

現(xiàn)在你應(yīng)該有感覺,何時(shí)何地把 MongoDB 融入你現(xiàn)有的系統(tǒng)是最棒的了。這有超多的新的類似的存儲技術(shù),肯定會讓你在選擇的時(shí)候暈頭轉(zhuǎn)向。

對我來說,最重要的教訓(xùn),跟 MongoDB 無關(guān),是說你不用再依賴單一的解決案來處理你的數(shù)據(jù)了。毫無疑問,一個單一的解決案有明顯的優(yōu)勢,對于許多項(xiàng)目來說 - 或者說大多數(shù) - 單一解決案是一個明智的選擇。意思不是說你?必須?使用不同的技術(shù),而是說你?可以。 只有你自己才知道,引進(jìn)新技術(shù)是否利大于弊。

說了那么多,我希望你到目前為止學(xué)到知識讓你覺得 MongoDB 是一個通用的解決案。我們已經(jīng)提到很多次了,面向文檔的數(shù)據(jù)庫和關(guān)系型數(shù)據(jù)庫有很多方面類似。因此,與其繞開這些相同點(diǎn),不如我們可以簡單的這樣認(rèn)為, MongoDB 是關(guān)系型數(shù)據(jù)庫的一個代替案。比如說用 Lucene 作為關(guān)系型數(shù)據(jù)庫的全文檢索索引的加強(qiáng),或者用 Redis 作為持久型 key-value 存儲,MongoDB 就是用來保存你的數(shù)據(jù)的。

注意,我沒有說用 MongoDB?取代?關(guān)系型數(shù)據(jù)庫,而是?代替?案。它能做的有很多工具也能做。有些事情 MongoDB 可以做的更好,另外一些 MongoDB 做得差點(diǎn)。我們來進(jìn)一步來討論一下。

無模式(Flexible Schema)

面向文檔數(shù)據(jù)庫經(jīng)常吹噓的一個好處就是,它不需要一個固定的模式。這使得他們比傳統(tǒng)的數(shù)據(jù)庫表要靈活得多。我同意無模式是一個很不錯的特性,但不是大多數(shù)人說的那樣。

人們講到無模式的時(shí)候,好像你就會把一堆亂七八糟的數(shù)據(jù)統(tǒng)統(tǒng)存起來一樣。確實(shí)有些領(lǐng)域有些數(shù)據(jù)用關(guān)系型數(shù)據(jù)庫來建模很痛苦,不過我覺得這些都是不常見的特例。無模式是酷,可是大多數(shù)情況下你的數(shù)據(jù)結(jié)構(gòu)還是應(yīng)當(dāng)好好設(shè)計(jì)的。真正需要處理混亂時(shí)是不錯,比如當(dāng)你添加一個新功能的時(shí)候,不過事實(shí)是,大多數(shù)情況下,一個空列基本可以解決問題。

對我來說,動態(tài)模式的真正好處在于無需很多設(shè)置以及可以降低在 OOP 中使用的阻力。這在你使用靜態(tài)語言的時(shí)候尤其明顯。我在 C# 和 Ruby 中用過 MongoDB ,差異非常明顯。Ruby 的動態(tài)特性以及它的流行的 ActiveRecord 實(shí)現(xiàn),已經(jīng)大幅降低面向?qū)ο?關(guān)系開發(fā)之間差異所帶來的阻力。這不是說 MongoDB 和 Ruby 不配,而是是說它們太配了。真的,我覺得許多 Ruby 開發(fā)者眼中的的 MongoDB 只是有些許改進(jìn)而已,而在 C# 或者 Java 開發(fā)者眼中,MongoDB 帶來的是處理數(shù)據(jù)交互方式的翻天覆地變化。

假設(shè)從驅(qū)動開發(fā)者角度來看這個問題。你想保存一個對象?把它串行化成 JSON (嚴(yán)格來說是 BSON, 不過差不多) 然后把它傳給 MongoDB。不需要做任何屬性映射或者類型映射。這種簡單性的好處就這樣傳遞給了你,終端開發(fā)者。

寫操作(Writes)

MongoDB 可以勝任的一個特殊角色是在日志領(lǐng)域。有兩點(diǎn)使得 MongoDB 的寫操作非常快。首先,你可以選擇發(fā)送了寫操作命令之后立刻返回,而無須等到操作完成。其次,你可以控制數(shù)據(jù)持久性的寫行為。這些設(shè)置,加上,可以定義一個成功的提交,需要在多少臺服務(wù)器上成功拿到你的數(shù)據(jù)之后才算成功,并且每個寫操作都是可設(shè)置, 這就給予你很高的權(quán)限用以控制寫性能和數(shù)據(jù)持久性。

除了這些性能因素,日志數(shù)據(jù)還是這樣一種數(shù)據(jù)集,用無模式集合更有優(yōu)勢。最后,MongoDB 還提供了?受限集合(capped collection)。到目前為止,所有我們默認(rèn)創(chuàng)建的集合都是普通集合。我們可以通過?db.createCollection?命令來創(chuàng)建一個受限集合并標(biāo)記它的限制:

//limit our capped collection to 1 megabyte
db.createCollection('logs', {capped: true,
    size: 1048576})

當(dāng)我們的受限集合到達(dá) 1MB 上限的時(shí)候,舊文檔會被自動清除。另外一種限制可以基于文檔個數(shù),而不是大小,用?max標(biāo)記。受限集合有一些非常有趣的屬性。比如說,你可以更新文檔但是你不能改變它的大小。插入順序是被設(shè)置好了的,因此不需要另外提供一個索引來獲取基于時(shí)間的排序,你可以 "tail" 一個受限集合,就和你在 Unix 中通過?tail -f?來處理文件一樣,獲取最新的數(shù)據(jù),如果存在數(shù)據(jù)的話,而不需要重新查詢它。

如果想讓你的數(shù)據(jù) "過期" ,基于時(shí)間而不是整個集合的大小,你可以用?TTL 索引?,所謂 TTL 是 "time-to-live" 的縮寫。

持久性(Durability)

在 1.8 之前的版本,MongoDB 不支持單服務(wù)器持久性。就是說,如果一個服務(wù)器崩潰了,可能會導(dǎo)致數(shù)據(jù)的丟失或者損壞。解決案是在多服務(wù)器上運(yùn)行 MongoDB 副本 (MongoDB 支持復(fù)制)。日志(Journaling)是 1.8 版追加的一個非常重要的功能。從 2.0 版的 MongoDB 開始,日志是默認(rèn)啟動的,該功能允許快速恢復(fù)服務(wù)器,比如遭遇到了服務(wù)器崩潰或者停電的情況。

持久性在這里只是提一下,因?yàn)閲@ MongoDB 過去缺乏單服務(wù)器持久的問題,人們?nèi)〉昧吮姸喑晒?。這個話題在以后的 Google 檢索中也許還會繼續(xù)出現(xiàn)。但是關(guān)于缺少日志功能這一缺點(diǎn)的信息,都是過時(shí)了的。

全文檢索(Full Text Search)

真正的全文檢索是在最近加入到 MongoDB 中的。它支持十五國語言,支持詞形變化(stemming)和干擾字(stop words)。除了原生的 MongoDB 的全文檢索支持,如果你需要一個更強(qiáng)大更全面的全文檢索引擎的話,你需要另找方案。

事務(wù)(Transactions)

MongoDB 不支持事務(wù)。這有兩個代替案,一個很好用但有限制,另外一個比較麻煩但靈活。

第一個方案,就是各種原子更新操作。只要能解決你的問題,都挺不錯。我們已經(jīng)看過幾個簡單的了,比如?$inc?和$set。還有像?findAndModify?命令,可以更新或刪除文檔之后,自動返回修改過的文檔。

第二個方案,當(dāng)原子操作不能滿足的時(shí)候,回到兩段提交上來。對于事務(wù),兩段提交就好像給鏈接手工解引用。這是一個和存儲無關(guān)的解決方案。兩段提交實(shí)際上在關(guān)系型數(shù)據(jù)庫世界中非常常用,用來實(shí)現(xiàn)多數(shù)據(jù)庫之間的事務(wù)。 MongoDB 網(wǎng)站?有個例子?演示了最典型的場合 (資金轉(zhuǎn)賬)。通常的想法是,把事務(wù)的狀態(tài)保存到實(shí)際的原子更新的文檔中,然后手工的進(jìn)行 init-pending-commit/rollback 處理。

MongoDB 支持內(nèi)嵌文檔以及它靈活的 schema 設(shè)計(jì),讓兩步提交沒那么痛苦,但是它仍然不是一個好處理,特別是當(dāng)你剛開始接觸它的時(shí)候。

數(shù)據(jù)處理(Data Processing)

在2.2 版本之前的 MongoDB 依賴 MapReduce 來解決大部分?jǐn)?shù)據(jù)處理工作。在 2.2 版本,它追加了一個強(qiáng)力的功能,叫做aggregation framework or pipeline,因此你只要對那些尚未支持管道的,需要使用復(fù)雜方法的,不常見的聚合使用 MapReduce。下一章我們將看看聚合管道和 MapReduce 的細(xì)節(jié)?,F(xiàn)在,你可以把他們想象成功能強(qiáng)大的,用不同方法實(shí)現(xiàn)的?group by?(打個比方)。對于非常大的數(shù)據(jù)的處理,你可能要用到其他的工具,比如 Hadoop。值得慶幸的是,這兩個系統(tǒng)是相輔相成的,這里有個?MongoDB connector for Hadoop

當(dāng)然,關(guān)系型數(shù)據(jù)庫也不擅長并行數(shù)據(jù)處理。MongoDB 有計(jì)劃在未來的版本中,改善增加處理大數(shù)據(jù)集的能力。

地理空間查詢(Geospatial)

一個很強(qiáng)大的功能就是 MongoDB 支持?geospatial 索引。這允許你保存 geoJSON 或者 x 和 y 坐標(biāo)到文檔,并查詢文檔,用如?$near?來獲取坐標(biāo)集,或者?$within?來獲取一個矩形或圓中的點(diǎn)。這個特性最好通過一些可視化例子來演示,所以如果你想學(xué)更多的話,可以試試看?5 minute geospatial interactive tutorial。

工具和成熟度

你應(yīng)該已經(jīng)知道這個問題的答案了,MongoDB 確實(shí)比大多數(shù)的關(guān)系型數(shù)據(jù)要年輕很多。這個問題確實(shí)是你應(yīng)當(dāng)考慮的,但是到底有多重要,這取決于你要做什么,怎么做。不管怎么說,一個好的評估,不可能忽略 MongoDB 年輕這一事實(shí),而可用的工具也不是很好 (雖然成熟的關(guān)系型數(shù)據(jù)庫工具有些也非常渣!)。舉個例子,它缺乏對十進(jìn)制浮點(diǎn)數(shù)的支持,在處理貨幣的系統(tǒng)來說,明顯是一個問題 (盡管也不是致命的) 。

積極的一方面,它為大多數(shù)語言提供了驅(qū)動,協(xié)議現(xiàn)代而簡約,開發(fā)速度相當(dāng)快。MongoDB 被眾多公司用到了生產(chǎn)環(huán)境中,雖然有所擔(dān)心,但經(jīng)過驗(yàn)證后,擔(dān)心很快就變成了過去。

小結(jié)

本章要說的是,MongoDB,大多數(shù)情況下,可以取代關(guān)系型數(shù)據(jù)庫。它更簡單更直接;更快速并且通常對應(yīng)用開發(fā)者的約束更少。不過缺乏事務(wù)支持也許值得慎重考慮。當(dāng)人們說起?MongoDB 在新的數(shù)據(jù)庫陣營中到底處在什么位置??時(shí),答案很簡單:?中庸(2)。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號