[TEAP早期試讀]《MongoDB in Action》——為什麼選擇MongoDB?

DigitalSonic發表於2012-05-03

圖靈社群按

TEAP是什麼?TEAP是Turingbook Early Access Program的簡稱,即早期試讀,它公佈的是圖靈在途新書未經編輯的內容。一本書的翻譯週期約為3到6個月,如果在翻譯過程中,譯者就能與讀者進行溝通和交流,對整本書的翻譯品質是有幫助的。通過TEAP,讀者可以提前閱讀將來才能出版的內容,譯者也能收穫寶貴的反饋意見,改進翻譯,提高質量。
本書原名為《MongoDB in Action》,中文暫定名為《MongoDB實戰》,所選內容為原書未編輯加工的第1.4節初稿。
譯者:丁雪豐(@digitalsonic),支付寶Java攻城師一枚,InfoQ中文站小編,常年混跡於各種社群,業餘時間寫作翻譯、漢化軟體,《Spring攻略》、《RESTful WebServices Cookbook中文版》等圖書的譯者。

為什麼MongoDB對您的專案來說是一個好的選擇?我想我已經提供了不少理由了。本節中,我會更明白地進行說明,首先考慮MongoDB專案的總體設計目標。根據其作者的觀點,MongoDB的設計是要結合鍵值儲存和關係型資料庫最好的特性。鍵值儲存,因為非常簡單,所以速度極快而且相對容易伸縮。關係型資料庫更難伸縮,至少水平伸縮很難,但擁有豐富的資料模型和強大的查詢語言。如果MongoDB能介於兩者之間,就能成為一款易於伸縮、能儲存豐富資料結構、提供複雜查詢機制的資料庫。

在使用場景方面,MongoDB非常適合用做以下應用程式的主要資料儲存——Web應用程式、分析與記錄應用程式,以及任何要求有中等級別快取的應用程式。此外,由於能方便地儲存無Schema資料,MongoDB還很適合儲存事先無法知曉其資料結構的資料。

之前所說的內容還不太足以讓人信服,為了證實它們,我們大致瞭解一下目前市面上的眾多資料庫,並和MongoDB做個對比。接下來,我將討論一些特殊的MongoDB使用場景,提供一些生產環境中的例子。最後,我還會討論一些MongoDB實際使用中的重要注意事項。

MongoDB與其他資料庫的對比

市面上的資料庫數量成爆炸式增長,要在它們之間進行權衡是很困難的。幸運的是,它們之中的大多數資料庫都能歸在幾個分類裡。本節中,我會描述簡單及複雜的鍵值儲存、關係型資料庫和文件資料庫,並對它們做一個比較。

簡單鍵值儲存

簡單鍵值儲存正如其名,它們基於給定的鍵對值做索引。常見的場景是快取。舉例來說,假設您需要快取一個由應用程式呈現的HTML頁面,此處的鍵可能是頁面的URL,值是HTML本身。請注意,對鍵值儲存而言,值就是一個不透明的位元組陣列。不用強加關係型資料庫中的Schema,也沒有任何資料型別的概念。這自然限制了鍵值儲存的操作:可以放入一個新值,然後通過鍵將其取出或刪除。擁有如此簡單性的系統通常很快,而且具有可伸縮性。

最著名的簡單鍵值儲存是memcached(發音是mem-cach-dee)。memcached僅在記憶體裡儲存資料,用永續性來換取速度。它也是分散式的,跨多臺伺服器的memcached節點能像單個資料儲存來使用,這消除了維護跨伺服器快取狀態的複雜性。

與MongoDB相比,memcached這樣的簡單鍵值儲存通常讀寫會更快。但與MongoDB不同的是,這些系統很少能充當主要資料儲存。簡單鍵值儲存的最佳用途是附加儲存,既可以作為傳統資料庫之上的快取層,也可以作為任務佇列之類的短暫服務的簡單持久層。

複雜鍵值儲存

