1.序言
MongoDB 是一個可擴充套件的高效能,開源,模式自由,面向文件的資料庫。 它使用 C++編寫。MongoDB 包含一下特點:
-
l 面向集合的儲存:適合儲存物件及JSON形式的資料。
-
l 動態查詢:Mongo 支援豐富的查詢方式,查詢指令使用 JSON 形式的標記,可輕易查詢文件中內嵌的物件及陣列。
-
l 完整的索引支援:包括文件內嵌物件及陣列。Mongo 的查詢優化器會分析查詢表示式,並生成一個高效的查詢計劃。
-
l 查詢監視:Mongo包含一個監控工具用於分析資料庫操作效能。
-
l 複製及自動故障轉移:Mongo 資料庫支援伺服器之間的資料複製,支援主-從模式及伺服器之間的相互複製。複製的主要目的是提供冗餘及自動故障轉移。
-
l 高效的傳統儲存方式:支援二進位制資料及大型物件(如:照片或圖片)。
-
l 自動分片以支援雲級別的伸縮性:自動分片功能支援水平的資料庫叢集,可動態新增額外的機器。
2.背景
MongoDB 的主要目標是在鍵值對儲存方式(提供了高效能和高度伸縮性) 以及傳統的 RDBMS(關係性資料庫)系統,集兩者的優勢於一身。Mongo 使用 一下場景:
- l 網站資料:Mongo 非常適合實時的插入,更新與查詢,並具備網站實時資料儲存所需的複製及高度伸縮性。
- l 快取:由於效能很高,Mongo 也適合作為資訊基礎設施的快取層。在系統重啟之後,由 Mongo 搭建的持久化快取可以避免下層的資料來源過載。
- l 大尺寸,低價值的資料:使用傳統的關聯式資料庫儲存一些資料時可能會比較貴,在此之前,很多程式設計師往往會選擇傳統的檔案進行儲存。
- l 高伸縮性的場景:Mongo非常適合由數十或數百臺伺服器組成的資料庫
- l 用於物件及JSON資料的儲存:Mongo的BSON資料格式非常適合文件格式化的儲存及查詢。
注:這裡需要說明下,本文旨在介紹高可用的 MongoDB 叢集;這裡不討論 Hadoop 平臺的 HDFS。可根據公司實際業務需求,選擇合適的儲存系統。
當然 MongDB 也有不適合的場景:
-
l 高度事務性的系統:例如銀行或會計系統。傳統的關係型資料庫目前還是更適用於需要大量原子性複製事物的應用程式。
-
l 傳統的商業智慧應用:針對特定問題的 BI 資料庫會對產生高度優化的查詢方式。對於此類應用,資料倉儲可能時更適合的選擇(如Hadoop套件中的Hive)。
-
l 需要SQL的問題。
3.搭建
3.1環境準備
在 Mongo 的官網下載 Linux 版本安裝包,然後解壓到對應的目錄下;由於資源有限,我們採用 Replica Sets + Sharding 方式來配置高可用。結構圖如下所示:
這裡我說明下這個圖所表達的意思。
- l Shard伺服器:使用Replica Sets確保每個資料節點都具有備份、自動容錯轉移、自動恢復的能力。
-
l 配置伺服器:使用使用3個配置伺服器確保後設資料完整性。
-
l 路由程式:使用3個路由程式實現平衡,提高客戶端接入效能
-
l 3 個分片程式:Shard11,Shard12,Shard13 組成一個副本集,提供Sharding 中 shard1 的功能。
-
l 3 個分片程式:Shard21,Shard22,Shard23 組成一個副本集,提供Sharding 中 Shard2 的功能。
- l 3個配置伺服器程式和3個路由器程式。
構建一個 mongoDB Sharding Cluster 需要三種角色:shard 伺服器(ShardServer)、配置伺服器(config Server)、路由程式(Route Process)
Shard 伺服器
shard 伺服器即儲存實際資料的分片,每個 shard 可以是一個 mongod 例項, 也可以是一組 mongod 例項構成的 Replica Sets.為了實現每個 Shard 內部的故障 自動轉換,MongoDB 官方建議每個 shard 為一組 Replica Sets.
配置伺服器
為了將一個特定的 collection 儲存在多個 shard 中,需要為該 collection 指定
一個 shard key,決定該條記錄屬於哪個 chunk,配置伺服器可以儲存以下資訊,
每個shard節點的配置資訊,每個chunk的shard key範圍,chunk在各shard
的分佈情況,叢集中所有 DB 和 collection 的 sharding 配置資訊。
路由程式
它是一個前段路由,客戶端由此接入,首先詢問配置伺服器需要到哪個 shard 上查詢或儲存記錄,然後連線相應的 shard 執行操作,最後將結果返回給客戶端,客 戶端只需要將原本發給 mongod 的查詢或更新請求原封不動地發給路由程式,而 不必關心所操作的記錄儲存在哪個 shard 上。
按照架構圖,理論上是需要 16 臺機器的,由於資源有限,用目錄來替代物理機(有風險,若其中某臺機器當機,配置在該機器的服務都會 down 掉),下面給出配置表格:
伺服器 |
Host |
服務和埠 |
1 |
10.211.55.28 |
Shard11:10011 Shard21:10021 ConfigSvr:10031 Mongos:10040 |
2 |
10.211.55.28 |
Shard12:10012 Shard22:10022 ConfigSvr:10032 Mongos:10042 |
3 |
10.211.55.28 |
Shard13:10013 Shard23:10023 ConfigSvr:10033 Mongos:10043 |
3.2.環境變數
下面給出 MongoDB 的環境變數配置,輸入命令並配置:
[root@mongo ~]# vi /etc/profile export MONGO_HOME=/root/mongodb-linux-x86_64-2.6.7 export PATH=$PATH:$MONGO_HOME/bin
然後儲存退出,輸入以下命令配置檔案立即生效:
[root@mongo ~]# . /etc/profile
3.3.配置 Shard+Replica Sets
我們分別啟動 Shard1 的所有程式,並設定副本集為:shard1。下面給出啟動 Shard1 的指令碼檔案。
- l shard11.conf
dbpath=/mongodb/data/shard11
logpath=/mongodb/log/shard11.log
pidfilepath=/mongodb/pid/shard11.pid
directoryperdb=true logappend=true replSet=shard1 port=10011 fork=true shardsvr=true journal=true
- l shard12.conf
dbpath=/mongodb/data/shard12
logpath=/mongodb/log/shard12.log
pidfilepath=/mongodb/pid/shard12.pid directoryperdb=true logappend=true replSet=shard1 port=10012 fork=true shardsvr=true journal=true
- l shard13.conf
dbpath=/mongodb/data/shard13 logpath=/mongodb/log/shard13.log pidfilepath=/mongodb/pid/shard13.pid directoryperdb=true logappend=true replSet=shard1 port=10013 fork=true shardsvr=true journal=true
- l shard21.conf
dbpath=/mongodb/data/shard21 logpath=/mongodb/log/shard21.log pidfilepath=/mongodb/pid/shard21.pid directoryperdb=true logappend=true replSet=shard2 port=10021 fork=true shardsvr=true journal=true
- l shard22.conf
dbpath=/mongodb/data/shard22 logpath=/mongodb/log/shard22.log pidfilepath=/mongodb/pid/shard22.pid directoryperdb=true logappend=true replSet=shard2 port=10022 fork=true shardsvr=true journal=true
- l shard23.conf
dbpath=/mongodb/data/shard23 logpath=/mongodb/log/shard23.log pidfilepath=/mongodb/pid/shard23.pid directoryperdb=true logappend=true replSet=shard2 port=10023 fork=true shardsvr=true journal=true
- l config1.conf
dbpath=/mongodb/config/config1
logpath=/mongodb/log/config1.log
pidfilepath=/mongodb/pid/config1.pid directoryperdb=true logappend=true port=10031 fork=true configsvr=true journal=true
- l config2.conf
dbpath=/mongodb/config/config2 logpath=/mongodb/log/config2.log pidfilepath=/mongodb/pid/config2.pid directoryperdb=true logappend=true port=10032 fork=true configsvr=true journal=true
- l config3.conf
dbpath=/mongodb/config/config3 logpath=/mongodb/log/config3.log pidfilepath=/mongodb/pid/config3.pid directoryperdb=true logappend=true port=10033 fork=true configsvr=true journal=true
- route.conf
configdb=mongo:10031,mongo:10032,mongo:10033
pidfilepath=/mongodb/pid/route.pid port=10040 chunkSize=1 logpath=/mongodb/log/route.log logappend=true fork=true
- route2.conf
configdb=mongo:10031,mongo:10032,mongo:10033 pidfilepath=/mongodb/pid/route.pid port=10042 chunkSize=1 logpath=/mongodb/log/route2.log logappend=true fork=true
- route3.conf
configdb=mongo:10031,mongo:10032,mongo:10033 pidfilepath=/mongodb/pid/route3.pid port=10043 chunkSize=1 logpath=/mongodb/log/route3.log logappend=true fork=true
注:配置檔案中的目錄必須存在,不存在需建立。
3.4.啟動批處理
下面給出啟動批處理的指令碼,內容如下:
3.5.引數說明
dbpath:資料存放目錄
logpath:日誌存放路徑
logappend:以追加的方式記錄日誌
replSet:replica set 的名字
port:mongodb 程式所使用的埠號,預設為 27017
fork:以後臺方式執行程式
journal:寫日誌
smallfiles:當提示空間不夠時新增此引數
其他引數
pidfilepath:程式檔案,方便停止 mongodb
directoryperdb:為每一個資料庫按照資料庫名建立資料夾存放
bind_ip:mongodb 所繫結的 ip 地址
oplogSize:mongodb 操作日誌檔案的最大大小。單位為 Mb,預設為硬碟剩餘
空間的 5%
noprealloc:不預先分配儲存
shardsvr:分片
configsvr:配置服務節點
configdb:配置 config 節點到 route 節點
3.6.配置分片的表和片鍵
首先,我們需要登入到路由節點,這裡我們登入到其中一個 10040 埠下的節點。輸入如下命令:
mongo mongo:10040 use admin
db.runCommand({addshard:"shard1/mongo:10011,mongo:10012,mongo:10013"})
db.runCommand({addshard:"shard2/mongo:10021,mongo:10022,mongo:10023"})
db.runCommand({ listshards:1 }) #列出 shard 個數
db.runCommand({enablesharding:"friends"}); #建立 friends 庫 db.runCommand( { shardcollection : "friends.user",key : {id: 1},unique : true } ) # 使用 user 表來做分片,片鍵為 id 且唯一
3.7.驗證
至此,整個叢集的搭建完成,下面我們測試叢集的高可用性。下面給出截圖:
首先是檢視叢集的狀態圖 :
可以看到,叢集中存有資料,這是我之前為了測試存的資料,注意,Mongo 只有資料達到一定量才會分片,所有我插入的資料比較大,每次測試都是 10w 的記錄插入。
下面,我 kill 掉 shard11 服務,看會發生什麼情況?截圖如下:
這裡我已經 kill 了 shard11 的程式服務。接下來,我們在 10040 埠的路由 節點輸入:db.user.stats()檢視狀態,顯示執行正常。截圖如下所示:
同樣可以在該路由節點插入 10w 條記錄,看是否成功,下面給出插入指令碼, 內容如下:
for(var i=1;i<=100000;i++)db.user.save({id:i,value1:"1234567890",value2:"1234567890",value3:"123 4567890",value4:"1234567890"});
4.總結
這片文章就分享到這裡,若在研究的過程中有什麼問題可以加群討論或傳送郵件給我,我會盡我所能為您解答,與君共勉!