MongoDB之 Sharded cluster架構(gòu)原理

MongoDB之 Sharded cluster架構(gòu)原理

為什么需要Sharded cluster?

MongoDB目前3大核心優(yōu)勢(shì):『靈活模式』+ 『高可用性』 + 『可擴(kuò)展性』,通過(guò)json文檔來(lái)實(shí)現(xiàn)靈活模式,通過(guò)復(fù)制集(https://yq.aliyun.com/articles/64?spm=0.0.0.0.9jrPm8)來(lái)保證高可用,通過(guò)Sharded cluster來(lái)保證可擴(kuò)展性。

當(dāng)MongoDB復(fù)制集遇到下面的業(yè)務(wù)場(chǎng)景時(shí),你就需要考慮使用Sharded cluster

●存儲(chǔ)容量需求超出單機(jī)磁盤容量

●活躍的數(shù)據(jù)集超出單機(jī)內(nèi)存容量,導(dǎo)致很多請(qǐng)求都要從磁盤讀取數(shù)據(jù),影響性能

●寫IOPS超出單個(gè)MongoDB節(jié)點(diǎn)的寫服務(wù)能力

如上圖所示,Sharding Cluster使得集合的數(shù)據(jù)可以分散到多個(gè)Shard(復(fù)制集或者單個(gè)Mongod節(jié)點(diǎn))存儲(chǔ),使得MongoDB具備了橫向擴(kuò)展(Scale out)的能力,豐富了MongoDB的應(yīng)用場(chǎng)景。

Sharded cluster架構(gòu)

Sharded cluster由Shard、Mongos和Config server 3個(gè)組件構(gòu)成。

Mongos是Sharded cluster的訪問(wèn)入口,強(qiáng)烈建議所有的管理操作、讀寫操作都通過(guò)mongos來(lái)完成,以保證cluster多個(gè)組件處于一致的狀態(tài)。

Mongos本身并不持久化數(shù)據(jù),Sharded cluster所有的元數(shù)據(jù)都會(huì)存儲(chǔ)到Config Server(下一節(jié)詳細(xì)介紹),而用戶的數(shù)據(jù)則會(huì)分散存儲(chǔ)到各個(gè)shard。Mongos啟動(dòng)后,會(huì)從config server加載元數(shù)據(jù),開始提供服務(wù),將用戶的請(qǐng)求正確路由到對(duì)應(yīng)的Shard。

數(shù)據(jù)分布策略

Sharded cluster支持將單個(gè)集合的數(shù)據(jù)分散存儲(chǔ)在多個(gè)shard上,用戶可以指定根據(jù)集合內(nèi)文檔的某個(gè)字段即shard key來(lái)分布數(shù)據(jù),目前主要支持2種數(shù)據(jù)分布的策略,范圍分片(Range based sharding)或hash分片(Hash based sharding)。

范圍分片

如上圖所示,集合根據(jù)x字段來(lái)分片,x的取值范圍為[minKey, maxKey](x為整型,這里的minKey、maxKey為整型的最小值和最大值),將整個(gè)取值范圍劃分為多個(gè)chunk,每個(gè)chunk(通常配置為64MB)包含其中一小段的數(shù)據(jù)。

Chunk1包含x的取值在[minKey, -75)的所有文檔,而Chunk2包含x取值在[-75, 25)之間的所有文檔… 每個(gè)chunk的數(shù)據(jù)都存儲(chǔ)在同一個(gè)Shard上,每個(gè)Shard可以存儲(chǔ)很多個(gè)chunk,chunk存儲(chǔ)在哪個(gè)shard的信息會(huì)存儲(chǔ)在Config server種,mongos也會(huì)根據(jù)各個(gè)shard上的chunk的數(shù)量來(lái)自動(dòng)做負(fù)載均衡。

范圍分片能很好的滿足『范圍查詢』的需求,比如想查詢x的值在[-30, 10]之間的所有文檔,這時(shí)mongos直接能將請(qǐng)求路由到Chunk2,就能查詢出所有符合條件的文檔。

范圍分片的缺點(diǎn)在于,如果shardkey有明顯遞增(或者遞減)趨勢(shì),則新插入的文檔多會(huì)分布到同一個(gè)chunk,無(wú)法擴(kuò)展寫的能力,比如使用_id作為shard key,而MongoDB自動(dòng)生成的id高位是時(shí)間戳,是持續(xù)遞增的。

Hash分片

Hash分片是根據(jù)用戶的shard key計(jì)算hash值(64bit整型),根據(jù)hash值按照『范圍分片』的策略將文檔分布到不同的chunk。

Hash分片與范圍分片互補(bǔ),能將文檔隨機(jī)的分散到各個(gè)chunk,充分的擴(kuò)展寫能力,彌補(bǔ)了范圍分片的不足,但不能高效的服務(wù)范圍查詢,所有的范圍查詢要分發(fā)到后端所有的Shard才能找出滿足條件的文檔。

合理的選擇shard key

選擇shard key時(shí),要根據(jù)業(yè)務(wù)的需求及『范圍分片』和『Hash分片』2種方式的優(yōu)缺點(diǎn)合理選擇,同時(shí)還要注意shard key的取值一定要足夠多,否則會(huì)出現(xiàn)單個(gè)jumbo chunk,即單個(gè)chunk非常大并且無(wú)法分裂(split);比如某集合存儲(chǔ)用戶的信息,按照age字段分片,而age的取值非常有限,必定會(huì)導(dǎo)致單個(gè)chunk非常大。

Mongos

Mongos作為Sharded cluster的訪問(wèn)入口,所有的請(qǐng)求都由mongos來(lái)路由、分發(fā)、合并,這些動(dòng)作對(duì)客戶端driver透明,用戶連接mongos就像連接mongod一樣使用。

Mongos會(huì)根據(jù)請(qǐng)求類型及shard key將請(qǐng)求路由到對(duì)應(yīng)的Shard

查詢請(qǐng)求

●查詢請(qǐng)求不包含shard key,則必須將查詢分發(fā)到所有的shard,然后合并查詢結(jié)果返回給客戶端

●查詢請(qǐng)求包含shard key,則直接根據(jù)shard key計(jì)算出需要查詢的chunk,向?qū)?yīng)的shard發(fā)送查詢請(qǐng)求

