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":"","username":Math.random(),"createdate":new Date()})}

----插入2月数据10万记录
for(var i=100000;i<200000;i++){ db.news.insert({"_id":i,"month":"","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本身计算能力就很弱。
|
备注: 作者:pursuer.chen 博客:http://www.cnblogs.com/chenmh 本站点所有随笔都是原创,欢迎大家转载;但转载时必须注明文章来源,且在文章开头明显处给明链接,否则保留追究责任的权利。 《欢迎交流讨论》 |
MongoDB 分片键的选择与案例的更多相关文章
- MongoDB 分片键分类与数据分发
In sharded clusters, if you do not use the _id field as the shard key, then your application must en ...
- Mongodb 分片 手动维护chunk
去年的笔记 For instance, if a chunk represents a single shard key value, then MongoDB cannot split the ch ...
- 在一台机器上模拟mongodb分片
首先选择一个目录在其中建立以下2个文件夹:data和log 在data下建立9个文件夹: 其中前3个为配置服务器所在文件夹,按照官网要求,一个集群需要3个config server rs-a-n和rs ...
- mongodb分片片键的选择(持续更新中)
首先要了解项目的情况,检查使用情况 对集合进行分片时,要选择一个或者两个字段拆分数据,这个键叫做片键 一旦拥有对个分片,在修改片键几乎是不肯能的事情,因此选择合适的片键是非常重要的. 对集合分片之前要 ...
- MongoDB 分片管理(不定时更新)
背景: 通过上一篇的 MongoDB 分片的原理.搭建.应用 大致了解了MongoDB分片的安装和一些基本的使用情况,现在来说明下如何管理和优化MongoDB分片的使用. 知识点: 1) 分片的配置和 ...
- MongoDB 分片的原理、搭建、应用
一.概念: 分片(sharding)是指将数据库拆分,将其分散在不同的机器上的过程.将数据分散到不同的机器上,不需要功能强大的服务器就可以存储更多的数据和处理更大的负载.基本思想就是将集合切成小块,这 ...
- 搭建mongodb分片
搭建mongodb分片 http://gong1208.iteye.com/blog/1622078 Sharding分片概念 这是一种将海量的数据水平扩展的数据库集群系统,数据分表存储在shardi ...
- mongodb分片
在系统早期,数据量还小的时候不会引起太大的问题,但是随着数据量持续增多,后续迟早会出现一台机器硬件瓶颈问题的.而mongodb主打的就是海量数据架构,他不能解决海量数据怎么行!不行!“分片”就用这个来 ...
- Elasticsearch和MongoDB分片及高可用对比
本文旨在对比Elasticsearch和MongoDB高可用和分片的实现机制. Elasticsearch ES天生就是分布式的,那她又是如何做到天生分布式的? 通过ES官方指南我们可以知道: 一个运 ...
随机推荐
- python学习记录20190121
print 语句默认会给每一行添加一个换行符.只要在print 语句的最后添加一个逗号(,),就可以改变它这种行为 带逗号的print语句输出的元素之间会自动添加一个空格 print 没有任何参数的p ...
- MonkeyFest2018Guangzhou
MonkeyFest 是一个一年一度由全球Microsoft Xamarin开发者发起的全球性社区活动,主旨推广在云计算.人工智能.大数据.移动开发等技术. 跨平台技术移动开发(卢建晖) .NET C ...
- 检查linux版本命令
lsb_release -a cat /etc/issue cat /proc/version uname -a cat /etc/redhat-release
- IE8 disable 兼容行问题
在chrome 下 如果样式设置为disabled 则不能点击, 但是在IE9 或者IE8 则还是可以点击
- (译)(function (window, document, undefined) {})(window, document); 真正的意思
由于非常感兴趣, 我查询了很多关于IIFE (immediately-invoked function expression)的东西, 如下: (function (window, document, ...
- mac抓包工具anyproxy
本文以 mac为代理,ios手机为客户端举例. 文档地址:http://anyproxy.io/ 1.环境配置: 安装 node :参考 https://www.jianshu.com/p/3 ...
- 10_27_unittest
接口测试的本质 就是测试类里面的函数. 单元测试的本质 测试函数 代码级别 单元测试框架 unittest 接口 pytest web 功能测试: 1.写用例 ----> TestCase ...
- notes for lxf(五)
类和实例的绑定方法和属性 实例绑定 obj.func = func obj.func(obj, &argv) obj.func = MethodType(func, obj) 第一个参数是方 ...
- SpringBoot与日志框架1(基本使用)
一.日志框架 1.无论在什么系统,日志框架都是一个重要角色,所以理解和用好日志框架是相当重要的:像JDBC一样,日志框架分为接口层的门面和具体的实现组成. 2.市面上的产品: 2.1门面:SLF4J( ...
- OO Unit 1 表达式求导
OO Unit 1 表达式求导 面向对象学习小结 前言 本博主要内容目录: 基于度量来分析⾃己的程序结构 缺点反思 重构想法 关于BUG 自己程序出现过的BUG 分析⾃己发现别人程序bug所采⽤的策略 ...