设为首页 加入收藏

TOP

MongoDB中shard key的选择(一)
2014-11-24 00:04:35 来源: 作者: 【 】 浏览:24
Tags:MongoDB shard key 选择

MongoDB中shard key的选择
将存储在MongoDB 数据库中的Collection进行分片需要选定分片Key(Shard key),对于分片Key的选定直接决定了集群中数据分布是否均衡、集群性能是否合理。那么我们究竟该选择什么样的字段来作为分片Key呢?有如下几个需要考虑点。
以下述记录日志的Document为例:
www.2cto.com
{
server : "ny153.example.com" ,
application : "apache" ,
time : "2011-01-02T21:21:56.249Z" ,
level : "ERROR" ,
msg : "something is broken"
} www.2cto.com
基数
Mongodb中一个被分片的Collection的所有数据都存放在众多的Chunk中。一个Chunk存放分片字段的一个区间范围的数据。选择一个好的分片字段非常重要,否则就会遭遇到不能被拆分的大Chunk。
用上述的日志为例,如果选择{server:1}来作为一个分片Key的话,一个server上的所有数据都是在同一个Chunk中,很容易想到一个Server上的日志数据会超过200MB(默认Chunk大小)。如果分片Key是{server:1,time:1},那么能够将一个Server上的日志信息进行分片,直至毫秒级别,绝对不会存在不可被拆分的Chunk。
将Chunk的规模维持在一个合理的大小是非常重要的,只有这样数据才能均匀分布,并且移动Chunk的代价也不会过大。
写操作可扩展
使用分片的一个主要原因之一是分散写操作。为了实现这个目标,尽可能的将写操作分散到多个Chunk就尤为重要了。
用上述的日志实例,选择{time:1}来作为分片key将导致所有的写操作都会落在最新的一个Chunk上去,这样就形成了一个热点区域。如果选择{server:1,application:1,time:1}来作为分片Key的话,那么每一个Server上的应用的日志信息将会写在不同的地方,如果有100个Server和应用对,有10台Server,那么每一台Server将会分担1/10的写操作。
www.2cto.com
查询隔离
另外一个需要考虑的是任何一个查询操作将会由多少个分片来来提供服务。最理想的情况是,一个查询操作直接从Mongos进程路由到一个Mongodb上去,并且这个Mongodb拥有该次查询的全部数据。因此,如果你知道最为通用的查询操作的都以server作为一个查询条件的话,以Server作为一个起始的分片Key会使整个集群更加高效。
任何一个查询都能执行,不管使用什么来作为分片Key,但是,如果Mongos进程不知道是哪一个Mongodb的分片拥有要查询的数据的话,Mongos将会让所有的Mongod分片去执行查询操作,再将结果信息汇总起来返回。显而易见,这回增加服务器的响应时间,会增加网络成本,也会无谓的增加了Load。
排序
在需要调用sort()来查询排序后的结果的时候,以分片Key的最左边的字段为依据,Mongos可以按照预先排序的结果来查询最少的分片,并且将结果信息返回给调用者。这样会花最少的时间和资源代价。
相反,如果在利用sort()来排序的时候,排序所依据的字段不是最左侧(起始)的分片Key,那么Mongos将不得不并行的将查询请求传递给每一个分片,然后将各个分片返回的结果合并之后再返回请求方。这个会增加Mongos的额外的负担。
可靠性
选择分片Key的一个非常重要因素是万一某一个分片彻底不可访问了,受到影响的Chunk有多大(即使是用貌似可以信赖的Replica Set)。
假定,有一个类似于Twiter的系统,Comment记录类似如下形式:
www.2cto.com
{
_id: ObjectId("4d084f78a4c8707815a601d7"),
user_id : 42 ,
time : "2011-01-02T21:21:56.249Z" ,
comment : "I am happily using MongoDB",
}
由于这个系统对写操作非常敏感,所以需要将写操作扁平化的分布到所有的Server上去,这个时候就需要用id或者user_id来作为分片Key了。使用Id作为分片Key有最大粒度的扁平化,但是在一个分片宕机的情况下,会影响几乎所有的用户(一些数据丢失了)。如果使用User_id作为分片Key,只有极少比率的用户会收到影响(在存在5个分片的时候,20%的用户受影响),但是这些用户会再也不会看到他们的数据了。
索引优化
正如在别的章节中提到索引的一样,如果只有一部分的索引被读或者更新的话,通常会有更好的性能,因为“活跃”的部分在大多数时间内能驻留在内存中。本文上述的所描述的选择分片Key的方法都是为了最终数据能够均匀的分布,与此同时,每一个Mongod的索引信息也被均匀分布了。相反,使用时间戳作为分片key的起始字段会有利于将常用索引限定在较小的一部分。
假定有一个图片存储系统,图片记录类似于如下形式:
{
_id: ObjectId("4d084f78a4c8707815a601d7"),
www.2cto.com
user_id : 42 ,
title: "sunset at the beach",
upload_time : "2011-01-02T21:21:56.249Z" ,
data: ...,
}
你也能构造一个客户id,让它包括图片上传时间对应的月度信息和一个唯一标志符(ObjectID,数据的 MD5等)。记录看起来就像下面这个样子的:
{
_id: "2011-01-02_4d084f78a4c8707815a601d7",
user_id : 42 ,
title: "sunset at the beach",
upload_time : "2011-01-02T21:21:56.249Z" ,
data: ...,
}
客户id作为分片key,并且这个id也被用于去访问这个Document。即能将数据均衡的分布在各个节点上,也减少了大多数查询所使用的索引比例。
www.2cto.com
更进一步来讲:
在每一个月份的开始,在开最初的一段时间内只有一个Server来存取数据,随着数据量的增长,负载均衡器(balancer)就开始进行分裂和迁移数据块了。为了避免潜在的低效率和迁移数据,预先创建分片范围区间是明智之举。(如果有5个Sever则分5个区间)
可以继续改进,可
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇Postgresql:连接、验证配置 下一篇分布式数据库中间件?(3)Cobar对简..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: