1. 程式人生 > >【轉】 MongoDB 應用場景、避坑事項與最佳實踐

【轉】 MongoDB 應用場景、避坑事項與最佳實踐

  MongoDB 是一個高效能,開源,無模式的文件型資料庫,是當前 NoSQL 資料庫產品中最熱門的一種。它在許多場景下可用於替代傳統的關係型資料庫或鍵/值儲存方式,MongoDB 使用 C++開發。

  1. 為什麼要用 NoSQL
    NoSQL,全稱是”Not Only Sql”,指的是非關係型的資料庫,這類資料庫主要有這些特點:非關係型的、分散式的、開源的、水平可擴充套件的。原始的目的是為了大規模 web 應用,NoSQL 被我們用得最多的當數 key-value 儲存,當然還有其他的文件型的、列儲存、圖型資料庫、xml 資料庫等

目前新浪微博的Redis和Google的Bigtable以及Amazon的SimpleDB使用的就是 NoSQL 型資料庫。NoSQL 資料儲存不需要固定的表結構,通常也不存在連線操作。

  1. MongoDB 是一個介於關係資料庫和非關係資料庫之間的產品,是非關係資料庫當中功能最豐富,最像關係資料庫的。MongoDB 最大的特點是他支援的查詢語言非常強大,其語法有點類似於面向物件的查詢語言,幾乎可以實現類似關係資料庫單表查詢的絕大部分功能,而且還支援對資料建立索引。它是一個面向集合的,模式自由的文件型資料庫。
    (1) 面向集合(Collenction-Orented)
    意思是資料被分組儲存在資料集中, 被稱為一個集合(Collenction)。每個集合在資料庫中都有一個唯一的標識名,並且可以包含無限數目的文件。集合的概念類似關係型資料庫(RDBMS)裡的表(table),不同的是它不需要定義任何模式(schema)。
    (2) 模式自由(schema-free)
    意味著對於儲存在 MongoDB 資料庫中的檔案,我們不需要知道它的任何結構定義。提了這麼多次"無模式"或"模式自由",它到是個什麼概念呢?例如,下面兩個記錄可以存在於同一個集合裡面:
    {“welcome” : “Beijing”}
    {“age” : 25}
    (3) 文件型
    意思是我們儲存的資料是鍵-值對的集合,鍵是字串,值可以是資料型別集合裡的任意型別,包括陣列和文件. 我們把這個資料格式稱作 “BSON” 即 “Binary Serialized dOcument Notation.”

  2. 功能
    (1) 面向集合的儲存:適合儲存物件及 JSON 形式的資料
    (2) 動態查詢:MongoDB 支援豐富的查詢表示式。查詢指令使用 JSON 形式的標記,可輕易查詢文件中內嵌的物件及陣列
    (3) 完整的索引支援:包括文件內嵌物件及陣列。MongoDB 的查詢優化器會分析查詢表示式,並生成一個高效的查詢計劃
    (4)查詢監視:MongoDB 包含一系列監視工具用於分析資料庫操作的效能
    (5)複製及自動故障轉移:MongoDB 資料庫支援伺服器之間的資料複製,支援主-從模式及伺服器之間的相互複製。複製的主要目標是提供冗餘及自動故障轉移
    (6)高效的傳統儲存方式:支援二進位制資料及大型物件(如照片或圖片)
    (7)自動分片以支援雲級別的伸縮性:自動分片功能支援水平的資料庫叢集,可動態新增額外的機器

  3. 適用場合
    (1)網站資料:MongoDB 非常適合實時的插入,更新與查詢,並具備網站實時資料儲存所需的複製及高度伸縮性
    (2)快取:由於效能很高,MongoDB 也適合作為資訊基礎設施的快取層。在系統重啟之後,由 MongoDB 搭建的持久化快取層可以避免下層的資料來源過載
    (3)大尺寸,低價值的資料:使用傳統的關係型資料庫儲存一些資料時可能會比較昂貴,在此之前,很多時候程式設計師往往會選擇傳統的檔案進行儲存
    (4)高伸縮性的場景:MongoDB 非常適合由數十或數百臺伺服器組成的資料庫。MongoDB的路線圖中已經包含對 MapReduce 引擎的內建支援
    (5)用於物件及 JSON 資料的儲存:MongoDB 的 BSON 資料格式非常適合文件化格式的儲存及查詢


  社群最近組織了交流活動,探討MongoDB適合的應用場景、避坑事項與最佳實踐。由社群專家劉誠傑根據交流內容整理成文,無論是MongoDB零基礎的小夥伴,還是正在應用中的朋友,在此均可以找到有價值的經驗和分享。

