MongoDB 初見指南

来源:http://www.cnblogs.com/mindwind/archive/2016/01/18/5137744.html
-Advertisement-
Play Games

技術若只如初見,那麼還會踩坑麽? 在系統引入 MongoDB 也有幾年了,一開始是因為 MySQL 中有單表記錄增長太快(每天幾千萬條吧)容易拖慢 MySQL 的主從複製。而這類數據增長迅速的流水錶,對數據一致性也沒那麼高要求,而且業務上也不需要關聯查詢它,就考慮分出去。為什麼是 M...


技術若只如初見,那麼還會踩坑麽?


在系統引入 MongoDB 也有幾年了,一開始是因為 MySQL 中有單表記錄增長太快(每天幾千萬條吧)容易拖慢 MySQL 的主從複製。而這類數據增長迅速的流水錶,對數據一致性也沒那麼高要求,而且業務上也不需要關聯查詢它,就考慮分出去。為什麼是 MongoDB?剛巧趕上公司 DBA 團隊引入了這個資料庫,有人幫助運維,對業務團隊就成了一個自然的選擇。不過對於任何技術產品你如果要把它用在生產環境上,最好確定對它的架構和運作機理有個全面的理解。

形態

MongoDB 是一種 NoSQL 資料庫,它在數據存儲的形態上和 MySQL 這類關係資料庫有本質區別。MongoDB 存儲的基本對象是 Document,所以我們把它稱為一種文檔資料庫,而文檔的集合則組成了 Collection。與 SQL 的概念類比,Collection 對應於 Table 而 Document 對應於 Row。Document 使用一種 BSON(Binary JSON)結構來表達,JSON 大家都熟悉,像下麵這樣。

Document 在內部是如何存儲的?每個 Document 被保存在一個 Record 中。Record 相當於 MongoDB 內部分配的一塊空間,除了保存 Document 的內容可能還會預留一些填充的額外空間。對於寫入後的 Document 如果還會更新,可能導致 Document 長度增加,就可以利用上額外的填充空間來。若業務對於寫入後的 Document 不會再更新或刪除(像監控日誌、流水記錄等),可以指定無填充的 Record 分配策略,更節省空間。

瞭解了 Document 形態的基礎上,我們再說點針對 Document 的訪問操作。新的 WiredTiger 存儲引擎提供了 Document 級別的併發操作,所以併發性能有所改善。另外 MongoDB 僅對單一 Document 提供事務的 ACID 保障,如果一個操作涉及多個 Document 則不能保證事務特性。不同的業務數據對事務一致性的要求不同,所以應用開發者需要知道將數據放在不同的 Document 中寫入時在一致性方面可能的影響。詳細的操作 API 直接看官方文檔,不贅述了。

安全

這裡的安全指的數據安全,安全就是說數據被安全的保存好了,不會丟失。關於 MongoDB 數據安全在早期的版本(1.x)引發了很多爭論。(可以看參考[2])

安全和效率其實是相互制約的,越安全則效率越低,越高效則越不安全。MongoDB 的設計場景考慮的是應對大量的數據寫入和查詢,而數據的重要性相對沒那麼高。所以 MongoDB 的預設設置在安全和效率之間,更偏向效率。

我們先看下一個 Document 被寫入到 MongoDB 後它內部的處理方式。MongoDB 的 API 提供了不同安全級別的寫入選項來讓使用方根據其數據性質靈活的選擇。

Write To Buffer Without ACK

這個模式下 MongoDB 是不確認寫請求的,Client 端調用驅動寫入後若沒有網路錯誤就認為成功,實際到底寫入成功沒有是不確定的。即使網路沒有問題,數據到達 MongoDB 後它先保存在記憶體 Buffer 中,再非同步寫入 Journaling 日誌,這中間有 100ms(預設值) 的落盤(寫入磁碟)時間視窗。一般資料庫的設計都是先寫 Journaling 的流水日誌,隨後非同步再寫真正的數據文件到磁碟,這個隨後可能就比較長了,MongoDB 是 60 秒或者 Journaling 日誌達到 2G。

Write To Buffer With ACK

