MongoDB分片集群由三个模块组成
- shard: 分片(或者分区)模块, 每个分片分别存储一部分数据, 从MongoDB 3.6开始, 分片必须是replica set(副本集)
- mongos: mongos是一个请求路由, 提供给客户端使用, 将请求分配到分片集群.
- config servers: 配置模块存储的是集群的配置信息和元数据, MongoDB 3.4之后配置模块也必须是replica set(CSRS).
一个副本集只能有一个主节点, 可以有多个从节点. 主节点可以读写, 从节点只能读. 主节点将数据修改操作保存至oplog中. 一个副本集需要奇数个节点, 心跳信息每两秒传递一次, 通过选举实现自动故障转移. 主节点宕机后会进行自动选举.
生产环境配置
在生产环境为了保证数据冗余以及系统的高可用, 建议使用以下的分片集群配置
- Config Servers使用3节点副本集
- Shard使用3节点副本集
- Mongos部署1个或多个
副本集分布式部署
如果可能的话, 建议将每个副本集中的一个节点部署至适合灾备恢复的机房
分片的个数
分片机制需要至少两个分片, 如果不是很快就要开始分片, 不要使用单个分片的集群.
Mongos的个数和部署
部署多个mongos支持高可用性和扩展性, 大多情况下会在每个应用服务器上部署一个mongos, 这样可以减小客户端应用和mongos之间的网络延迟. 对于大型的项目, 可以将mongos部署在专用的服务器上, 避免mongos的数量随应用而增长, 并且使得mongos可以使用更大的内存. mongos和mongod的内存是不共享的, 如果部署在同一个服务器上要留意内存是否充足. 在部署数量上, mongos没有限制, 但是mongos会频繁与配置服务器通信, 在增加mongos数量后要密切监视配置服务器的负载, 如果导致性能下降, 就要减小mongos的数量.
开发环境配置
对于测试和开发, 你可以按最小数量来部署.
- Config Server使用1节点副本集
- Shard使用1节点副本集
- Mongos部署1个
分片
在分片集群中, 每个分片会包含全部数据的一个子集. 用户,客户端和应用应当直接连接到分片来进行本地管理和维护操作.
在单个分片上进行查询, 只会返回这个子集中的数据. 集群级别的读写操作应当连接到mongos进行.
主分片
在分片集群中, 每个db都有一个主分片, 用来存储这个db中所有未分片的collection. 每个db都有各自的主分片. 主分片与副本集中的主副本无关.
mongos在创建新db时, 会选择集群中数据量最小的那个分片, 在其上创建主分片. 使用listDatabase命令返回的totalSize也是判断的一个因素.
要修改db的主分片, 使用movePrimary命令. 迁移主分片的过程会明显耗时, 迁移的过程中不应该去访问对应的数据.
分片状态
在mongo shell用 sh.status() 方法查看集群状态. 报告包含那些分片是db主分片以及在分片上的chunk分布情况.
分片集群安全
使用Internal/Membership验证来保证集群内的安全, 防止未授权的模块连入或访问集群, 在启动每个mongod的时候, 要设置好对应的安全配置, 对应的是
集群内模块间的安全, 使用Internal Authentication, 例如keyfile
客户端和集群间的安全, 使用User Access Controls, 客户端必须使用用户账户进行连接
分片本地用户
各个分片都支持基于角色的访问控制Role-Based Access Control (RBAC), 在mongod启动时使用 --auth 参数启用RBAC. 另外, 启用 Internal/Membership Authentication 时也会通过RBAC启用用户访问控制.
每个分片都有自己的本地用户, 这些用户不能用在其他分片上, 也不能用于通过mongos连接集群
分片主键
分片主键决定了collection数据在集群中各个分片如何分布, 分片主键可以是一个索引字段, 也可以是一个索引组合字段, 只要它存在于collection中的每一个记录. MongoDB使用主键值的区间对数据进行分区, 每个区间定义了数据块, 对应一个不会与其他数据块交叠的主键值范围. MongoDB会尽量保持数据块在集群的分片中均匀分布, 分片主键的选择和分布的效率有直接联系.
数据块
MongoDB在数据块尺寸超过限制后, 会将数据块进行拆分. 在insert和update操作后都有可能发生拆分. 数据块能对应的最小的区间就是一个单个的分片主键值, 如果数据块只对应了一个主键值, 那就不能再拆分了.
数据块初始化
填充Collection
分片操作会用完整的主键值区间创建初始数据块, 数据块的数量取决于配置的数据块尺寸. 在初始数据块创建后, balancer会在分片之间迁移这些数据块.
空Collection
如果你定义了zone, 并且zone区间定义在了一个空的或不存在的collection上, 分片操作会创建空数据块. 如果未在空collection上设置zone,
对于hashed sharding: 分片操作会创建空数据块, 默认情况下每个分片会创建两个数据块, 可以通过numInitialChunks选项来调整数量.
对于ranged sharding: 分片操作会创建一个空数据块, 然后进行迁移.
数据块尺寸
MongoDB中的默认数据块尺寸是64MB, 大小可以在配置中修改.
- 小数据块可以让数据分布更均匀, 但是迁移会更频繁, 增加mongos查询开销.
- 大数据块可以减小迁移频率, 从网络角度看更高效, 但是数据存储分布会更不均匀.
- 数据块尺寸会影响每个数据块的最大记录数, 影响分片的最大collection尺寸.
- 大部分场景下, 需要允许轻微的数据不均匀, 来避免频繁的数据块迁移.
修改数据块尺寸的影响说明:
自动拆分只会在insert和update时发生, 如果你减小了数据块尺寸, 会需要等一段时间才能看到所有数据块拆分为新的尺寸.
拆分是不能回退的, 如果你增加数据块尺寸, 现有的数据块要在insert和update过程中增长到新的尺寸
数据块拆分
拆分是为了避免数据块增长得过大, 当一个数据块增长到超过预设的尺寸或者记录数超过每个数据块允许迁移的最大记录数时, MongoDB会基于分片主键值将数据块进行拆分. 必要的时候一个数据块会被拆分成多个数据块. 拆分是元数据修改, MongoDB并不会迁移任何数据或影响分片.
拆分会导致分片之间的数据块存储分布的不均衡, 这时候balancer会将数据块在分片之间进行调整. Balancer是一个后台进程, 用于管理数据块迁移. 如果集群中分片的最大数据块数量和最小数据块数量超过了阈值, balancer就会进行迁移以保证数据的均匀分布.
在某些情况下, 例如对应的分片主键已经缩减为单值, 数据块增长超过了限制但是又不能进行拆分, 会使得数据块增长得越来越大, 这就会成为性能瓶颈, 特别是当这个主键被频繁使用的时候.