寫請(qǐng)求

寫操作必須包含shard key,mongos根據(jù)shard key算出文檔應(yīng)該存儲(chǔ)到哪個(gè)chunk,然后將寫請(qǐng)求發(fā)送到chunk所在的shard。

更新/刪除請(qǐng)求

更新、刪除請(qǐng)求的查詢條件必須包含shard key或者_(dá)id,如果是包含shard key,則直接路由到指定的chunk,如果只包含_id,則需將請(qǐng)求發(fā)送至所有的shard。

其他命令請(qǐng)求

除增刪改查外的其他命令請(qǐng)求處理方式都不盡相同,有各自的處理邏輯,比如listDatabases命令,會(huì)向每個(gè)Shard及Config Server轉(zhuǎn)發(fā)listDatabases請(qǐng)求,然后將結(jié)果進(jìn)行合并。

Config Server

config database

Config server存儲(chǔ)Sharded cluster的所有元數(shù)據(jù),所有的元數(shù)據(jù)都存儲(chǔ)在config數(shù)據(jù)庫(kù),3.2版本后,Config Server可部署為一個(gè)獨(dú)立的復(fù)制集,極大的方便了Sharded cluster的運(yùn)維管理。

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集合存儲(chǔ)各個(gè)Shard的信息,可通過(guò)addShard、removeShard命令來(lái)動(dòng)態(tài)的從Sharded cluster里增加或移除shard。如下所示,cluster目前擁有2個(gè)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集合存儲(chǔ)所有數(shù)據(jù)庫(kù)的信息,包括DB是否開啟分片,primary shard信息,對(duì)于數(shù)據(jù)庫(kù)內(nèi)沒有開啟分片的集合,所有的數(shù)據(jù)都會(huì)存儲(chǔ)在數(shù)據(jù)庫(kù)的primary shard上。

