MongoDB分片键的选择和案例实例详解

 更新时间:2018年05月31日 10:37:19   作者:pursuer.chen  
分片集群中良好的查询性能都依赖于正确选择分片键。下面这篇文章主要给大家介绍了关于MongoDB分片键的选择和案例的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧

前言

分片键选择不好,应用程序就无法利用分片集群所提供的诸多优势。在这种情况下,插入和查询的性能都会显著下降。下决定时一定要严肃,一旦选择了分片键,就必须坚持选择,分片键是不可以修改的。要让分片键提供好的体验,部分源自了解怎样才算一个好的分片键。

本文将详细介绍关于MongoDB分片键的选择和案例,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。

MongoDB版本:3.6

一、分片键类别

1.升序片键

升序片键例如:日期时间字段、自增字段。

2.随机分发片键

随机分发片键例如:用户名、邮件名、UUID、MD5值或者是其它的一些没有规律的值的列。

3.基于位置的片键

基于位置的片键例如:IP、经纬度、居住地址等。

二、分片策略

1.范围分片

创建分片时,只在主分片上创建了一个块{ "username" : { "$minKey" : 1 } } -->> { "username" : { "$maxKey" : 1 } } on : rs-a Timestamp(1, 0)

至少得3个不同的值才会进行块切分,相同的值只会在一个分片块中。比如对一个name字段进行范围分区,如果一直往name字段插入"a",那么它会一直存储主分片的{ "username" : { "$minKey" : 1 } } -->> { "username" : { "$maxKey" : 1 } }中,直到name出现三个不同的值,比如“a”,“b”,“c”这个时候就会进行分片。当然这只是测试,现实中不会对这种粗粒度的字段单独做分片。

2.hashed分片

创建分片时,默认在每个分片上创建了两个数据块。但是当前每个块上面是没有数据的。

3.组合分片

组合分片是比较好的一种分片的选择,好的组合分片可以同时解决热点和随机读IO问题。例如:

sh.shardCollection("test.bbbb",{"username":1,"_id":1});

4.标签分片

比如对于一些日志非查询文档,可以通过标签将其只插入到某个分片中。例如

sh.addTagRange("test.log",{ "_id" : { "$minKey" : 1 } }, { "_id" : { "$maxKey" : 1 } },"tag_rs-a");

可以在config库中的tag文档中查看设置的标签信息。

use config

db.tags.find();

三、标签

可以通过标签将特定范围的数据在指定的分片中。

{ "_id" : 18000 } -->> { "_id" : 26000 }范围的数据保存到rs-a的分片上,这部分数据跨越了两个数据块。

1.为分片指定tag

sh.addShardTag("rs-a","tag_rs-a");

sh.addShardTag("rs-b","tag_rs-b");

sh.addShardTag("rs-c","tag_rs-c");

2.创建规则

sh.addTagRange("test.person",{ "_id" : 18000 }, { "_id" : 26000 },"tag_rs-a");

数据{ "_id" : 18000 } -->> { "_id" : 26000 }已经被移动到了rs-a分片上。

四、分片案例

分片策略没有绝对的好坏,针对不同的业务场景选择不同的分片策略。

1.分片情景

1.所有的分片读写都均匀。

2.数据访问均匀,而不是随机性的访问;由于新数据都是先在内存中创建,尽量避免需要从磁盘访问新数据。

3.尽量避免由于数据块的数据移动导致数据从磁盘加载到内存中从而导致热数据被清理出内存。

4.组合字段分片可能会是理想的分片方案。

分片键公式: {coarseLocality:1,search:1}

coarseLocality:应该是一个大粒度的局部字段。比如MONTH月份升序字段。

search:是一个经常用来查找的字段。

2.分片案例

案例1.使用日期字段、自增字段、时间戳分片的问题

有一个网站浏览记录表,表中有一个createtime字段用来记录每天记录的插入时间。

对于这类文档不太适合使用createtime字段作为分片字段,因为读写可能都会集中在最新的分片上。使用自增字段也存在同样的问题

案例2.大粒度字段分片问题

有一个五大洲的用户文档表,表中有一个continent字段存储用户所在洲。

如果使用continent作为分片字段会存在以下几个问题:

1.分片的粒度太大了,会导致最后每一个分片的数据都非常的大而且没有再分的可能。而且也有可能会导致磁盘空间不够的情况。

2.可能会导致某个分片在某个时间点的访问量远远大于其他分片。

案例3:使用月份和用户名进行组合分片

有一个用户操作记录集合,业务需要查询用户最近一个月操作记录。集合有month,userName键

使用{month:1,userName:1}分片情景如下:

month保证热数据优于内存。

userName:保证数据的随机性,避免集中过热问题。

存在的问题:对于新文档由于很多月份还不存在,会导致新数据都是往最后一个分片上面插入数据,存在热读写问题,最后通过均衡器对数据块进行移动。

数据测试

sh.shardCollection("test.news",{"month":1,"username":1 });

----插入1月数据10万记录

