MongoDB的分片集群
分片集群簡介
在之前有說過關于MongoDB的復制集,復制集主要用來實現自動故障轉移從而達到高可用的目的,然而,隨著業務規模的增長和時間的推移,業務數據量會越來越大,當前業務數據可能只有幾百GB不到,一臺DB服務器足以搞定所有的工作,而一旦業務數據量擴充大幾個TB幾百個TB時,就會產生一臺服務器無法存儲的情況,此時,需要將數據按照一定的規則分配到不同的服務器進行存儲、查詢等,即為分片集群。分片集群要做到的事情就是數據分布式存儲。
分片部署架構
架構設計
先看一張圖:
先做一些解釋:
1.shard片:一般為一臺單獨的服務器,即為一個數據存儲節點,這個存儲節點需要做復制集,實現高可用以及自動故障轉移,一般一個分片集群有多個shard片;
2. config服務器:主要是記錄shard的配置信息(元信息metadata),如數據存儲目錄,日志目錄,端口號,是否開啟了journal等信息,為了保證config服務器的可用性,也做了復制集處理,注意,一旦配置服務器無法使用,則整個集群就不能使用了,一般是獨立的三臺服務器實現冗余備份,這三臺可能每一臺是獨立的復制集架構。
3.Mongos路由進程(Router):應用程序通過驅動程序直接連接router,router啟動時從配置服務器復制集中讀取shared信息,然后將數據實際寫入或讀取(路由)到具體的shard中。
部署配置
注意:此處由于我這邊只有一臺服務器(PC機),所以這里實現的是一個偽集群,部署架構如圖所示:
一個Shard(復制集模式),一個config進程,一個router進程,均在同一臺服務器上面
沿用上一節的復制集作為shard,
啟動:
mongod --dbpath=D:\MongoDB\Server\3.2\data\rs0_0 --logpath=D:\MongoDB\Server\3.2\logs\rs0_0.log --port=40000 --replSet=rs0 mongod --dbpath=D:\MongoDB\Server\3.2\data\rs0_1 --logpath=D:\MongoDB\Server\3.2\logs\rs0_1.log --port=40001 --replSet=rs0 mongod --dbpath=D:\MongoDB\Server\3.2\data\rs0_2 --logpath=D:\MongoDB\Server\3.2\logs\rs0_2.log --port=40002 --replSet=rs0配置服務器啟動:
mongod --dbpath=D:\MongoDB\Server\3.2\data\db_config --logpath=D:\MongoDB\Server\3.2\logs\dbconfig.log --port=40003 --configsvr路由服務器啟動
mongos --logpath=D:\MongoDB\Server\3.2\logs\dbrouter.log --port=40004 --configdb=linfl-PC:40003添加分片信息到集群:
mongo --port 40004 mongos> use admin switched to db admin mongos> sh.addShard("rs0/linfl-PC:40000,linfl-PC:40001") {"ok" : 0,"errmsg" : "can't add shard 'rs0/linfl-PC:40000,linfl-PC:40001' because a local database 'config' exists in another config","code" : 96 }報錯了,原來的rs0由于已經存在config數據庫了,去把他刪掉:
D:\MongoDB\Server\3.2\bin>mongo --port 40000 2017-02-27T16:14:51.454+0800 I CONTROL [main] Hotfix KB2731284 or later update is not installed, will zero-out data files MongoDB shell version: 3.2.9 connecting to: 127.0.0.1:40000/test rs0:PRIMARY> show dbs cms 0.000GB config 0.000GB local 0.000GB test 0.000GB rs0:PRIMARY> use config switched to db config rs0:PRIMARY> db.dropDatabase() { "dropped" : "config", "ok" : 1 }然后重新連接到4004執行添加分片即可,看下狀態:
D:\MongoDB\Server\3.2\bin>mongo --port 40004 2017-02-27T16:15:17.286+0800 I CONTROL [main] Hotfix KB2731284 or later update is not installed, will zero-out data files MongoDB shell version: 3.2.9 connecting to: 127.0.0.1:40004/test mongos> sh.addShard("rs0/linfl-PC:40000,linfl-PC:40001") { "shardAdded" : "rs0", "ok" : 1 } mongos> sh.status() --- Sharding Status ---sharding version: {"_id" : 1,"minCompatibleVersion" : 5,"currentVersion" : 6,"clusterId" : ObjectId("58b3d9df84493cb599359c8b") }shards:{ "_id" : "rs0", "host" : "rs0/linfl-PC:40000,linfl-PC:40001" }active mongoses:"3.2.9" : 1balancer:Currently enabled: yesCurrently running: noFailed balancer rounds in last 5 attempts: 5Last reported error: remote client 192.168.56.1:51845 tried to initiali ze this host as shard rs0, but shard name was previously initialized as configTime of Reported error: Mon Feb 27 2017 16:15:48 GMT+0800Migration Results for the last 24 hours:No recent migrationsdatabases:{ "_id" : "cms", "primary" : "rs0", "partitioned" : false }{ "_id" : "test", "primary" : "rs0", "partitioned" : false }對config數據庫中的各個集合做如下解釋:
mongos> use config switched to db config mongos> show collections actionlog // changelog //保存被分片的集合的任何元數據的改變信息,如chunks的遷移,分割等 chunks //集群中所有的塊信息,塊的數據范圍以及塊所在的片 databases //集群中所有的數據庫 lockpings //追蹤集群中的激活組件 locks//均衡器產生的鎖信息 mongos//所有路由信息 settings//分片集群的配置信息,如chunk大小,均衡器狀態等 shards//集群中所有的片信息 tags version//元信息版本注意:對集群的操作應該都是通過客戶端連接mongos路由來執行。
正常來講,一個完整的生產環境至少需要9個Mongod實例,一個Mongos實例,10臺機器才能組成,而由于可以對部分實例采用合并在一臺機器上進行部署的操作(對資源消耗較低,或對資源消耗的類型不同),能夠得到典型的部署結構如下:
以上部署方案使得每個shard(復制集)中的節點完全分開到不同的服務器上,并將config服務分開,使得其中任何一臺服務器宕機,集群都可正常工作,當然我認為,最少只需要三臺服務器即可構成穩定的集群(3壞1可正常工作),然而卻非典型的架構了。
分片工作機制
MongoDB的分片是基于集合(表)來進行的,要對一個集合分片,就要像使其所在的數據庫支持分片。
集合分片
MongoDB的分片是基于返回的,即任何一個文檔一定位于指定片鍵的某個范圍內,一單片鍵選擇好以后,chunks就會按照片鍵將一部分documents從邏輯上組合在一起
如:對users集合選擇city作為片鍵來分片,如果city字段中存在 ‘beijing’,’guangzhou’,’changsha’,初始時隨機的向集群中插入文檔,由于初始時chunks比較小,沒有達到閾值64MB或10000個文檔,不需要分片,隨著繼續插入,超過chunk閾值后chunk被分割成兩個,最終分步可能如下所示:
開始鍵值 – 結束鍵值 –所在分片
開始鍵值 結束鍵值 所在分片
| -∞ | beijing | rs0 |
| beijing | changsha | rs1 |
| changsha | guangzhou | rs0 |
| guangzhou | ∞ | rs1 |
需要注意的是:chunks所包含的文檔并非物理上包含,而是一種邏輯包含,指標是帶有片鍵的文檔會落在那個范圍內。
使集合支持分片,必須先使數據庫支持分片:
sh.enableSharding('cms')對于已有的集合如果要分片,那么選定片鍵后,需要在片鍵上面首先創建索引,如果集合初始狀態為空,則自動創建索引
查看rs.status()可以看到,如下信息片段:
證明 cms已經支持分片
在已存在的集合中分片
先創建索引:
注意:由于我本地是單臺PC,做分片后看不到效果,但如果有兩個分片,分別為rs0,與rs1,往users中插入數據,最后的結果會是
通過
db.changelog.find()可以看到具體的塊分割過程,當存儲的chunk小于64MB時,不分割,當大于64MB時,開始分割成兩部分,-∞~beijing,beijing~∞,隨著數據的進一步增大,beijing~∞被繼續分割成beijing~guangzhou,guangzhou~∞,這樣,rs0就有三個chunk了,隨后,-∞到beijing的chunk開始發生轉移,從rs0遷移到rs1上面去,依次類推,MongDB就是這樣實現了海量數據的分布式存儲的。
集群平衡器
在上一步的操作中最后講到了塊chunk從rs0遷移到rs1的操作,這個動作是由 平衡器的后臺進程自動完成的。
當一個被分片的集合的所有chunk在集群中分布不均衡時(如200個chunk在rs0,50個在rs1上),平衡器就會將chunk從最多的片上遷移到最少的片上,直到chunk數量基本相等為止。平衡器會根據chunk數量的不同,有不同的規則觸發塊遷移,默認配置為chunk<20,閾值為2,20 < chunk<79閾值為4,chunk>80,閾值為8,這也就是為什么我們在剛才要在chunk為3時才能看到遷移過程的變化。
基本的chunk遷移流程如下所示:
本示例中源片指的是rs0,目標片指的是rs1
集群的寫、讀
集群的讀、寫與單個MongoDB的讀寫是一樣的,對應用程序時透明的,這里主要看分片集群對性能的影響。
片鍵是決定查詢落到哪一個chunk上的依據,這個信息保存在配置服務器上,而索引是針對每個片上的集合來說的,每個片都會為自己的集合創建索引數據,因此,查詢語句中是否包含片鍵與索引對查詢性能影響較大。
可以通過explain解釋執行查看,需要注意幾個點:
nscanned:查詢用到索引時,索引中掃描的文檔數
nscannedObjects:在集合中掃描的文檔數
nscannedAllPlans:所有查詢計劃中掃描的文檔總數
nscanned:選定的某一種查詢計劃下掃描的文檔總數
片鍵選擇策略
好的片鍵應該具有如下特質:
通常我們需要由幾個字段組合作為片鍵,如city+_id,既能夠保證同一city下的文檔盡量分布在同一個片上,_id則保證了chunk能夠一直被分割。
在實際業務中可以考慮order表中 company_id與create_date或id共同組成片鍵。
注意
只有當數據量很大、讀寫請求很高時才適合用分片集群。
參考鏈接
https://docs.mongodb.com/manual/core/sharded-cluster-components
總結
以上是生活随笔為你收集整理的MongoDB的分片集群的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一步一步实战HTML音乐播放器
- 下一篇: WonderTrader高频交易初探及v