這個比上一種模式稍微好一點,MongoDB 收到寫入請求,先寫入記憶體 Buffer 後回發 Ack 確認。Client 端能確保 MongoDB 收到了寫入數據,但依然有短暫的 Journaling 日誌落盤時差導致潛在的數據丟失可能。

Write To Journaling With ACK

這個模式確保至少寫入 Journaling 日誌後才回發 Ack 確認,Client 端能確保數據至少寫入磁碟了,安全性較高。

Write To Replica Buffer With ACK

這個模式是針對多副本集的,為了提升數據安全性,除了及時寫入磁碟也可以通過寫多個副本來提升。在這個模式下,數據至少寫入 2 個副本的記憶體 Buffer 中才回發 Ack 確認。雖然都在記憶體 Buffer 中,但兩個實例在落盤短暫的 100ms 時差中同時故障的概率很低,所以安全性有所提升。

明白了不同的寫入模式選項,我們才能更好的真對數據的性質選擇合適的安全級別。後面效率一節我們再分析不同寫入模式下的效率差異。

容量

在考慮 MongoDB 整體的存儲容量前,先考慮作為基本單元的 Document 的容量。Document 這種 JSON 形態天生會帶來數據存儲冗餘,主要是 field 屬性每個 Document 都會保存一遍。目前 3.2 版本的 MongoDB 已經將新的 WiredTiger 作為預設存儲引擎,它提供了壓縮功能,有兩種壓縮形式:

  • Snappy 預設壓縮演算法,在壓縮率和 CPU 開銷之間取得平衡。
  • Zlib 更高的壓縮率,但也帶來更高的 CPU 開銷。

而每個 Document 依然有最大容量限制,不能無限增長下去,這個限制目前是 16MB。那麼我要存大於 16MB 的文件怎麼辦,MongoDB 提供了 GridFS 來存儲超過 16MB 大小的文件。如下圖所示,一個大文件被拆分成小的 File Chunk,每個 Chunk 大小 255KB,並存放在一個 Document 中。GridFS 使用了 2 個 Collection 來分別存放文件 Chunk 和文件元數據。

單機的容量總是受限於磁碟大小,而 MongoDB 解決方案依然是分片化。是用更多的機器來提供更大的容量,分片集群採用代理模式(《Redis 集群的合縱與連橫》一文中寫過這類模式),如下圖。

而每個分片上的數據又以 Chunk 的形式組織(類似於 Redis Cluster 的 Slot 概念),以便於集群內部的數據遷移和再平衡。比較容易混淆的是這裡的 Chunk 不是前面 GridFS 里提到的 Chunk,它們的關係大概如下圖(吐槽下,幹嘛要用同名的術語來表達完全不同的概念)。

支持水平擴展和數據再平衡功能的 MongoDB Cluster 基本上數據容量就不再是個問題了。

效率

前面「安全」一節列舉了不同的寫入模式,我們看下在這些不同模式下寫入的效率如何。由於官方沒有提供基準性能測試數據,下麵的數據來自參考文獻[5]一個從 2009 年開始使用 MongoDB 的專業技術公司博客分享的寫入基準測試數據。我這裡根據數據結果做一些分析總結,下麵是測試結果數據的表格和圖形展示。

  • w=0, Write To Buffer Without ACK
  • w=1, Write To Buffer With ACK
  • j=1, Write To Journaling With ACK
  • w=2, Write To Replica Buffer With ACK

測試類型多了一項將 Journaling 日誌放在 SSD 和機械硬碟上的差異,這讓我們可以直觀的感受 SSD 和機械硬碟在順序寫情況下的性能差異。對於機械硬碟最大的性能制約是在磁頭移動,所以 MongoDB 官方文檔也建議將 Journaling 日誌和數據文件放在不同的磁碟上。保證順序寫 Journaling 日誌的磁頭不會被隨機寫數據文件影響,而數據文件的寫入是通過記憶體 buffer 緩衝的一個非同步過程,對交互性能延遲的影響不大。