可以改進簡單鍵值模型來處理複雜的讀寫Schema或提供更豐富的資料模型。如此一來,就有了複雜鍵值儲存。廣為流傳的論文Dynamo:Amazon's Highly Available Key-value Store中描述的Amazon Dynamo就是這樣一個例子。Dynamo旨在成為一個健壯的資料庫,在網路故障、資料中心停轉及類似情況下仍能工作。這要求系統總是能夠進行讀和寫,本質上就是要求資料能自動跨多個節點進行復制。如果一個節點發生故障,系統的使用者,也許這裡是一個使用Amazon購物車的顧客,不會察覺到服務中斷。當系統允許同一份資料被寫到多個節點時,發生衝突的情況是不可避免的,Dynamo提供了一些解決衝突的方法。與此同時,Dynamo也很容易伸縮。因為沒有主節點——所有節點都是對等的,很容易從整體上理解系統,能方便地新增節點。儘管Dynamo是一個私有系統,但其構建理念啟發了很多NoSQL系統,包括Cassandra、Project Voldemort和Riak。

看看是誰開發了這些複雜鍵值儲存,看看實踐中它們的使用情況如何,您就能知道它們的優點了。以Cassandra為例,它實現了很多Dynamo的伸縮屬性,同時還提供了與Google BigTable類似的面向列的資料模型。Cassandra是一款開源的資料儲存,是Facebook為其收件箱搜尋功能而開發的。該系統可以水平擴充套件,索引60TB以上的收件箱資料,允許在收件箱中對關鍵字和收件人做檢索。資料是根據使用者ID做索引的,每條記錄由一個用於關鍵字檢索的搜尋項陣列和一個用於收件人檢索的收件人ID陣列構成。

這些複雜鍵值儲存是由Amazon、Google和Facebook這樣的大型網際網路公司開發的,用來管理系統的多個部分,擁有非常大的資料量。換言之,複雜鍵值儲存管理了一個相對自包含的域,它對有效儲存和可用性有一定要求。由於採用了無主節點的架構,這些系統能輕鬆地通過新增節點進行擴充套件。它們都選擇了最終一致性,也就是說讀請求不必返回最後一次寫的內容。使用者用較弱的一致性所換得的是在某一節點失效時仍能寫入的能力。

這與MongoDB正好相反,它提供了強一致性、(每個分片)一個主節點、更豐富的資料模型,還有二級索引,最後兩項特性總是一起出現的。如果一個系統允許建模多個領域物件,例如,構建完整Web應用程式時就會有此要求,那麼查詢就需要跨整個資料模型,這時就要用到二級索引了。

因為有豐富的資料模型,可以考慮把MongoDB作為更通用的大型、可伸縮Web應用程式的解決方案。MongoDB的伸縮架構有時也會受到爭議,因為它並非源自Dynamo。但MongoDB針對不同領域有不同的伸縮解決方案。MongoDB的自動分片受到了Yahoo! PNUTS資料儲存和Google BigTable的啟發。讀過這些資料儲存的白皮書的人會發現,MongoDB實現伸縮的方法已經被實現了,而且還很成功。

關係型資料庫

本章中已經介紹了不少關係型資料庫的內容,簡單起見,我只討論RDBMS與MongoDB的相同點和不同點。儘管MySQL使用固定Schema的資料表,MongoDB使用無Schema的文件,但兩者都能表示豐富的資料模型。MySQL和MongoDB都支援B樹索引,那些適用於MySQL索引的經驗也同樣適用於MongoDB。MySQL支援關聯和事務,因此,如果您必須使用SQL或者要求有事務,那麼只能選擇MySQL或其他RDBMS。在不需要事務的情況下,MongoDB的文件模型通常也足夠表示物件了。MongoDB中對單獨文件的更新也是原子的,這提供了傳統事務的一個子集。MongoDB和MySQL都支援複製。就可伸縮性而言,MongoDB設計成能水平擴充套件的,能自動分片並處理故障轉移。MySQL上的分片都需要手動管理,有一定的複雜性,更常見的是垂直擴充套件的MySQL系統。

文件資料庫

自稱為文件資料庫的產品還不多,在本書編寫時,除了MongoDB之外,唯一的著名文件型資料庫就是Apache CouchDB。儘管CouchDB的資料是使用JSON格式的純文字儲存的,而MongoDB使用的是BSON二進位制格式,但兩者的文件模型是相似的。與MongoDB一樣,CouchDB也支援二級索引,不同之處是CouchDB中的索引是通過編寫MapReduce函式來定義的,這比MySQL和MongoDB使用的宣告式語法更復雜一些。兩者伸縮的方式也有所不同,CouchDB不會把資料分散到多臺伺服器上,每個CouchDB節點都是其他節點的完整副本。

使用場景和生產部署

