MongoDB-分片片键
1.分片
分片是什么?分片就是将数据存储在多个机器上。当数据集超过单台服务器的容量,服务器的内存,磁盘IO都会有问题,即超过单台服务器的性能瓶颈。此时有两种解决方案,垂直扩展和水平扩展(分片)。
垂直扩展就是增加CPU,增加容量,但高性能系统的CPU和容量不成比例,这样扩展成本大,并且有上限。
水平扩展分片,将数据分发到多个服务器,每个服务器是一个单独的数据库,各个服务器加起来组成一个逻辑数据库,把写压力和操作分流到不同服务器,提高容量和吞吐量。
MongoDB的文档是无模式的,不固定结构,因此只能进行水平分片。当块超过指定大小或者文档数超过最大文档数,MongoDB尝试分割这个块,若分割成功,把它标记为一个大块避免重复分割。拆分块的关键就是片键,下面介绍常见片键的种类。
2.片键种类
片键是文档的一个属性字段或者一个复合索引字段,一旦建立不能改变。片键是分片拆分数据的关键,片键的选择直接影响集群的性能。
MongoDB首先根据片键划分块chunks当块超过指定大小(默认64M),然后把块分到其他的分片上,片键类型主要有以下几种:
注意:片键也是查询时常用的一个索引。
(1) 递增片键
这类片键比较常见,比如使用时间戳,日期,自增的主键,ObjectId,_id等,此类片键的写入操作集中在一个分片服务器上,写入不具有分散性,这会导致单台服务器压力较大,但分割比较容易,这台服务器可能会成为性能瓶颈。
递增片键的创建,对foo数据库的bar集合使用timestamp时间戳分片
mongos> use foo
mongos> db.bar.ensureIndex({"timestamp":1})
mongos> sh.enableSharding("foo")
{ "ok" : 1 }
mongos> sh.shardCollection("foo.bar",{"timestamp":1})
{ "collectionsharded" : "foo.bar", "ok" : 1 }
(2) 哈希片键
使用一个哈希索引字段作为片键,优点是使数据在各节点分布比较均匀,数据写入可随机分发到每个分片服务器上,把写入的压力分散到了各个服务器上。但是读也是随机的,可能会命中更多的分片,一般具有随机性的片键(如密码,哈希,MD5)查询隔离性能比较差。
哈希片键的创建,对GridFS的chunks集合使用files_id哈希分片
mongos> db.bar.ensureIndex({"files_id":"hashed"})
mongos> sh.enableSharding("foo")
{ "ok" : 1 }
mongos> sh.shardCollection("foo.fs.chunks",{"files_id":"hashed"})
{ "collectionsharded" : " foo.fs.chunks ", "ok" : 1 }
(3) 组合片键
数据库中没有比较合适的片键供选择,或者是打算使用的片键基数太小(即变化少如星期只有7天可变化),可以选另一个字段使用组合片键,甚至可以添加冗余字段来组合。一般是粗粒度+细粒度进行组合。
组合片键的创建,对GridFS的chunks集合使用files_id和n组合分片
mongos> sh.enableSharding("foo")
{ "ok" : 1 }
mongos> sh.shardCollection("foo.fs.chunks",{"files_id":1, "n":1})
{ "collectionsharded" : " foo.fs.chunks ", "ok" : 1 }
(4) 标签分片
数据存储在指定的分片服务器上,可以为分片添加tag标签,然后指定相应的tag,比如让10.*.*.*(T)出现在shard0000上,11.*.*.*(Q)出现在shard0001或shard0002上,就可以使用tag让均衡器指定分发。
标签分片的创建
mongos > sh.addShardTag("shard0000", "T")
mongos > sh.addShardTag("shard0001", "Q")
mongos > sh.addShardTag("shard0002", "Q")
mongos> sh.addTagRange("foo.ips",{ "ip": "010.000.000.000 ", … , "ip": "011.000.000.000 "}}, "T")
mongos> sh.addTagRange("foo.ips",{ "ip": "011.000.000.000 ", … , "ip": "012.000.000.000 "}}, "Q")
3.片键选择策略
大致了解了片键的种类,那么怎么选择片键呢?无非从两个方面考虑,数据的查询和写入,最好的效果就是数据查询时能命中更少的分片,数据写入时能够随机的写入每个分片,关键在于如何权衡性能和负载。
如何选择片键主要从下面几个问题考虑:
(1)首先确定一个经常性查询的字段
(2)找到影响这些操作性能的关键点
(3)如果选的字段基数比较小,添加一个粒度细的字段
怎么选择,如何权衡,跟具体的业务以及数据类型都有关系,具体问题具体分析。