MongoDB 分片集的基本概念

什么是分片集?

副本集(ReplicaSet) 用于解决读请求扩展、高可用等问题。但随着业务场景的进一步增长,可能会出现以下问题:

  • 存储容量超出单机磁盘容量;
  • 活跃数据集超出单机内存容量,很多读请求需要从磁盘读取;
  • 写入量超出单机 IOPS 上限

MongoDB 分片集群(Sharded Cluster)是对数据进行水平扩展的一种方式,使用分片集群来支持大数据集和高吞吐量的业务场景。

垂直扩容(Scale Up)& 水平扩容(Scale Out):

  • 垂直扩容:用更好的服务器,提高 CPU 处理核数、内存数、带宽等;
  • 水平扩容:将任务分配到多台计算机上

分片集基本架构

MongoDB 分片集的基本概念_第1张图片

  • Mongos
    • 分片集群的访问入口;
    • 对请求进行路由、分发、合并;
    • 部署多个 Mongos 来保证高可用
  • ConfigServer
    • 存储元信息和集群配置;
    • 部署为副本集来保证高可用
  • Shard
    • 存储用户数据,不同 Shard 保存不同用户数据;
    • 部署为副本集来保证高可用

MongoDB 分片集的基本概念_第2张图片

有了一个分片集群以后,Drivers 需要通过连接 Mongos 来达到和整个集群交互的目的,而 Mongos 则会根据客户端的请求来向后端不同的 Shard 进行请求的发起。
默认情况下,每个 database 的集合都是未分片的,存储在一个固定的 shard 上,称为 primary shard。当创建一个 database 时,系统会根据各个 shard 的存储数据量,选择一个数据量最小的 shard 作为新 database 的 primary shard。
eg:sh.enableSharding("records")用于启用 records 数据库的分片功能; sh.shardCollection("records.people", { zipcode: 1 } )对 records.people 集合基于 zipcode 的范围进行分片。

分片键(Shard Key)

  • 范围分片
    根据 Shard Key 的值进行数据分片。
    • 优点:很好的满足范围查询的需求;
    • 缺点:分片键单调写入,无法扩充写能力

MongoDB 分片集的基本概念_第3张图片

如上图所示,是一个基于 x 的范围分片,数据被分为了 4 部分,切割点分别是 x: -75,x: 25,x: 175 值,相近的数据是相邻的。在这种情况下,可以很好的满足范围查询的需求;但是如果是基于分片键的单调写入,由于所有的写入数据都会被最后一个 Chunk 来承载,所以就无法很好的扩充写能力。

  • 哈希分片
    根据 Shard Key 计算哈希值,基于哈希值进行数据分片。
    • 优点:分片单调写入,充分的扩展写能力;
    • 缺点:不能高效的进行范围查询

MongoDB 分片集的基本概念_第4张图片

如上图所示,数据经过哈希计算后被打散到不同的 Chunk 上,对于分片键单调写入的场景,可以充分的扩展写能力,但是却不能高效的进行范围查询。

选择合理的分片键

  • Cardinality(基数):越大越好。例如若以性别作为分片键,则数据最多被拆分成 2 份;若以月份作为分片键,则数据可以被拆分成 12 份;
  • Frequency(频率,文档中出现某个值的频率):越低越好。例如若以所在城市作为分片键统计全国人口分布情况,则一线城市所在的 Chunk 存储大量数据;
  • ·Monotonically Changing(单调变化):使用哈希分片记录日志集合,使用日志生成时间作为分片键。例如若使用范围分片,数据写入只会在最后一个 Shard 上完成

分片键的约束

