本文基于MongoDB 3.2系列, 最新版本的MongoDB的balancer流程,应该会和3.2有不一致的地方
前言
MongoDB Balancer 是一个运行在 mongos 中的后台线程,该线程的主要作用就是监控 shard 上的 chunk 数量。如果发现某个 shard 上的 chunk 达到一定的数量,则 balancer 会自动的将部分 chunk 块迁移到其它 shard中,保证所有的 shard 中拥有的 chunk 块数量基本一致。
Balancer 的整个运行过程对用户和应用是完全透明的,但是运行过程中,对整个集群的性能有一定的影响。
当一个 balancer 进程被激活的时候,负责本次过程的 mongos 节点会通过修改 congfig server 中的一个文档来获取锁,每次都只有一个 mongos 节点负责一次 balance。
Primary Shard
使用 MongoDB Sharding 后,数据会以 chunk 为单位(默认64MB)根据 shardKey 分散到后端1或多个 shard 上。
MongoDB 中每个库会有一个 primary shard,在库创建时分配。
- 库下启用分片(即调用 shardCollection 命令)的集合,刚开始会生成一个[minKey,maxKey]的 chunk,该 chunk 初始会存储在 primary shard 上,然后随着数据的写入,不断地发生 chunk 分裂及迁移,整个过程如下图所示。
- 一个库若是没有启用分片地集合,其所有地数据都会存储到 primary shard。
何时触发 chunk 分裂?
mongos 上可以通过 sh.disableAutoSplit() 配置项,用于控制是否自动触发 chunk 分裂,默认是开启的。(强烈建议不要关闭autoSplit)
MongoDB 的自动 chunk 分裂只会发生在 mongos 写入数据时,当写入的数据超过一定量时,就会触发 chunk 的分裂。chunk 的默认大小为 64MB,分裂阈值如下:
集合chunk数量 | 分裂阈值 |
---|---|
1 | 1024B |
[1, 3) | 0.5MB |
[3, 10) | 16MB |
[10, 20) | 32MB |
[20, max) | 64MB |
写入数据时,当 chunk 上写入的数据量超过分裂阈值时,就会触发 chunk 分裂;chunk 分裂后,若是出现各个 shard 上 chunk 分布不均衡时,就会触发 chunk 迁移。
何时触发 chunk 迁移?
默认情况下,MongoDB会开启balancer,在各个shard间迁移chunk来让各个shard间负载均衡。用户也可以手动的调用 sh.moveChunk(fullName,find,to) 命令在shard之间迁移数据。
Balancer 在工作时,会根据 shard tag、集合的 chunk 数量、shard 间 chunk 数量差值来决定是否需要迁移。
(1)根据 shard tag 迁移
MongoBD sharding支持shard tag
特性,用户可以给shard打上标签,然后给集合的某个range打上标签,MongoDB会通过balancer的数据迁移来保证「拥有tag的range会分配到具有相同tag的shard上」。
(2)根据 shard 间的 chunk 数量差值迁移
集合 chunk 数量 | 迁移阈值 |
---|---|
[1, 20) | 2 |
[20, 80) | 4 |
[80, max) | 8 |
针对所有启用分片的集合,如果「拥有最多数量chunk的shard」与「拥有最少数量chunk的shard」的差值超过某个阈值,就会触发chunk迁移; 有了这个机制,当用户调用addShard添加新的shard,或者各个shard上数据写入不均衡时,balancer就会自动来均衡数据。
(3)remove Shard触发迁移
还有一种情况会触发迁移,当用户调用 removeShard 命令从集群里移除shard时,Balancer也会自动将这个shard负责的chunk迁移到其他节点。
chunkSize 对分裂及迁移的影响
MongoDB默认的chunkSize为64MB,如无特殊需求,建议保持默认值;chunkSize会直接影响到chunk分裂、迁移的行为。
- chunkSize越小,chunk分裂及迁移越多,数据分布越均衡;反之,chunkSize越大,chunk分裂及迁移会更少,但可能导致数据分布不均。
- chunkSize太小,容易出现jumbo chunk(即shardKey 的某个取值出现频率很高,这些文档只能放到一个chunk里,无法再分裂)而无法迁移;chunkSize越大,则可能出现chunk内文档数太多(chunk内文档数不能超过 250000)而无法迁移。
- chunk自动分裂只会在数据写入时触发,所以如果将chunkSize改小,系统需要一定的时间来将chunk分裂到指定的大小。
- chunk只会分裂,不会合并,所以即使将chunkSize改大,现有的chunk数量不会减少,但chunk大小会随着写入不断增长,直到达到目标大小。
如何减小分裂及迁移影响?
TIP:
(1)当集群中新加入一个 shard 的时候,会导致 chunk 一个不平衡。因为新的 shard 中没有任何的 chunk,所有 mongodb 开始将数据迁移到新 shard 的时候,会花费一定的时间。
(2)当把一个 shard 从一个集群中移除后,会发生类似的过程,balancer 需要花费一定的时间,把这个 shard 中的数据重新分布到其它的 shard,所以在移除 shard 的过程中,一定不要关闭被移除的服务器
1、预分片提前分裂
在使用 sh.shardCollection() 命令对集合进行分片时,如果使用hash分片,可以对集合进行「预分片」,直接创建出指定数量的chunk,并打散分布到后端的各个shard。
通过指定 sh.shardCollection() 命令中 numInitialChunks 参数 指定初始化的分片数量,该值不能超过8192。
如果使用range分片,因为shardKey的取值不确定,预分片意义不大,很容易出现部分chunk为空的情况。
2、合理配置 balancer
MonogDB的balancer能支持非常灵活的配置策略来适应各种需求。
- Balancer能动态的开启、关闭
- Blancer能针对指定的集合来开启、关闭
- Balancer支持配置时间窗口,只在制定的时间段内进行迁移。如何配置balancer时间窗口,请参考:传送门
参考文章:
https://blog.csdn.net/joy0921/article/details/80131276
https://bbs.huaweicloud.com/forum/thread-7973-1-1.html