【譯】爲何永遠都不要使用MongoDB Why You Should Never Use MongoDB

背景web

       最近在學習DDIA(Designing Data-Intensive Applications)這本分佈式領域很是急經典的入門書籍,裏面第二章《數據模型與查詢語言》,強調了對一對多、多對1、多對多等各類不一樣的數據關係進行建模時要怎樣選擇合適的數據庫模型,並重點闡述了關係型數據庫(如PostgreSQL、MySQL)、文檔性數據庫(MongoDB)、以及進來大熱的圖數據庫在不一樣數據關係建模時的使用。這個學習過程當中收益匪淺。其中爲了增強對相關知識的理解消化,又選擇了一些重點的資料進行閱讀。sql

       今天要翻譯的這一篇《 Why You Should Never Use MongoDB》即是其中一篇關於多對一場景下選擇文檔數據庫MongoDB時,爲何有事會對應用的拓展形成災難性後果的闡述。讀完以後,相信咱們會對文檔性數據庫爲何特別適合在多對一場景下使用,以及若是使用不當會形成什麼樣的後果由很是清晰的認識。mongodb

       特別說明下:這一篇文章的標題有誇大的嫌疑,將MongoDB在實際產品開發中的應用視爲災難級的。但其實在適當的場景下使用MongoDB會使得應用在數據表現力方面取得極大的便利性。另外這篇文章的年頭也有點久了(2013年發表的),當前最新的MongoDB在數據聚合等方面也作了不少改進。可是之因此這篇文章爲何我感受它的價值還很大,其實就在於做者對文檔性數據庫的使用闡述得特別詳細,很是適合咱們理解多對一關係以及文檔性數據庫的使用原理。數據庫

       文章很長,整個翻譯大體須要一週左右時間,一點點放進來的。編程

---------------------如下開始是原文翻譯------------------------------後端

爲何你永遠都不要使用MongoDB數組

       聲明:個人工做並非開發數據庫引擎,我開發web應用。每一年我都會主導管理4-6個項目的開發工做,所以,我開發了不少的web 應用。在這個過程當中,我發現每個應用都有不一樣的需求,須要不一樣的數據庫引擎。因此,我使用過不少不一樣的數據存儲組件或應用,基本上全部大家聽到過的數據存儲應用我都使用過,其中有一些大家可能歷來沒有據說過。服務器

      在個人職業生涯中,我碰到過少數幾回數據存儲組件選擇失誤的例子。這裏我將分享其中一個選擇錯誤的例子,包括爲何最初咱們會選擇它,咱們是怎麼發現這個選擇是錯誤的,最後又是怎麼去修復它,整個過程都發生在Diaspora這個開源項目中。網絡

項目數據結構

        Diaspora是一個背後有着複雜故事的分佈式社交網絡應用。時間回退到2010年,四個來自紐約大學的本科生在Kickstarter上發佈一個衆籌$10,000的視頻,目的是利用一個暑假的時間開發一個能夠替換Facebook的分佈式社交網絡應用。他們將這個想法推送給加人、朋友,指望獲得一個好的結果。

       他們真的是踩在點上,那個時候Facebook正好暴露出一個關於用戶隱私的醜聞。因此當他們在Kickstarter發佈這個想法的時候,得到了來自6400多人高達200,000美刀的支持,而這些支持僅僅是爲了一個一行代碼都沒有的一個軟件項目。

       Diaspora是第一個衆籌金額遠遠超過其初期目標的Kickstarter項目。所以,一篇他們事蹟的文章被髮表在紐約時報上,可是這裏有一個小插曲,因爲在團隊照片的背景圖上的一個黑板上面寫着一個一個黃色的笑話,且直到文章在紐約時報上出版的時候都沒有人發現,因此這篇文章也致使了一些醜聞。也所以,我才第一次瞭解到這個項目。

       得益於他們衆籌項目的成功,這些傢伙離開了學校來到舊金山開始爲這個項目開發代碼。他們最終落腳在我工做的地方。那個時候我在Pivotal實驗室工做,這些傢伙裏的其中一個的哥哥也在這個實驗室工做,因此Pivotal免費爲他們提供辦公位置、網絡,固然也包括冰啤酒。那段時間我主要服務與官方的客戶,在下班的時候就跟他們一些而且在週末的時候爲項目貢獻代碼。

       最後,他們在實驗室呆了超過兩年的時間,在第一個暑假結束額時候,他們已經有一個很小的,可是在某種意義上來說已經可用的分佈式社交網絡的實現,這個實現開發語言是Ruby on Rails,後端的數據庫是MongoDB。

      套用一個流行詞,讓咱們慢慢來解剖這個項目。