劉誠傑,專注於MongoDB、MySQL、Redis等開源資料庫的使用與研究,MongoDB上海使用者組聯合發起人。
閱讀說明:以下內容中——
1~6為0基礎就可看懂
7~11為運維管理問題
12~13為案例分析

1、如何學習MongoDB?

 MongoDB日趨流行,作為一個開發/運維,如何快速上手MongoDB?或者有哪些推薦的學習MongoDB的方式?

英文比較好的小夥伴:

  1. 強烈推薦MongoDB官方的教程,MongoDB線上大學,無論開發還是DBA,都可以找到適合自己的視訊教程。因為視訊有英語字幕,聽不懂的同學,多多暫停,看一下字幕都能理解。

 每節課結束都有相應的作業,可以自己用來練手。而且作業都會有類似一鍵指令碼的東西,幫你配置好需要的實驗環境。完成作業後,會有不少成就感,讓自己可以有學下去的動力。另外,每次作業和最後的考試都通過會有一張結業證書。最後,MongoDB官方的新員工也是從這裡開始學習的,而且課程更新頻率也很高。

  1. MongoDB的官方文件,文件地址,選擇自己想要看到章節,文件的內容寫的很詳細,而且有的地方直接提供web shell的環境,讓你實際操作。

  2. MongoDB工程師網站,網站地址,這裡可以深入看到一些MongoDB原理的內容。此外也推薦看percona公司關於MongoDB的一些博文

看到英語就頭疼的小夥伴:
 暫時沒找到較好的基礎視訊教程,IT大咖說上面有MongoDB使用案例的視訊,可以一看,不過不適合初學,需要有一定的基礎。

  1. 先從看書開始,強烈推薦《MongoDB實戰 第二版》,因為這本書是3.x版本的,相對來說內容比較新。然後《MongoDB權威指南 第二版》,這本內容蠻多的,不過已經過時了。《MongoDB應用設計模式》關於MongoDB設計適用的書,非常短,值得一看。
  2. MongoDB中文社群有部分官方文件的翻譯。
  3. MongoDB中文社群的公眾號及部落格,雲棲社群MongoDB板塊

2、Mongodb用在什麼樣的場景合適?

Mongodb是最近流行的NOsql資料庫,但一直對其用在什麼場景合適而不清楚。主要知道這個資料庫是快速開發很合適。但一直歸屬到大資料板塊,想要諮詢下Mongodb適用的場景有哪些?在大資料板塊充當什麼角色哪?

  • 常見應用場景:
  1. 最近單的入手就是存log,因為mongodb本身存的就是json,可以很方便的接入各種儲存日誌的地方。然後可以做成相關監控報表,比如說APM,NPM等,比如說千尋位置
  2. 其他的話要看題主所在的行業了,不同的行業有不同的用法,比如說資訊的展示等等
  3. 在網遊界,MongoDB也非常流行,比如說最近大火的陰陽師,資料庫用的就是MongoDB

大資料方面,MongoDB有以下三個優勢:

  1. 自帶sharding,快速得水平擴充套件,為儲存海量資料帶來便捷
  2. 官方提供驅動,可以直接對接hadoop或者spark

3、能提供幾個mongodb的案例嗎?

國外的例子太多,在mongodb的官網上就有,無論是金融、傳統等行業,我這裡說一下國內的案例。

  • 金融:
     非核心業務的話幾乎每家知名企業都在嘗試使用,比如某國有銀行用在了apm系統,平安科技用在了內部系統和日誌系統。核心業務的話網際網路金融企業考拉理財的大多數業務都在mongodb上。
  • 傳統:
    這一塊瞭解不多,目前知道東方航空用在了下一代旅客服務系統 。
  • 網際網路:
    網際網路使用的企業非常多。媽媽幫的核心繫統,小紅書的核心繫統,高德的app展示,千尋位置的日誌收集分析,Teambition的核心繫統,陰陽師的資料庫,360的移動搜尋等。

