代码改变世界

Mongodb sharding知识库

2017-07-03 10:07  Kevin.hhl  阅读(401)  评论(0)    收藏  举报

一. MongoDB sharing类型

1.1 Range

[minkey,x1)区间值,都是前闭后开,属于某个chunk,一个chunk只能落到某一个shard,随着集群数据量的增大,如开开启rebalance,chunk也会在shard 之间move 。

 

满足如下特点的适合Range的shard key:

a.基数高。

b.shard key的值不会出现某些值重复(聚集多),简单说值的分布比较均匀。如果可能不均匀,可以考虑多列做shard key。

c.shard key的写入(insert)不是递增或递减的(否则会出现某段时间集中写某个shard,写入不均匀)。

1.2 Hash

目前Hash sharding只支持单列。 

满足如下特点的适合Hash的shard key:

a.基数高(否则容易出现巨大的jumbo chunk,导致无法split)。
b.递增/递减写入的适合分散写入到各个shard。

 

1.3 tag aware sharding/zone

zone 是在3.4 开始引入,是tag aware sharding的升级版本,简单的理解是自定义某些范围的数据到某个zone,每个zone可以包含有若干个shard,这种很方便由DBA来设置数据在物理上的分布,比如说不希望某些范围的数据分布在多个shard,这样可能会影响性能,这种情况下可以指定这些范围的数据在某一个shard;还有跨机房部署sharding,使用zone可以保证数据分布和应用在同一个机房,不会有跨地域。

例子:比如要按照地域省份来做sharding,分布在物理不同的城市的数据落到当地的shard上。

beijing       shanghai    shenzhen    guangzhou            ------> zone

shard01    shard02      shard03       shard04                ------->shard分片   

上面shard01指定到zone: beijing,   shard01指定到zone: beijing,  shard02指定到zone: shanghai,  shard03指定到zone: shenzhen, shard04指定到zone: guangzhou

可以理解zone是shard上的逻辑管理,最后我们要指定各个zone 的数据范围,也既是该zone下所有shard存放数据的范围。

满足如下特点的适合zone的shard key:

a.业务需要指定某些特定的shard key到某些shard上。

b.跨机房部署sharding,业务访问在同一机房的shard。

二. MongoDB Sharding的限制

2.1 不支持group命令。

2.2 单个document 的操作必须包含shard key。   All updateOne(), removeOne(), and deleteOne()。

2.3 跨shard的unique key需要把完整的shard key作为unique key的前缀部分。

三. 如何选择合理的shard key

3.1 从业务/db出发

      比如是db遇到容量问题,写多读少,写是主要瓶颈,此时sharding 要考虑的是分散写入IO,同时要考虑业务读的性能,读请求的数据尽量都在一个shard,保证读取数据的性能。

      业务特点都是选择shard key的关键因素,

3.2 基数

      核心原则:保证shard key 的值比较均匀分布,把chunk维持在一定规模大小,不会产生巨大的chunk,大chunk 很多无法split,导致在shard 间移动代价大。

      考虑作为shard key的基数,如果适合做range sharding 的shard key只有一列,但是该列的基数很低或者有某些值有堆积聚集严重,需要考虑增加一列(比如_id,created_time)

3.3 可靠性

      比如评论数据,id和user_id都是可以作为shard key,它们都可以让数据分布比较均匀,但从系统可靠性考虑,假如某个shard的不可用,如果使用id 作为shard key,几乎大部分用户有评论丢失,影响的范围用户较多,如果使用user_id 作为shard key,一个shard 不可用(比如总共有4个shard),影响的用户大约是1/4。

 3.4 写扩展

      写操作尽量落到每个shard,流量均匀。

3.5 读隔离

      请求读尽量落到同一个shard,不要跨shard读数据,会有性能问题。

3.6 从设计模式上优化shard key

    业务多多维度查询,使业务的写入、查询落到某个shard。shard key 本身就是索引,直接通过shard key查询,减少创建其他索引。

比如下面是
{
_id: ObjectId("4d084f78a4c8707815a601d7"),
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: ...,

为了使同一user的文档都落到某一个shard上,改造_id成如下格式: 

id:   {userid}_2011-01-02__4d084f78a4c8707815a601d7   这样用户按照月份时间维度查询自己上传的图片,都落到同一个shard上。