[mongodb翻译]选择合适的shard key
為一個(gè)集合(collection)選擇合適的shard key非常重要。如果這個(gè)集合非常龐大,那么將來(lái)再來(lái)修改shard key將會(huì)很困難。如有任何疑問(wèn)請(qǐng)到論壇或者IRC尋求幫助。
?
示例文檔
view plain- {??
- server?:?"ny153.example.com"?,??
- application?:?"apache"?,??
- time?:?"2011-01-02T21:21:56.249Z"?,??
- level?:?"ERROR"?,??
- msg?:?"something?is?broken"??
- }??
基數(shù)(cardinality)
一個(gè)集合中的所有數(shù)據(jù)會(huì)被分裂為多個(gè)數(shù)據(jù)塊(chunk),一個(gè)數(shù)據(jù)塊包含了某個(gè)范圍shard key的數(shù)據(jù)。請(qǐng)選擇合適的shard key,否則你將會(huì)得到很大的不能分裂的數(shù)據(jù)塊。
使用上面的日志例子,如果你選擇了:
view plain- {server:1}??
作為shard key,那么所有關(guān)于某個(gè)server的數(shù)據(jù)會(huì)存在一個(gè)數(shù)據(jù)塊中,你可以很容易想到一個(gè)server的數(shù)據(jù)會(huì)超過(guò)64MB(默認(rèn)數(shù)據(jù)塊大小)。如果shard key是:
- {server:1,time:1}??
你可以將單個(gè)服務(wù)器的數(shù)據(jù)分裂到毫秒級(jí)。只要你的單個(gè)服務(wù)器不會(huì)有200MB/S,就不會(huì)有不能分裂的數(shù)據(jù)塊。
保持?jǐn)?shù)據(jù)塊在一個(gè)合適大小是很重要的,這樣數(shù)據(jù)就可以在集群中均衡分布并且移動(dòng)一個(gè)數(shù)據(jù)塊代價(jià)也不會(huì)太大。
?
水平寫
使用分片的一個(gè)主要原因就是分發(fā)寫操作。為了達(dá)到這個(gè)目的,寫操作應(yīng)當(dāng)盡可能的分散到不同的數(shù)據(jù)塊。
再次使用前面的例子,選擇:
view plain- {?time?:?1?}??
作為shard key,會(huì)導(dǎo)致所有的寫操作都集中到最新的數(shù)據(jù)塊中。如果shard key選擇:
- {server:1,application:1,time:1}??
那么每個(gè)服務(wù)器:應(yīng)用映射都會(huì)被寫到不同的地方。如果這里有100種服務(wù)器:應(yīng)用映射,和10臺(tái)服務(wù)器,那么每臺(tái)服務(wù)器將會(huì)分配約1/10的寫操作。
需要注意的是,由于ObjectId中很重要的一部分是基于時(shí)間生成的,使用ObjectId作為shard key等同于直接使用時(shí)間值。
?
查詢隔離
另外一個(gè)考慮就是任何一個(gè)查詢需要分發(fā)到多少個(gè)shard。理想情況下,一個(gè)查詢操作經(jīng)mongos直接分發(fā)到擁有期望數(shù)據(jù)的mongod。如果你知道大部分的查詢使用了那些條件,那么使用這些條件屬性作為shard key可以提高很多效率。
即使查詢條件中沒(méi)有包含shard key,查詢依然可以工作。由于mongos不知道哪個(gè)shard擁有期望的數(shù)據(jù),mongos會(huì)將這個(gè)請(qǐng)求順序分發(fā)到所有的shard中,這會(huì)增加響應(yīng)時(shí)間和網(wǎng)絡(luò)數(shù)據(jù)流量及服務(wù)器負(fù)載。
?
排序
如果查詢中包含了排序請(qǐng)求,這個(gè)查詢請(qǐng)求會(huì)同以前沒(méi)有排序要求時(shí)一樣分發(fā)到需要的shard中。每一個(gè)shard執(zhí)行查詢?nèi)缓笤诒镜刈雠判?#xff08;如果有 索引的話會(huì)使用索引)。mongos會(huì)合并從shard返回的已經(jīng)排序好的結(jié)果,然后返回合并后的數(shù)據(jù)給客戶端。這樣的話,mongos只需要做少量的工 作和很少的RAM。
可靠性
分片的一個(gè)重要方面就是如果整個(gè)shard不能訪問(wèn)了(即使使用了可靠的復(fù)制組),這將會(huì)對(duì)整個(gè)系統(tǒng)帶來(lái)多大的影響。
例如你有一個(gè)類似于twitter的系統(tǒng),評(píng)論記錄類似于:
view plain- {??
- _id:?ObjectId("4d084f78a4c8707815a601d7"),??
- user_id?:?42?,??
- time?:?"2011-01-02T21:21:56.249Z"?,??
- comment?:?"I?am?happily?using?MongoDB",??
- }??
由于系統(tǒng)對(duì)寫操作是非常敏感的,如果你希望將寫操作分散到各個(gè)服務(wù)器中,你需要使用"_id"或者"user_id"作為shard key。"_id"可以給你較好的顆粒度和寫擴(kuò)散性。但是一旦某個(gè)shard宕機(jī)了,它將會(huì)影響到幾乎所有的用戶(有些數(shù)據(jù)丟失了)。如果你使 用"user_id"作為shard key,此時(shí)一小部分用戶會(huì)受到影響(比如在5個(gè)shard組成的集群中,這個(gè)百分比是20%),即使這些用戶再也看不到他們的任何數(shù)據(jù)了。
?
索引最佳化
正如前面章節(jié)關(guān)于索引的描述,通常經(jīng)常對(duì)一部分索引做讀/更新會(huì)帶來(lái)較好的性能表現(xiàn),這是因?yàn)檫@“活躍”的部分可以大多數(shù)時(shí)間都駐留在RAM。前面 介紹的shard key雖然可以將寫操作分散到各個(gè)shard中,但是他們還是屬于每個(gè)mongod的索引的。作為替代,將時(shí)間戳分解為某種形式并作為shard key的前綴可以帶來(lái)一些好處,這樣可以減小經(jīng)常訪問(wèn)的索引大小。
例如你有一個(gè)圖片存儲(chǔ)系統(tǒng),圖片記錄類似于:
view plain- {??
- _id:?ObjectId("4d084f78a4c8707815a601d7"),??
- user_id?:?42?,??
- title:?"sunset?at?the?beach",??
- upload_time?:?"2011-01-02T21:21:56.249Z"?,??
- data:?...,??
- }??
你可以定制一個(gè)包含了上傳時(shí)間的月份和唯一的標(biāo)示符(如ObjectId,數(shù)據(jù)的md5值等)的_id來(lái)替代默認(rèn)的_id,新的記錄類似于:
- {??
- _id:?"2011-01_4d084f78a4c8707815a601d7",??
- user_id?:?42?,??
- title:?"sunset?at?the?beach",??
- upload_time?:?"2011-01-02T21:21:56.249Z"?,??
- data:?...,??
- }??
使用它作為shard key,同時(shí)也是訪問(wèn)一個(gè)文檔使用的_id.它可以很好的將寫操作分散到所有shard中。并且它減小了大部分查詢需要訪問(wèn)的索引的大小。
進(jìn)一步注釋:
- ?在每個(gè)月的開始,只有一臺(tái)shard被訪問(wèn)知道均衡器開始分裂數(shù)據(jù)塊。為了避免這種潛在的低性能和數(shù)據(jù)遷移,建議在時(shí)間前面增加了一個(gè)范圍值(比如5或者更大的范圍值如果你有5臺(tái)服務(wù)器)。
- 更進(jìn)一步的改善,你可以將用戶名(user id)納入到圖片id中,這樣可以保持同一個(gè)用戶的文檔都存儲(chǔ)到同一個(gè)shard中,例如:"2011-01_42_4d084f78a4c8707815a601d7"
?
GirdFS
根據(jù)不同的需要,這里有多種不同的方法可以對(duì)GridFS進(jìn)行分片。一種基于已經(jīng)存在的索引的分片方法是:
- "files"集合不做分片。所有的文件記錄都將存儲(chǔ)在一個(gè)shard中,強(qiáng)烈建議保證該shard非常可靠(使用至少3節(jié)點(diǎn)的復(fù)制組)。
- "chunks" 集合應(yīng)當(dāng)使用索引"files_id:1"進(jìn)行分片。由驅(qū)動(dòng)創(chuàng)建的已經(jīng)存在的"files_id,n"索引不能被使用在"files_id"上面進(jìn)行分片 (這是一個(gè)限制,將來(lái)會(huì)被fix)。所以你需要單獨(dú)為"files_id"創(chuàng)建一個(gè)索引。使用"files_id"進(jìn)行分片開始保證某個(gè)文件存儲(chǔ)到同一個(gè) shard中,這樣"filemd5"命令就可以工作了。運(yùn)行命令: view plain
- >?db.fs.chunks.ensureIndex({files_id:?1});??
- >?db.runCommand({?shardcollection?:?"test.fs.chunks",?key?:?{?files_id?:?1?}})??
- {?"collectionsharded"?:?"test.fs.chunks",?"ok"?:?1?}??
files_id默認(rèn)使用ObjectId,因此files_id是遞增的,所有新的GridFS數(shù)據(jù)塊會(huì)被送往同一個(gè)shard。如果你的寫負(fù)載太大以至于單臺(tái)服務(wù)器無(wú)法應(yīng)付,你可能需要考慮使用其他的shard key或者使用其他的值作為file的_id.
轉(zhuǎn)載于:https://www.cnblogs.com/xinghebuluo/archive/2011/11/22/2266204.html
總結(jié)
以上是生活随笔為你收集整理的[mongodb翻译]选择合适的shard key的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。