如下所示,shtest數(shù)據(jù)庫(kù)是開啟分片的(通過(guò)enableSharding命令),primary shard為mongo-9003; 而test數(shù)據(jù)庫(kù)沒有開啟分片,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ù)庫(kù)創(chuàng)建時(shí),為用戶選擇當(dāng)前存儲(chǔ)數(shù)據(jù)量最小的shard作為數(shù)據(jù)庫(kù)的primary shard,用戶也可調(diào)用movePrimary命令來(lái)改變primary shard以實(shí)現(xiàn)負(fù)載均衡,一旦primary shard發(fā)生改變,mongos會(huì)自動(dòng)將數(shù)據(jù)遷移到的新的primary shard上。

config.colletions

數(shù)據(jù)分片是針對(duì)集合維度的,某個(gè)數(shù)據(jù)庫(kù)開啟分片功能后,如果需要讓其中的集合分片存儲(chǔ),則需調(diào)用shardCollection命令來(lái)針對(duì)集合開啟分片。

如下命令,針對(duì)shtest數(shù)據(jù)里的hello集合開啟分片,使用x字段作為shard key來(lái)進(jìn)行范圍分片。

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

集合分片開啟后,默認(rèn)會(huì)創(chuàng)建一個(gè)新的chunk,shard key取值[minKey, maxKey]內(nèi)的文檔(即所有的文檔)都會(huì)存儲(chǔ)到這個(gè)chunk。當(dāng)使用Hash分片策略時(shí),可以預(yù)先創(chuàng)建多個(gè)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ù)量增加到一定閾值時(shí),會(huì)觸發(fā)chunk分裂,將一個(gè)chunk的范圍分裂為多個(gè)chunk,當(dāng)各個(gè)shard上chunk數(shù)量不均衡時(shí),會(huì)觸發(fā)chunk在shard間的遷移。如下所示,shtest.coll的一個(gè)chunk,在寫入數(shù)據(jù)后分裂成3個(gè)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集合里主要存儲(chǔ)sharded cluster的配置信息,比如chunk size,是否開啟balancer等

mongos> db.settings.find()

{ "_id" : "chunksize", "value" : NumberLong(64) }

{ "_id" : "balancer", "stopped" : false }

其他集合

●config.tags主要存儲(chǔ)sharding cluster標(biāo)簽(tag)相關(guān)的你洗,以實(shí)現(xiàn)根據(jù)tag來(lái)分布chunk的功能;

●config.changelog主要存儲(chǔ)sharding cluster里的所有變更操作,比如balancer遷移chunk的動(dòng)作就會(huì)記錄到changelog里;

●config.mongos存儲(chǔ)當(dāng)前集群所有mongos的信息;

●config.locks存儲(chǔ)鎖相關(guān)的信息,對(duì)某個(gè)集合進(jìn)行操作時(shí),比如moveChunk,需要先獲取鎖,避免多個(gè)mongos同時(shí)遷移同一個(gè)集合的chunk。

來(lái)源:數(shù)據(jù)庫(kù)內(nèi)核月報(bào)

原文:http://mysql.taobao.org/monthly/2016/05/08/

如有侵權(quán)或不周之處,敬請(qǐng)勞煩聯(lián)系若飛(微信:1321113940)馬上刪除,謝謝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,197評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,415評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,104評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,884評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,647評(píng)論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,130評(píng)論 1 323
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,208評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,366評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,887評(píng)論 1 334
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,737評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,939評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,478評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,174評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,586評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,827評(píng)論 1 283
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,608評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,914評(píng)論 2 372

推薦閱讀更多精彩內(nèi)容