for(var i=0;i<100000;i++){db.news.insert({"_id":i,"month":"1","username":Math.random(),"createdate":new Date()})}

----插入2月数据10万记录

for(var i=100000;i<200000;i++){ db.news.insert({"_id":i,"month":"2","username":Math.random(),"createdate":new Date()})}

新数据往一直往最末尾的分片(rs-a)上插,因为这个时候"month":2在最大的分片上。 { "month" : "1", "username" : 0.9258836896982892 } -->> { "month" : { "$maxKey" : 1 }, "username" : { "$maxKey" : 1 } } on : rs-a Timestamp(3, 1)

数据插入完之后均衡器将rs-c上的一个块分给了rs-a

----插入全部月份数据。

for(var a=1;a<13;a++)
{
for(var i=0;i<20000;i++){ db.news.insert({"month":a,"username":Math.random(),"createdate":new Date()})}
}

保证每个月的数据都均匀的分布到不同的分片上,并且随着时间的推移旧的数据可能就不会被使用也不会被移动。

注意:这个案例比较特殊,因为对于日志集合比较旧的数据基本上是不会被查询的,所以借助了month键作为了分片键保证了热数据优先存储于内存,对于整张表都是热数据比如登入用户集合就不适合这种分片方式,hashed会更适合。

案例4:使用队列

队列不仅在容灾中非常的有用,而且在常规的突发流量下也非常的有用。队列可以吸收短时间内爆发的大量请求。也可以把队列反过来用,即缓存MongoDB返回的结果。

比如:RabbitMQ

案例5:使用用户名和创建时间进行组合分片

用户名:保证数据的随机性,避免热点问题

创建时间:保证单个数据块过大问题

五、设计集合注意事项

1.集合的键数量应该是固定的,包括嵌套文档的数量都应该提前规划好。

2.尽量都是做原子更新,而不是某个键的值受其它键值更新的影响。比如num1,num2,total如果num键的值是经常会被更新的那么这种设计就不好,因为total也要对应跟着变,而mongodb本身计算能力就很弱。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

相关文章

  • mongodb 修改器($inc/$set/$unset/$push/$pop/upsert)

    mongodb 修改器($inc/$set/$unset/$push/$pop/upsert)

    对于文档的更新除替换外,针对某个或多个文档只需要部分更新可使用原子的更新修改器,能够高效的进行文档更新。更新修改器是中特殊的键
    2017-04-04
  • MongoDB CRUD操作中的插入实例教程

    MongoDB CRUD操作中的插入实例教程

    这篇文章主要给大家介绍了关于MongoDB CRUD操作中的插入的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用MongoDB具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2020-07-07
  • MongoDB性能优化及监控

    MongoDB性能优化及监控

    MongoDB 是一个基于分布式文件存储的数据库。接下拉通过本文给大家分享MongoDB性能优化及监控,本文介绍的非常详细,非常具有参考借鉴价值,感兴趣的朋友一起学习吧
    2016-02-02
  • Linux下MongoDB数据库实现自动备份详解

    Linux下MongoDB数据库实现自动备份详解

    这篇文章主要给大家介绍了在Linux系统下下MongoDB数据库实现自动备份的相关资料,文中通过示例代码介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面跟着小编一起来学习学习吧。
    2017-06-06
  • 详解MongoDB中创建集合与删除集合的操作方法

    详解MongoDB中创建集合与删除集合的操作方法

    因为MongoDB属于NoSQL,所以集合collection相当于关系型数据库中的表table,这里我们就来详解MongoDB中创建集合与删除集合的操作方法:
    2016-06-06
  • MySQL和MongoDB设计实例对比分析

    MySQL和MongoDB设计实例对比分析

    MySQL是关系型数据库中的明星,MongoDB是文档型数据库中的翘楚。
    2011-07-07
  • MongoDB固定集合(capped collection)的知识小结

    MongoDB固定集合(capped collection)的知识小结

    固定集合指的是事先创建,并且大小固定的集合。下面这篇文章主要给大家总结介绍了MongoDB固定集合(capped collection)的知识,文中介绍的非常详细,需要的朋友可以参考借鉴,下面来一起学习学习吧
    2018-10-10
  • mongoDB数据库索引快速入门指南

    mongoDB数据库索引快速入门指南

    索引是一种特殊的数据结构,存储设置在一个易于遍历形式的数据的一小部分。索引存储一个特定的字段或一组字段的值,在索引中指定的值的字段排列的,对mongoDB索引相关知识感兴趣的朋友跟随小编一起学习下吧
    2022-03-03
  • Navicat Premium连接mongodb详细教程

    Navicat Premium连接mongodb详细教程

    这篇文章主要介绍了Navicat Premium连接mongodb详细教程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03
  • 浅谈MongoDB的备份方式

    浅谈MongoDB的备份方式

    mongodb数据库同样离不开必要的维护,如备份、恢复、导入、导出。其实备份和恢复比导入和导出要方便些,而且一般不会出错,所以大部分时候使用备份和恢复操作就可以了。下面我们来简单谈谈MongoDB的备份方式
    2015-05-05

最新评论