MongoDB之 Sharded cluster架構(gòu)原理
為什么需要Sharded cluster跋理?
MongoDB目前3大核心優(yōu)勢:『靈活模式』+ 『高可用性』 + 『可擴展性』拜效,通過json文檔來實現(xiàn)靈活模式,通過復(fù)制集(https://yq.aliyun.com/articles/64?spm=0.0.0.0.9jrPm8)來保證高可用拭荤,通過Sharded cluster來保證可擴展性。
當(dāng)MongoDB復(fù)制集遇到下面的業(yè)務(wù)場景時秘蛔,你就需要考慮使用Sharded cluster
●存儲容量需求超出單機磁盤容量
●活躍的數(shù)據(jù)集超出單機內(nèi)存容量糠排,導(dǎo)致很多請求都要從磁盤讀取數(shù)據(jù),影響性能
●寫IOPS超出單個MongoDB節(jié)點的寫服務(wù)能力
如上圖所示蠢壹,Sharding Cluster使得集合的數(shù)據(jù)可以分散到多個Shard(復(fù)制集或者單個Mongod節(jié)點)存儲嗓违,使得MongoDB具備了橫向擴展(Scale out)的能力,豐富了MongoDB的應(yīng)用場景图贸。
Sharded cluster架構(gòu)
Sharded cluster由Shard蹂季、Mongos和Config server 3個組件構(gòu)成冕广。
Mongos是Sharded cluster的訪問入口,強烈建議所有的管理操作偿洁、讀寫操作都通過mongos來完成撒汉,以保證cluster多個組件處于一致的狀態(tài)。
Mongos本身并不持久化數(shù)據(jù)涕滋,Sharded cluster所有的元數(shù)據(jù)都會存儲到Config Server(下一節(jié)詳細介紹)睬辐,而用戶的數(shù)據(jù)則會分散存儲到各個shard。Mongos啟動后宾肺,會從config server加載元數(shù)據(jù)溯饵,開始提供服務(wù),將用戶的請求正確路由到對應(yīng)的Shard锨用。
數(shù)據(jù)分布策略
Sharded cluster支持將單個集合的數(shù)據(jù)分散存儲在多個shard上丰刊,用戶可以指定根據(jù)集合內(nèi)文檔的某個字段即shard key來分布數(shù)據(jù),目前主要支持2種數(shù)據(jù)分布的策略增拥,范圍分片(Range based sharding)或hash分片(Hash based sharding)啄巧。
范圍分片
如上圖所示,集合根據(jù)x字段來分片跪者,x的取值范圍為[minKey, maxKey](x為整型棵帽,這里的minKey、maxKey為整型的最小值和最大值)渣玲,將整個取值范圍劃分為多個chunk,每個chunk(通常配置為64MB)包含其中一小段的數(shù)據(jù)弟晚。
Chunk1包含x的取值在[minKey, -75)的所有文檔忘衍,而Chunk2包含x取值在[-75, 25)之間的所有文檔… 每個chunk的數(shù)據(jù)都存儲在同一個Shard上,每個Shard可以存儲很多個chunk卿城,chunk存儲在哪個shard的信息會存儲在Config server種枚钓,mongos也會根據(jù)各個shard上的chunk的數(shù)量來自動做負載均衡。
范圍分片能很好的滿足『范圍查詢』的需求瑟押,比如想查詢x的值在[-30, 10]之間的所有文檔搀捷,這時mongos直接能將請求路由到Chunk2,就能查詢出所有符合條件的文檔多望。
范圍分片的缺點在于嫩舟,如果shardkey有明顯遞增(或者遞減)趨勢,則新插入的文檔多會分布到同一個chunk怀偷,無法擴展寫的能力家厌,比如使用_id作為shard key,而MongoDB自動生成的id高位是時間戳椎工,是持續(xù)遞增的饭于。
Hash分片
Hash分片是根據(jù)用戶的shard key計算hash值(64bit整型)蜀踏,根據(jù)hash值按照『范圍分片』的策略將文檔分布到不同的chunk。
Hash分片與范圍分片互補掰吕,能將文檔隨機的分散到各個chunk果覆,充分的擴展寫能力,彌補了范圍分片的不足殖熟,但不能高效的服務(wù)范圍查詢局待,所有的范圍查詢要分發(fā)到后端所有的Shard才能找出滿足條件的文檔。
合理的選擇shard key
選擇shard key時吗讶,要根據(jù)業(yè)務(wù)的需求及『范圍分片』和『Hash分片』2種方式的優(yōu)缺點合理選擇燎猛,同時還要注意shard key的取值一定要足夠多,否則會出現(xiàn)單個jumbo chunk照皆,即單個chunk非常大并且無法分裂(split)重绷;比如某集合存儲用戶的信息,按照age字段分片膜毁,而age的取值非常有限昭卓,必定會導(dǎo)致單個chunk非常大。
Mongos
Mongos作為Sharded cluster的訪問入口瘟滨,所有的請求都由mongos來路由候醒、分發(fā)、合并杂瘸,這些動作對客戶端driver透明倒淫,用戶連接mongos就像連接mongod一樣使用。
Mongos會根據(jù)請求類型及shard key將請求路由到對應(yīng)的Shard
查詢請求
●查詢請求不包含shard key败玉,則必須將查詢分發(fā)到所有的shard敌土,然后合并查詢結(jié)果返回給客戶端
●查詢請求包含shard key,則直接根據(jù)shard key計算出需要查詢的chunk运翼,向?qū)?yīng)的shard發(fā)送查詢請求
寫請求
寫操作必須包含shard key返干,mongos根據(jù)shard key算出文檔應(yīng)該存儲到哪個chunk,然后將寫請求發(fā)送到chunk所在的shard血淌。
更新/刪除請求
更新矩欠、刪除請求的查詢條件必須包含shard key或者_id,如果是包含shard key悠夯,則直接路由到指定的chunk癌淮,如果只包含_id,則需將請求發(fā)送至所有的shard疗疟。
其他命令請求
除增刪改查外的其他命令請求處理方式都不盡相同该默,有各自的處理邏輯,比如listDatabases命令策彤,會向每個Shard及Config Server轉(zhuǎn)發(fā)listDatabases請求栓袖,然后將結(jié)果進行合并匣摘。
Config Server
config database
Config server存儲Sharded cluster的所有元數(shù)據(jù),所有的元數(shù)據(jù)都存儲在config數(shù)據(jù)庫裹刮,3.2版本后音榜,Config Server可部署為一個獨立的復(fù)制集,極大的方便了Sharded cluster的運維管理捧弃。
mongos> use config
switched to db config
mongos> db.getCollectionNames()
[
"shards",
"actionlog",
"chunks",
"mongos",
"collections",
"lockpings",
"settings",
"version",
"locks",
"databases",
"tags",
"changelog"
]
config.shards
config.shards集合存儲各個Shard的信息赠叼,可通過addShard、removeShard命令來動態(tài)的從Sharded cluster里增加或移除shard违霞。如下所示嘴办,cluster目前擁有2個shard,均為復(fù)制集买鸽。
mongos> db.addShard("mongo-9003/10.1.72.135:9003,10.1.72.136:9003,10.1.72.137:9003")
mongos> db.addShard("mongo-9003/10.1.72.135:9003,10.1.72.136:9003,10.1.72.137:9003")
mongos> db.shards.find()
{ "_id" : "mongo-9003", "host" : "mongo-9003/10.1.72.135:9003,10.1.72.136:9003,10.1.72.137:9003" }
{ "_id" : "mongo-9004", "host" : "mongo-9004/10.1.72.135:9004,10.1.72.136:9004,10.1.72.137:9004" }
config.databases
config.databases集合存儲所有數(shù)據(jù)庫的信息涧郊,包括DB是否開啟分片,primary shard信息眼五,對于數(shù)據(jù)庫內(nèi)沒有開啟分片的集合妆艘,所有的數(shù)據(jù)都會存儲在數(shù)據(jù)庫的primary shard上。
如下所示看幼,shtest數(shù)據(jù)庫是開啟分片的(通過enableSharding命令)批旺,primary shard為mongo-9003; 而test數(shù)據(jù)庫沒有開啟分片诵姜,primary shard為mongo-9003汽煮。
mongos> sh.enableSharding("shtest") { "ok" : 1 }
mongos> db.databases.find()
{ "_id" : "shtest", "primary" : "mongo-9003", "partitioned" : true }
{ "_id" : "test", "primary" : "mongo-9003", "partitioned" : false }
Sharded cluster在數(shù)據(jù)庫創(chuàng)建時,為用戶選擇當(dāng)前存儲數(shù)據(jù)量最小的shard作為數(shù)據(jù)庫的primary shard棚唆,用戶也可調(diào)用movePrimary命令來改變primary shard以實現(xiàn)負載均衡逗物,一旦primary shard發(fā)生改變,mongos會自動將數(shù)據(jù)遷移到的新的primary shard上瑟俭。
config.colletions
數(shù)據(jù)分片是針對集合維度的,某個數(shù)據(jù)庫開啟分片功能后契邀,如果需要讓其中的集合分片存儲摆寄,則需調(diào)用shardCollection命令來針對集合開啟分片。
如下命令坯门,針對shtest數(shù)據(jù)里的hello集合開啟分片微饥,使用x字段作為shard key來進行范圍分片。
mongos> sh.shardCollection("shtest.coll", {x: 1})
{ "collectionsharded" : "shtest.coll", "ok" : 1 }
mongos> db.collections.find()
{ "_id" : "shtest.coll", "lastmodEpoch" : ObjectId("57175142c34046c3b556d302"), "lastmod" : ISODate("1970-02-19T17:02:47.296Z"), "dropped" : false, "key" : { "x" : 1 }, "unique" : false }
config.chunks
集合分片開啟后古戴,默認會創(chuàng)建一個新的chunk欠橘,shard key取值[minKey, maxKey]內(nèi)的文檔(即所有的文檔)都會存儲到這個chunk。當(dāng)使用Hash分片策略時现恼,可以預(yù)先創(chuàng)建多個chunk肃续,以減少chunk的遷移黍檩。
mongos> db.chunks.find({ns: "shtest.coll"})
{ "_id" : "shtest.coll-x_MinKey", "ns" : "shtest.coll", "min" : { "x" : { "$minKey" : 1 } }, "max" : { "x" : { "$maxKey" : 1 } }, "shard" : "mongo-9003", "lastmod" : Timestamp(1, 0), "lastmodEpoch" : ObjectId("5717530fc34046c3b556d361") }
當(dāng)chunk里寫入的數(shù)據(jù)量增加到一定閾值時,會觸發(fā)chunk分裂始锚,將一個chunk的范圍分裂為多個chunk刽酱,當(dāng)各個shard上chunk數(shù)量不均衡時,會觸發(fā)chunk在shard間的遷移瞧捌。如下所示棵里,shtest.coll的一個chunk,在寫入數(shù)據(jù)后分裂成3個chunk姐呐。
mongos> use shtest
mongos> for (var i = 0; i < 10000; i++) { db.coll.insert( {x: i} ); }
mongos> use config
mongos> db.chunks.find({ns: "shtest.coll"})
{ "_id" : "shtest.coll-x_MinKey", "lastmod" : Timestamp(5, 1), "lastmodEpoch" : ObjectId("5703a512a7f97d0799416e2b"), "ns" : "shtest.coll", "min" : { "x" : { "$minKey" : 1 } }, "max" : { "x" : 1 }, "shard" : "mongo-9003" }
{ "_id" : "shtest.coll-x_1.0", "lastmod" : Timestamp(4, 0), "lastmodEpoch" : ObjectId("5703a512a7f97d0799416e2b"), "ns" : "shtest.coll", "min" : { "x" : 1 }, "max" : { "x" : 31 }, "shard" : "mongo-9003" }
{ "_id" : "shtest.coll-x_31.0", "lastmod" : Timestamp(5, 0), "lastmodEpoch" : ObjectId("5703a512a7f97d0799416e2b"), "ns" : "shtest.coll", "min" : { "x" : 31 }, "max" : { "x" : { "$maxKey" : 1 } }, "shard" : "mongo-9004" }
config.settings
config.settings集合里主要存儲sharded cluster的配置信息殿怜,比如chunk size,是否開啟balancer等
mongos> db.settings.find()
{ "_id" : "chunksize", "value" : NumberLong(64) }
{ "_id" : "balancer", "stopped" : false }
其他集合
●config.tags主要存儲sharding cluster標簽(tag)相關(guān)的你洗曙砂,以實現(xiàn)根據(jù)tag來分布chunk的功能头谜;
●config.changelog主要存儲sharding cluster里的所有變更操作,比如balancer遷移chunk的動作就會記錄到changelog里麦轰;
●config.mongos存儲當(dāng)前集群所有mongos的信息乔夯;
●config.locks存儲鎖相關(guān)的信息,對某個集合進行操作時款侵,比如moveChunk末荐,需要先獲取鎖,避免多個mongos同時遷移同一個集合的chunk新锈。
來源:數(shù)據(jù)庫內(nèi)核月報
原文:http://mysql.taobao.org/monthly/2016/05/08/
如有侵權(quán)或不周之處甲脏,敬請勞煩聯(lián)系若飛(微信:1321113940)馬上刪除,謝謝妹笆!