共计 3379 个字符,预计需要花费 9 分钟才能阅读完成。
在 MongoDB(版本 3.2.9)中,数据的分发是指将 collection 的数据拆分成块(chunk),分布到不同的分片(shard)上,数据分发主要有 2 种方式:基于数据块(chunk)数量的均衡分发和基于片键范围(range)的定向分发。MongoDB 内置均衡器(balancer),用于拆分块和移动块,自动实现数据块在不同 shard 上的均匀分布。balancer 只保证每个 shard 上的 chunk 数量大致相同,不保证每个 shard 上的 doc 数量大致相同。
一,数据按照 chunk 数量进行均衡分发
均衡分发是 MongoDB 自动实现的,使数据库架构对 Application 透明,简化系统的管理,使得向分片集群中增减分片变得容易。均衡分发是由 MongoDB 内置均衡器(balancer)来实现的,Balancer 按照 collection 的索引字段来进行数据分发,该字段叫做片键(sharded key)。片键一般有三种类型:升序片键,随机片键和基于分组的片键。
块(chunk)是由多个 doc 组成的一个分组,在某个索引字段(片键)上是连续的,每个 chunk 的片键是有一定范围的。块的默认大小是 64MB。有些 chunk 会非常大,包含的 doc 数量非常多,但是,在 MongoDB 看来,仍然是一个 chunk,和没有任何 doc 的空 chunk 没有区别。均衡分发保证每个 shard 的 chunk 数量是大致相同的。因此,片键的选择直接影响分片的好坏。
例如:一个 MongoDB 分片集群有 3 个 shard,分别是 shard1,shar2,shard3。片键的最小值是:$MinKey,最大值是:$MaxKey。包含端值 $MinKey 的 chunk 是最小块,包含端值 $MaxKey 的 chunk 是最大块。
1,升序片键
升序片键类似 date 字段或者_id 字段,是一种随着时间稳定增长的字段。假如分片的字段是_id 字段,集合 foo 中存在 10 个 doc,每个 shard 中存在一个数据块,分别是:chunk1:$MinKey-3,chunk2:4-8,chunk3:9-$MaxKey。
使用升序片键的劣势是:每次插入一个新的 doc,都会插入到最大块中,这会导致所有的写请求都会被路由到同一个分片,导致最大块不断增长,不断被拆分,然后不断被移动到其他分片中,导致数据的写入不均衡,块移动会额外增加 Disk 的写数量。使用升序片键的优势是:按照片键进行范围读时,性能高。
2,随机片键
随机片键是指片键的值不是固定增长,而是一些没有规律的键值。由于写入数据是随机分发的,各分片增长的速度大致相同,减少了 chunk 迁移的次数。使用随机分片的弊端是:写入的位置是随机的,如果使用 Hash Index 来产生随机值,那么范围查询的速度会很慢。
3,基于分组的片键
基于分组的片键是两字段的复合片键,第一个字段用于分组,该字段的势最好是比较低的,势是在同一字段中不同值(distinct value)的数量或所占的比例;第二个字段用于自增,该字段最好是自增字段。这种片键策略是最好的,能够实现多热点数据的读写。
单个 mongod 在处理升序写请求时是最有效的,数据只需要写入到集合的末尾。基于分组的片键,将数量不多的分组分布在分片集群中,每个 shard 只有少量的 chunk,这样能够将数据的写操作分布在分片集群中的每个 shard 上,在单个 shard 上,以升序方式读写数据。一个 shard 上的分组太多,写请求就相当于随机写了,反而不好。
二,按照片键范围进行定向分发
如果希望特定范围的 chunk 被分发到特定的分片中,可以为分片添加 tag,然后为 tag 指定相应的片键范围,这样,如果一个 doc 属于 tag 的片键范围,就会被定向到特定的 shard 中。
1,为 shard 指定 tag
sh.addShardTag("shar1","shard_tag1");
sh.addShardTag("shar2","shard_tag2");
sh.addShardTag("shar3","shard_tag2");
2,为 tag 指定片键范围
sh.addTagRange("db_name.collection_name",
{field:"min_value"},
{field:"max_value"},
"shard_tag"
)
每个 shard 的 tag 可以使用任意数量的 tag,MongoDB 的均衡器在移动块时,会将特定片键范围的 chunk 移动到特定的 shard 上。
三,手动进行数据的分发
MongoDB 内置均衡器(balancer),自动实现数据块的拆分和移动,有时,可以关闭 balancer,使用 moveChunk 命令手动移动数据块。
1,关闭 balancer
连接到一个 mongos,更新 config.setting 命名空间
use config
db.setting.update({"_id":"balancer"},{"enabled":false},true)
--or
sh.setBalancerState(false);
2,拆分块
拆分块是指新增一个边界点,将一个 chunk 在边界点处拆分成两个 chunk。在 MongoDB 中,将片键从小到大排序,边界值属于右边的 chunk。
sh.splitAt("db_name.collection_name",{sharded_filed:"new_boundary_value"})
3,移动块
MongoDB 将包含指定文档的 chunk 移动到指定的 shard 上,必须使用片键来查找所要一定的 chunk。
sh.moveChunk("db_name.collection_name",{sharded_filed:"value_in_chunk"},"new_shard_name")
4,启用 balancer
sh.setBalancerState(true)
5,刷新 mongos 的缓存
在 Application layer 和数据存储之间,存在一个 Query Router,即 mongos,mongos 会在第一次启动或分片的元数据被更新之后,从 config server 同步配置数据,并缓存在 mongos 中。有时,mongos 无法从 config server 上及时同步最新的配置信息,导致无法路由到相应的 chunk,不能返回正确的数据,可以使用 flushRouterConfig 命令手动刷新 mongos 的缓存
db.adminCommand({"flushRouterConfig":1})
更多 MongoDB 相关教程见以下内容:
CentOS 编译安装 MongoDB 与 mongoDB 的 php 扩展 http://www.linuxidc.com/Linux/2012-02/53833.htm
CentOS 6 使用 yum 安装 MongoDB 及服务器端配置 http://www.linuxidc.com/Linux/2012-08/68196.htm
Ubuntu 13.04 下安装 MongoDB2.4.3 http://www.linuxidc.com/Linux/2013-05/84227.htm
MongoDB 入门必读(概念与实战并重) http://www.linuxidc.com/Linux/2013-07/87105.htm
Ubunu 14.04 下 MongoDB 的安装指南 http://www.linuxidc.com/Linux/2014-08/105364.htm
《MongoDB 权威指南》(MongoDB: The Definitive Guide)英文文字版[PDF] http://www.linuxidc.com/Linux/2012-07/66735.htm
Nagios 监控 MongoDB 分片集群服务实战 http://www.linuxidc.com/Linux/2014-10/107826.htm
基于 CentOS 6.5 操作系统搭建 MongoDB 服务 http://www.linuxidc.com/Linux/2014-11/108900.htm
MongoDB 的详细介绍:请点这里
MongoDB 的下载地址:请点这里
参考文档:
Sharding
本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-09/135650.htm