4、Mongodb相對hbase、MySQL來說,有哪些優勢?

這裡就簡單說一下題主說的幾個資料庫中,mongodb優勢的地方。

  • vs hbase:

hbase是基於row key儲存寬列的一款nosql,乍一看結構類似mongodb的_id主鍵和可變長的列數量。
具體的原理和區別這裡不展開。
mongodb的優勢在於輕量化部署非常簡單,不用像hbase那樣搭一整套hadoop叢集,即開即用。hbase更適合離線的海量資料分析。

  • vs mysql pg:

這兩款都是關係型資料庫,所以放在一起比較。
MongoDB的優勢主要有3個。
1、結構靈活,表結構更改比較自由,不用每次alter的時候付出代價,適合業務快速迭代,而且json原生和大多數的語言有天然的契合。還支援陣列,巢狀文件等資料型別
2、自帶高可用,自動主從切換(副本集)
3、自帶水平分片(分片),內建了路由,配置管理。應用只要連線路由,對應用來說是透明的。

5、MongoDB是否支援事務?

MongoDB只支援行級的事務,或者說支援原子性,單行的操作要麼全部成功,要麼全部失敗。
需要事務的話,得自己用程式碼實現二次提交作,模擬事務的功能,官方文件有相關的說明。
https://docs.mongodb.com/manual/tutorial/perform-two-phase-commits/
這裡放一個小彩蛋,因為WiredTiger引擎本身支援事務,官方正考慮在MongoDB上實現事務。

6、MongoDB黑客勒索事件是怎麼回事?

這次鬧的沸沸揚揚的黑客事件主要是使用者自己的MongoDB沒有開啟使用者驗證,而且把MongoDB保護在公網。打個比方就是你家住在鬧市區,晚上沒人的時候,門還沒鎖,然後就被小偷光顧了。
要解決問題很簡單,首先,千,萬,不,要把MongoDB暴露在公網,如果要外網訪問,無論是vpn還是ssh隧道都行。
此外,開啟Mongodb的驗證,這樣所有操作都要使用者名稱密碼了但是短連線會因為驗證造成資源損耗,這裡就自己權衡了。阿里雲和騰訊雲針對這個問題都做了優化。

7、Mongodb資料庫備份只能用mongodump嗎?

常用而且通用的方法就是mongodump
備份還有這幾種方法:

  1. mongoexport(這個是邏輯備份,備份出json和csv)
  2. 做磁碟快照
  3. 停機後冷拷貝

8、Mongo大資料遷移方案,遷移過程中需要注意什麼,叢集的時候呢?

你的遷移是指怎麼遷移?一般來說mongodump來遷移即可。
叢集遷移的話,建議直接在目標伺服器上面搭建從節點。全部搭建完之後,把新的從節點升級為主節點,再把老機器剔除出叢集。
不過如果資料量太大,而且平時資料更改很頻繁的話,初始化同步的過程可能Oplog不夠用。
方案1:
先升級到3.4版本,這個版本在初始化同步的時候會抓取oplog
方案2:
停機一臺從節點,物理複製到區域網中心機器,當從節點啟動
這臺從節點配置一個大oplog,然後遷移目標端的從節點從這臺oplog從節點同步。

9、MONGODB的水平擴充套件是什麼原理?

MONGODB的水平擴充套件是依賴什麼原理哪?如果由於前期規劃不足,導致需要通過擴容的方式提高MOGODB的能力,在給他水平擴充套件的時候是否複雜哪?是否將原有資料重新同步?是否可以線上處理哪?

MongoDB的水平擴充套件主要依賴的原理相當有一個config元件負責管理元資料的位置,然後mongo的路由會從config取得資料所在或者應該在的資料節點位置,從而去對應的資料節點讀寫(路由本身也會有快取)。
在這裡插入圖片描述

我這裡只是簡單的說明,具體可以看官方文件sharding一章節

