第44章:MongoDB-集群--Sharding(分片)--分片的片键选择

时间:2021-04-10 20:36:16
①片键选择的重要性

所谓片键,就是用来拆分数据的字段,通常为1-2个字段,由于片键一旦确定,并已经分片过后,基本上就不可能再修改片键了,因此初期设计和选择就非常重要了

②片键规则

1:不可以是数组

2:一旦插入了文档,片键不可修改,要修改就必须先删除文档,然后才能修改片键

3:大多数特殊类型的索引都不能作为片键

4:片键的数据取值应该是多样的,这样才利于分片

③片键的几种类型

1:小基数片键

就是片键可取的值非常少,所以叫小基数。通常这不是个好方式,因为:片键有N个值,也就最多只能有N个块,也就是最多只能N个分片。这也意味着当某个块越来越大的时候,MongoDB无法拆分块,因此你什么也干不了,除了购买更大的硬盘。

2:升序片键

就是片键值是不断增加的,类似于自增字段。通常这不是个好方式,因为:

(1)新加入的数据始终会加入最后一个块,即所有数据都被添加到一个块上,从而导致了热点必然存在,且是单一,不可分割的热点。

(2)由于数据始终会先加入到最大块,会导致最大块需要不断的拆分出新的小块

(3)会导致数据均衡处理很困难,因为所有的新快都是由同一个分片创建的

3:随机分发的片键

就是片键值是随机散列的数据,这种方式对数据的均衡是有好处的,数据加载速度也很快,缺点是:如果需要按照片键值进行范围查找的话,就必须到所有分片上执行了。

创建一个散列片键,需要先创建散列索引,示例如下:

db.users.ensureIndex({“userId”:”hashed”});

然后对集合分片,示例如下:

sh.shardCollection(“mydb.users”,{“userId”:”hashed”});

4:基于某个业务的片键

这个就要具体问题具体分析和选择了,比如:选择用户IP,电话号码段,或者是自定义的编码段等。如果要指定特定范围的块出现在特定的分片中,可以为分片添加tag,然后为块指定tag,例如:

sh.addShardTag(“myrep2”,“gtu”) 然后:

sh.addTagRange("mydb.users",{"userId":"v0"},{"userId":"v9"},"gtu");

就可以设定v0-v9的数据存放到myrep2这个分片里面去

(1)在设置范围的时候,可以使用:ObjectId()、MinKey、MaxKey 等来作为值

(2)不用某个tag了可以删除:sh.removeShardTag(“myrep2”,“gtu”);

④好片键的建议

实际项目中,建议尽量采用准升序键加查询键构成组合片键。

其中升序键的每个值最好能对应几十到几百个数据块,而查询键则是应用程序通常都回依据其进行查询的字段。

例如:某应用,用户会定期访问过去一个月的数据,就可以在{month:1,user:1}上进行分片,month是一个粗粒度的升序字段,每个月都会增大;而user是经常会查询某特定

用户数据的查询字段。

1:注意一点:查询键不可以是升序字段,否则该片键会退化成为一个升序片键,照样会面临

热点问题

2:通常通过准升序键来控制数据局部化,而查询键则是应用上常用的查询字段