分佈式社交網絡

       若是你瞭解過社交網絡的話,那麼你已經知道了全部關於Facebook你須要知道的東西。說白了社交網絡就是一個運行在一個單一的邏輯服務器上面且讓你能夠跟別人保持聯繫的web應用。當你登錄應用後,Diaspora的界面結構看起來跟Facebook類似:

在頁面的中間展現的是好友的發佈事件流。在兩邊則是沒有人回去關注,隨便填充的亂七八糟的東西。Diaspora跟Facebook在技術上最重要的區別是終端用戶看不到的,這個區別就是‘分佈式’的部分。

        Diaspora的基礎架構並非部署在一個單一的web地址上,而是部署在幾百臺各自獨立的Diaspora服務器上。Diaspora的代碼是開源的,所以若是你願意的話,你也能夠在你本身的服務器上面部署一個Diaspora服務。每個Diaspora服務都叫作一個POD,都有本身的數據庫以及用戶集,並且將與其餘全部的Diaspora服務彼此之間相互交互數據。

        每個POD都與其餘的pod經過HTTP接口進行消息交互。當你在其中一個pod上面建立一個帳號後,若是你沒有關注其餘人(就是當被人的粉絲),那實際上是至關無聊的。你能夠關注同一個pod上的用戶,也能夠關注跟你處於不一樣pod上面的用戶。當某個你關注的用戶在其餘pod上面發佈一條狀態的時候,會發生下面的幾件事:

一、這條狀態存儲到發佈者坐在pod的數據庫上。

二、你所在的pod會經過HTTP接口收到通知;

三、這條狀態會被被保存在你所在pod的數據庫上

四、當你刷新新的事件流時,會看到這條更新的狀態會跟隨其餘你關注的人的狀態一塊兒展示在你的最新事件流上。

       評論也是一樣的方式,每一條的狀態的全部評論,有一些是來自於跟發佈者用同一個pod上的用戶,有一些是來自於其餘pod上面的用戶。每個有權限查看狀態的用戶均可以看到這些全部的評論,就像你在那些部屬單一邏輯服務器上的其餘應用所期待的那樣。

誰在乎呢?

       這個架構有技術上跟法律上的優勢。技術上最主要的優勢是容錯性。

       任何一個pod崩潰了,都不會影響到其餘的pod的正常運行。系統任然可用,即便發生網絡分區,這個特性有一些很是有趣的隱含意義,例如,若是你所在的國家切斷了外部的網絡,禁止你訪問Facebook and Twitter,你所在的本地pod任然可讓你跟同一個過年的用戶進行聯繫,即便任何外部的東西你都訪問不到。

       法律上最重要的優勢是服務的獨立性。每個pod都是一個獨立的實體,受部署所在地的法律約束。每個pod都有各自的服務聲明,對於絕大多數的pod而言,你能夠在上面發佈內容而且不須要放棄你的權利(譯者注:這裏應該是數據的全部者權利),而不像在Facebook那樣,你本身沒法擁有數據。Diaspora是一個擁有‘自由’、‘免費’標籤的軟件,大多數完pod的人都是很是在乎這兩點的。

      上述就是整個系統級別的大體架構,下面咱們一塊兒看下單個pod內部的架構。

這是一個Rails的應用

      每一個pod都是依賴一個後端數據庫的Ruby on Rails的web應用,後端數據庫最初是MongoDB。某種意義上來說,整個工程的代碼庫就是一個典型的Rails應用,擁有一個可視化且可編程的用戶界面,一些Ruby代碼,還有一個數據庫。可是從另一個角度上講它有含有任何東西但且是經典的。

 

 

 

       可視化的界面固然是定義網站用戶怎樣跟Diaspora交互的方式。API接口一個很重要的做用是服務於大量的移動端用戶,另外API接口也用於構建聯盟,聯盟這個詞用來描述pod內部之間相互交互的技術用意。應爲分佈式的本質使得在基礎代碼上構建了增長了幾層的應用,而這些額外的應用是不會出如今一個典型的應用中的。

       固然,使用MongoDB來做爲數據存儲是一個非典型的選擇。基本上絕大多數的Rails應用都會選擇PostgreSQL做爲後端的數據庫存儲或者Mysql。

      上述咱們分析了代碼,接下來讓咱們將目光轉移到咱們存儲了哪些類型的數據。