老實說,您不會僅根據資料庫的特性就做出選擇,您需要知道使用它的真實成功案例。這裡,我提供一些廣義上的MongoDB使用場景,以及一些生產環境中的範例。

Web應用程式

MongoDB很適合作為Web應用程式的主要資料儲存。就算是一個簡單的Web應用程式也會有很多資料模型,用來管理使用者、會話、應用特定的資料、上傳和許可權,更不用說完整領域了。正如它們能和關係型資料庫的扁平式方法對齊一樣,它們也能獲益於MongoDB的集合與文件模型。因為文件能表示豐富的資料結構,建模相同資料所需的集合數量通常會比使用完全正規化關係型模型的資料表數量要少。此外,動態查詢和二級索引能讓您輕鬆地實現SQL開發者所熟悉的大多數查詢。最後,作為一個成長中的Web應用程式,MongoDB提供了清晰的擴充套件路線。

在生產環境中,MongoDB已經證明它能管理應用的方方面面,從主要資料領域到附加資料儲存,比如日誌和實時分析。這裡的案例來自The Business Insider(TBE),它從2008年1月起使用MongoDB作為主要資料儲存。雖然TBE是一個新聞網站,但它流量很大,每天有超過一百萬獨立頁面訪問(page view)。這個案例中有意思的是除了處理站點的主要內容(文章、評論、使用者等等),MongoDB還處理並儲存實時分析資料。這些分析被TBE用於生成動態熱點地圖,標明不同新聞故事的點選率。該站目前還沒有太多的資料需要分片,但它有使用副本集來保證自動故障轉移。

敏捷開發

無論如何看待敏捷開發運動,您都很難否認大家對於快速構建應用程式的渴望。不少開發團隊,包括Shutterfly和紐約時代的團隊,都部分選擇了MongoDB,因為相比關係型資料庫,使用MongoDB他們能更快地開發應用程式。一個明顯的原因是MongoDB沒有固定的Schema,所有花在提交、溝通和實施Schema變更的時間都省下來了。

除此之外,不再需要花時間把資料的關係型表述硬塞進物件導向的資料模型裡去了,也不用處理ORM生成的SQL的奇怪行為,或者對它做優化了。如此一來,MongoDB為專案帶來了更短的開發週期和敏捷的、中型大小的團隊。

分析和日誌

我之前已經暗示過MongoDB適用於分析和日誌,將MongoDB用於這些方面的應用程式數量增長得越來越快。通常,發展成熟的公司都會選擇用於分析的特殊應用作為切入點,進入MongoDB的世界。這些公司包括GitHub、Disqus、Justin.tv和Gilt Groupe,還有其他公司就不再列舉了。

MongoDB與分析的關聯源自於它的速度和兩個關鍵特性:目標原子更新和固定集合(capped collection)。原子更新讓客戶端能高效地增加計數器,將值放入陣列。固定集合,常被用於日誌,特點是分配的大小是固定的,能實現自動過期。相比檔案系統,將日誌資料儲存在資料庫裡更易組織,而且能提供更強大的查詢能力。現在,拋開grep或自定義日誌檢索工具,使用者可以使用他們熟悉並喜歡的MongoDB查詢語言來檢視日誌輸出。

快取

這是一種資料模型,它能更完整地表示物件,結合了更快的平均查詢速度,經常讓MongoDB介於傳統的MySQL與memcached之間。例如之前提到的TBE,它不使用memcached,直接通過MongoDB來響應頁面請求。

可變Schema

看看這段程式碼範例:

curl https://stream.twitter.com/1/statuses/sample.json -umongodb:secret | mongoimport -c tweets

這裡您從Twitter的流上拉下一小段範例,並用管道將其直接匯入MongoDB集合。因為流生成的是JSON文件,在把它發給資料庫前就不需要預先處理資料了。mongoimport工具能直接將資料轉換成BSON。這意味著每條Tweet都能保持其結構,原封不動地儲存為集合中的單個文件。無論您是想查詢、索引或執行MapReduce聚合,都能立刻運算元據。而且,不需要事先宣告資料的結構。

如果您的應用程式需要呼叫JSON API,那麼擁有這樣一個能輕鬆轉換JSON的系統就太棒了。如果在儲存之前無法預先了解資料的結構,MongoDB沒有Schema約束的特效能大大簡化資料模型。

相關文章