根據測試結果數據看,有無 Ack 之間響應延時相差一倍,基本就是多了一個網路傳輸的延時等待時間。開啟 Journaling 保證及時落盤,不論是 SSD 還是機械硬碟,這個延時都上升了 2 個數量級,翻了百倍,而 SSD 的順序寫比機械硬碟平均快 3 倍。而寫雙副本的平均延時比我預期高了不少,應該說延時的波動很大,不像寫磁碟延時最小、最大和平均的值非常接近。理論上寫雙副本不落盤的情況延時只應該比單一情況多一倍的網路開銷外加部份程式開銷,而實際測試數據顯示遠遠高於預期而且延時波動範圍大了很多。這種模式下 MongoDB 延時表現波動範圍太大,不夠穩定,具體到底是實現上的缺陷還是測試不夠準確,就不得而知。而且當時測試的版本是 2.4.1 不知道最新的 3.2 版本如何,如果採用這類寫模式,可模擬自己生產環境實測得出結論。

至於讀取性能是沒法做基準測試了,不同的文檔模型,選擇不同的查詢條件,性能都可能不同。雖然 MongoDB 是 Schemaless 的,但不意味著不需要對文檔的 Schema 進行設計,不同的 Schema 設計對性能的影響還是很大的。

總結

面臨一個新的技術產品或系統,「形態」是針對這個產品或系統最獨特部分的描述,屬於核心模型。而「安全」、「容量」、「效率」三個核心維度全面反應了一個技術產品或系統的不同設計和實現考慮,可類於比機械設計中的「三視圖」。對於初次面對一個新的技術產品或系統,這是一個適合的切入點來幫助做初步的技術決策,然後跟著進一步的實踐測試來驗證思考和理解,這樣才能更好的理解和用好現有技術,做一個合格的技術拿來主義者。

參考

[1] MongoDB Doc. MongoDB Manual
[2] MongoDB White Paper. MongoDB Architecture Guide
[3] 陳皓. 千萬別用MongoDB?真的嗎?. 2011.11
[4] David Mytton. Does everyone hate MongoDB?. 2012.09
[5] David Mytton. MongoDB Benchmarks. 2012.08
[6] David Mytton. MongoDB Schema Design Pitfalls. 2013.02


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • TabLayout——選項卡佈局,通過選項卡的方式切換view並不是material design中才有的新概念,選項卡既可以固定,也可以滾動顯示效果如下: 通過addTab方法可以實現選項卡的動態添加:tabLayout.addTab(tabLayout.newTab().setText...
  • 不管怎樣,我相信,每一個我遇到的難題,對我來說都是一次提升的機會。 作為一隻C++,混SQL群壓力還是蠻大的。
  • 1.http://www.cnblogs.com/huangxincheng/archive/2012/02/18/2356595.html
  • 目錄讀前註意與概述動態SQL簡介使用EXCUTE IMMEDIATE語句處理DDL和DCL語句處理DML語句處理單行查詢處理多行查詢在動態SQL中使用批量綁定讀前註意與概述 當編寫PL/SQL塊時,靜態SQL語句只能完成一些固定任務。為了使得PL/SQL塊可以靈活的處理SQL語句,需要使用動態SQ....
  • 開窗函數與聚合函數一樣,都是對行的集合組進行聚合計算。它用於為行定義一個視窗(這裡的視窗是指運算將要操作的行的集合),它對一組值進行操作,不需要使用GROUP BY子句對數據進行分組,能夠在同一行中同時返回基礎行的列和聚合列。開窗函數的調用格式為:函數名(列) OVER(選項)。第一大類:聚合開窗函...
  • Java通過Hadoop提供的API訪問HDFS不算困難,但針對其上文件的計算就比較麻煩。比如分組、過濾、排序等計算,用java來實現都比較複雜。集算器esproc能很好地協助java解決計算問題,同時也封裝了HDFS的訪問,藉助esproc可以讓java加強HDFS上文件的計算能力,結構化半結構....
  • USE[test_YTHH]GO/******Object:StoredProcedure[dbo].[usp_Print_SCC_Menu]ScriptDate:04/08/201311:21:23******/SETANSI_NULLSONGOSETQUOTED_IDENTIFIERONGO——...
  • Sometimes when we attempting to login the SQL Server 20xx Management Studio, when we type in the correct password, it fails with: "A network-related ....
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...