我認爲這個詞的意思並非你想象中的意思

      ‘社交數據’是關於咱們本身的朋友網絡,朋友們各自的朋友網絡,以及全部人在這個大網絡中的活動事件。從概念上來說,咱們將‘社交數據’當成這樣一個網絡:咱們處於網絡的中心,而咱們的朋友從這個中心往外擴散並由此造成的一個沒有方向的圖。

 

 

 

       任什麼時候候咱們存儲社交數據,其實就是在存儲上述的拓撲圖,還有全部在這個拓撲圖的邊上流動的活動事件。

       過去幾年,咱們一直在聽到這樣一個貌似聰明的論斷:社交數據並非關係型的,若是你講這些數據存儲在關係型數據庫上,那麼你就作錯啦。

       那咱們有什麼其餘的選擇嗎?一些傢伙可能會說圖數據庫是最天然的選擇,可是在這裏我不想討論這個圖數據庫話題,由於他目前仍是很小衆的不適合用於實際產品中。另一些傢伙可能會說文檔型數據庫最匹配社交關係數據了,並且在實際的應用中也足夠主流。下面讓咱們一塊兒看一下,爲何有人會認爲MongoDB會比PostgreSQL更適合社交數據的存儲。

MongoDB是怎樣存儲數據的

        MongoDB是一個面向文檔的數據庫,區別於關係型數據庫將數據存儲在由一個個單獨的行組成的表那樣,穩定性的數據庫將數據存儲在由一個個單獨的文檔組成的集合裏面。在MongoDB裏面,一個文檔是由一個大型的JSON字符串組成的,這個JSON字符串沒有特殊的格式或者模式。

       讓咱們假設你要對一個相似於下面這樣一個關係集合進行建模,其實這個模型已經跟使用MongoDB的Pivotal項目的模型很類似了,也是我能夠找到的來解釋文檔型數據庫最好的例子了。

 

 

 

       在根節點上,你有一個電視節目(TV show)的集合。每個節目有不少季,每一季有不少集,每一季有不少評論跟不少角色。當用戶訪問這個視頻站點的時候,他們會直接進入某個特定的電視節目頁面。在這個頁面上用戶能夠看到這個電視節目的全部季、全部集、全部角色、全部評論。因此從應用的角度來看,每當有用戶訪問這個電視節目所在的網頁時,咱們都但願將於這個節目關聯的數據所有檢索出來。

       有不少對這些數據建模的方式。在一個典型的關係型數據庫中,每個類型的數據都放在一個表裏面。因此你會有一個tv_shows表,一個seasons 表,並經過外鍵與tv_shows掛鉤,一個episodes 表經過外鍵與seasons 表掛鉤,一個reviews 表,一個cast_members表,這兩個表均經過外鍵與episodes表掛鉤。所以,若是想要獲取一個電視節目的全部信息,那麼你就須要有一個鏈接5個數據表的數據庫操做。

       咱們也能夠把這個數據建模爲一個內嵌的哈希集合.每個特定電視節目的信息都是一個大的嵌套的k/v數據結構。在‘電視節目’鍵內部,是一個季的數組,每個‘季’也是一個哈希。在每一季內部,是一個角色的數組,每個角色鍵也是一個哈希。這是MongoDB對數據建模的方式。每個TV show都是一個文檔,文檔內部有咱們須要的關於這個節目的全部信息。

       下面是Babylon 5這個電視節目對應的文檔的例子。

 

 

 

基本就是一個巨大的分型數據結構。

 

 

 

        任何咱們須要的關於一個TV show的信息都放在一個文檔裏面,因此即便是一個很大的完檔,咱們任然很容易就能夠一次性將全部的信息檢索出來。

        所以從不少方面來說,這個TV Show應用基本表明了文檔型存儲的一個理想的使用例子。

可是對於社交網絡又是怎樣的呢?

       是的,當你回過頭來看社交網絡站點的時候,你會發現咱們在這個網站頁面中咱們最關心的只有一個,那就是你的活動事件流。這個活動事件流會根據時間順序從最新的開始,查詢全部你關注的用戶的狀態發佈。每一條發佈狀態都有嵌套的信息在裏面,包括照片、點贊、評論等。

 ---未完待續 ---

相關文章
相關標籤/搜索