水平擴充套件的步驟不算複雜,不用將資料重新同步(但是從單點到副本集還是要做同步的),整個過程可以線上處理(不過3.4開始,在設定為sharding模式的時候需要滾動重啟一下mongod程序,加上shardsvr的配置)。
具體看這一篇文件:
https://docs.mongodb.com/manual/tutorial/convert-replica-set-to-replicated-shard-cluster/

10、mongodb叢集實際應用中如何選擇片鍵和索引?

  • 分片方式有兩種:
  1. 範圍分片:這個類似分割槽表,合適的分片條件可以增加查詢效能,更優的設計可以優化寫入效能。
    比如說資料1、2在節點a,資料3、4、5在節點b,資料6、7在節點c
  2. hash分片:使資料均勻落在不同的分片節點上,優化寫入效能,但是讀的話需要掃所有節點
  • 好的片鍵需要以下的考量:
  1. 片鍵中文件儘可能的少,避免單chunk過大,這個會導致無法balance
  2. 片鍵離散分佈,這樣可以在不同的節點寫入(避免自增主鍵或者時間戳單獨的做片鍵,這樣會存在寫入熱點問題)
  3. 大多數的查詢的條件要包含你的分片條件
    舉一個例子:
    一個日誌記錄系統,有hostname,timestamp,message等資訊,經常會有查詢需求,這裡用範圍分片
    很多人可能會直接拿timestamp做範圍片鍵,這樣可以覆蓋到常見的時間查詢需求,但是所有寫的請求都落到同一臺,造成熱點問題。而且查hostname的時候會掃描所有節點。
    好的方案就是選擇hostname和timestamp做一個聯合的分片條件,一來資料分佈更均勻,二來基於主機和時間的查詢也可以優化到。

11、MongoDB如何進行升級?

這裡升級以副本集為例

  • 小版本升級:
    非常簡單,直接停機,替換二進位制檔案,啟動即可。先升級從節點,再升級主節點,避免業務中斷。

  • 大版本升級(不更換儲存引擎):
    也是直接替換即可,有的版本(如升級到3.4),想啟動新版本功能,需要執行
    db.adminCommand( { setFeatureCompatibilityVersion: “3.4” } )

  • 大版本升級(換儲存引擎):
    資料檔案需要重做,新建從節點,升級那個從節點的二進位制檔案,配置使用新的引擎,將資料完整的同步,然後該從節點升級為主節點,其他節點正常升級。
    不建議跨大版本升級,否則會有不確定的問題。

最後,官方文件非常詳細,一步一步的操作都有
https://docs.mongodb.com/manual/release-notes/3.4-upgrade-replica-set/

12、Mongodb升級報錯?

mongodb副本集從2.6升級到3.0,密碼驗證升級了 報如下錯誤
Failed to authenticate [email protected] with mechanism MONGODB-CR: AuthenticationFailed MONGODB-CR credentials missing in the user document
應該如何解決呢? 是把原來的使用者刪了,用3.0的在建立一個一樣的使用者嗎? 有沒有更好的辦法呢?

原因是因為3.0開始mongodb的認證加密模式從Mongodb-cr改到了sha1

  • 治標方法:
    先關閉驗證,然後把
    admin庫中system.version表的
    { “_id” : “authSchema”, “currentVersion” : 3 }
    那個currentVersion改成3(預設是5),就可以了

  • 治本方法:

  1. 升級客戶端的驅動(遲早要升級了,不然不支援新功能)
  2. 上面那個currentVersion別動

參考:https://jira.mongodb.org/browse/SERVER-17459

13、MongoDB在出現負載過高的情況下如何處理?

原來遇到過一次mongodb負載過高的情況,主庫和從庫的負載突然就上來了,CPU佔有率都到了100%,這種情況下,如何處理?mongodb是做的副本集,但是主庫和從庫這個時候是負載同時來的。

簡單點看db.currentop,看mongotop和mongostat,currentop相當於當前所有在執行的任務,看一下是在執行什麼,有多少數量。也可以去slowlog裡面看是否有記錄,然後mongotop和mongostat是用來檢視和平時比有什麼異常資訊。
可能的情況有連線數突然變高,查詢突然變多,有一種查詢沒有索引,建立大表的索引等等。