Shard Key 必须是一个索引。非空集合须在 ShardCollection 前创建索引(用于将一个集合分片的命令);空集合 ShardCollection 自动创建索引。

  • 4.4 版本之前:
    • Shard Key 大小不能超过 512 Bytes;
    • 仅支持单字段的哈希分片键,例如 { x: “hashed” };
    • Document 中必须包含 Shard Key;
    • Shard Key 包含的 Field 不可以被修改
  • 4.4 版本之后:
    • Shard Key 大小不作限制;
    • 支持复合哈希分片键,例如 { x: 1, y: “hashed” };
    • Document 中可以不包含 Shard Key,插入时被当做 Null 处理;
    • 为 Shard Key 添加后缀 refineCollectionShardKey 命令,可以修改 Shard Key 包含的 Field
  • 4.2 版本之前,Shard Key 对应的值不可以修改;
  • 4.2 版本之后,如果 Shard Key 为非 _ID 字段,那么可以修改 Shard Key 对应的值

Mongos 请求转发策略

  • 特定目标的操作(Targeted Operations)
    根据分片键计算出目标 Shard(s),然后发起请求并返回结果。包含分片键的查询、更新、删除、插入操作。

MongoDB 分片集的基本概念_第5张图片

如上图所示,以 a 为 Shard Key 时,如果请求当中携带了 a 字段,那么 Mongos 就可以识别出来它的目标 Shard,如果是 Shard B,就可以直接跟 Shard B 进行交互,获取结果并返回给客户端。

  • 广播的操作(Broadcast Operations)
    将请求发送给所有的 Shard,合并查询结果并返回给客户端。不包含分片键的查询操作、_ID 字段的更新、删除操作。

MongoDB 分片集的基本概念_第6张图片

Chunk & Balancer

MongoDB 基于 Shard Key 将 Collection 拆分成多个数据子集,每个子集称为一个 Chunk,Chunk 是分割存储在分片集群上的数据集的最小单元。
ShardedCollection 的数据按照 Shard Key 划分为 MinKey ~ MaxKey 区间;每个 Chunk 有自己负责的一个区间(左闭右开);存储 ShardedCollection 的 Shard 上有该 Collection 的一个或多个 Chunk。

Chunk 分裂(Chunk Splits)

随着数据的写入,当 Chunk 增长到指定大小(默认为 64 MB)时,MongoDB 会对 Chunk 进行分裂。

  • 手动触发
    • sh.splitAt(namespace, query),指定 Chunk 分裂点;
    • sh.splitFind(namespace, query),从中间分裂目标 Chunk;
    • 调整 ChunkSize。调小 ChunkSize 可以让 Chunk 更均衡的分布,但是 Chunk 迁移次数会增加;调大 ChunkSize 会减少 Chunk 迁移次数,但会导致 Chunk 分布不均
  • 自动触发
    只有插入和更新操作才会触发自动 Chunk Split。当 Chunk Size 被调小时,不会立即发生 Chunk Split

注意:一个最小的 Chunk 可以只包含一个唯一的 Shard Key,这样的 Chunk 不可以再进行分裂,称为 JumboChunk。

Chunk 迁移(Chunk Migration)

保证数据负载均衡,MongoDB 支持 Chunk 在 Shard 之间进行迁移。

  • 自动触发
    当 Chunk 在 Shard 之间分布不均时,Balancer 进程会自动触发;
  • 手动触发
    sh.moveChunk(namespace, query, destination)

Chunk 迁移的影响:

  • 影响 Shard 使用磁盘的大小;
  • 增加网络带宽及系统负载,会对系统性能造成影响

Chunk 迁移的约束:

  • 每个 Shard 在同一时间内只能有一个 Chunk 进行迁移;
  • 不会迁移 Chunk 中文档数量是平均 Chunk 文档数 1.3 倍的 Chunk(4.4 版本中提供了选项支持)

Balancer 进程:

  • Balancer 是 MongoDB 的一个后台进程,用以保证集合的 Chunk 在各个 Shard 上是均衡的;
  • Balancer 运行在 ConfigServer 的 Primary 节点。 默认为开启状态;
  • 当分片集群中发生 Chunk 不均衡时,Balancer 将触发 Chunk 从 Chunk 数量最多的 Shard 向 Chunk 数量最少的 Shard 上进行迁移

MongoDB 分片集的基本概念_第7张图片

参考资料

  • 玩转 MongoDB 从入门到实战

你可能感兴趣的:(MongoDB,mongodb)