MongoDB 分片集群使用及原理介绍

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
云原生多模数据库 Lindorm,多引擎 多规格 0-4节点
简介: 作者 | 煮茶

一、分片集群的基本架构

为什么要使用分片集群?


副本集遇到的问题:


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


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


垂直扩容(Scale Up) VS ⽔平扩容(Scale Out):


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


什么是 MongoDB 分⽚集群:


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

分⽚集群的基本架构.png

分⽚集群的基本架构

  • Mongos
  • 分片集群的访问入口
  • 对请求进行路由、分发、合并
  • 部署多个 Mongos 来保证高可用


  • ConfigServer
  • 存储元信息和集群配置
  • 部署为副本集来保证高可用

  • Shard
  • 存储用户数据,不同 Shard 保存不同用户数据
  • 部署为副本集来保证高可用

Shard.png

如何链接分片集群

有了一个分片集群以后,Drivers 需要通过连接 Mongos 来达到和整个集群交互的目 的,而 Mongos 则会根据客户端的请求来向后端不同的 Shard 进行请求的发起。 比如对 集合一进行读写,Mongos 会和 Shard A 和 Shard B 进行请求交互,如果读写集合二, 那么 Mongos 指挥只会和 Shard A 进行数据交互。


如下图所示:在阿里云 Mongos 上申请的一个分片集群,列举了每个 Mongos 的链接 地址,并且拼接好了 ConnectionStringURI,如果使用单个 Mongos 进行链接,可能会 有单点的风险,所以推荐使用 ConnectionStringURI 来进行访问。

如何链接分片集群.png

ConnectionStringURI 各个组成部分:


mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:por tN]]][/[database][?options]]


  • Mongodb://:前缀,代表这是一个 Connection String URI 连接地址。
  • Username:password@:连接 MongoDB 实例的用户名和密码,使用英文冒号(:) 分隔。
  • HostX:portX:实例的连接地址和端口号。
  • /Database:鉴权数据库名,即数据库账号所属的数据库。
  • ?Options:指定额外的连接选项。


举个例子:

“Example : mongodb://user:password@mongos1:3717,mongos2:3717/ad min”


用户名为 User,密码为 Password,然后来连接 Mongos1 和 Mongos2,它们的端 口都是 3717,全数据库是 admin,这样的一个 ConnectionStringURI。


Database 的主分⽚(Primary Shard)


Primary Shard 的定义:


默认情况下,每个 Database 的集合都是未分片的,存储在一个固定的 Shard 上, 称为 Primary Shard。


Primary Shard 的选择:


当创建一个新的 Database 时,系统会根据各个 Shard 目前存储的数据量,选择一 个数据量最小的 Shard 作为新 Database 的 Primary Shard。

Shard.png

如何将集合进行分片

MongoDB 将数据进行分片支持集合级别,已经被分片的集合被切分成多份保 存在 Shard 上。


sh.enableSharding("")

  • // eg: "record" Example : sh.enableSharding("records") sh.shardCollection(".", {  : , ... } )
  • : 分片键字段的名字
  • : {1 | -1 |"hashed"} 。1 | -1 : 基于范围分片键,"hashed" : 哈希

分片键


举个例子:


“Example : sh.shardCollection("records.people", { zipcode: 1 } )”对 recor ds.people 集合进行分片,这是一个基于 records 范围分片。

records.png

二、Shard Key(分片键)


范围分⽚ VS 哈希分⽚


  • 范围分⽚:根据 ShardKey 的值进⾏数据分⽚。
    优点:很好的满足范围查询的需求;
    缺点:分片键单调写入,无法扩充写能力;
    范围分⽚⽀持多个字段的范围分⽚:{x : 1} {x : 1 , y : 1}

Shard Key.png

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


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

单调写入.png

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


哈希分⽚仅⽀持单个字段的哈希分⽚:


{ x : "hashed" } {x : 1 , y : "hashed"} // 4.4 new


4.4 以后的版本,可以将单个字段的哈希分片和一个到多个的范围分片键字段来进行组 合,比如下指定 x:1,y 是哈希的方式。


如何选择合理的分⽚键

  • Cardinality(基数):越⼤越好
  • 以性别作为分片键 :数据最多被拆分为 2 份
  • 以⽉份作为分片键 :数据最多被拆分为 12 份


如何选择合理的分⽚键.png


  • Frequency(频率,⽂档中出现某个值的频率):越低越好 记录全国人口的集合,以当前所在城市作为分片键:大多数数据集中在一线城市所在的 Chunk。

Frequency.png

  • Monotonically Changing(单调变化):使⽤哈希分⽚
    记录日志集合,使用⽇志⽣成时间作为分片键:
    如果使用范围分片,数据写入只会在最后一个 Shard 上完成。

Monotonically.png

分片键(ShardKey)的约束


ShardKey 必须是一个索引。非空集合须在 ShardCollection 前创建索引;空集合 ShardCollection 自动创建索引


4.4 版本之前:


  • ShardKey 大小不能超过 512 Bytes;
  • 仅支持单字段的哈希分片键;
  • Document 中必须包含 ShardKey;
  • ShardKey 包含的 Field 不可以修改。

4.4 版本之后:

  • ShardKey 大小无限制;
  • 支持复合哈希分片键;
  • Document 中可以不包含 ShardKey,插入时被当做 Null 处理;
  • 为 ShardKey 添加后缀 refineCollectionShardKey 命令,可以修改 ShardKey 包含 的 Field;

而在 4.2 版本之前,ShardKey 对应的值不可以修改;4.2 版本之后,如果 ShardKey 为非_ID 字段,那么可以修改 ShardKey 对应的值。


FefineCollectionShardKey


4.4 版本新增命令,通过分片键增加后缀字段的方式来修改分片键:


db.adminCommand( { 
refineCollectionShardKey: "<database>.<collection>", 
key: { <existing key specification>, 
<suffix1>: <1|"hashed">, ... } 
} )

这个例子中:


  • : 当前的分片键,即新的分片键必须以当前分片键为 前缀;
  • : 新增的分片键字段;
  • <1|"hashed"> : <1> -- 范围分片键 ;<"hashed"> -- 哈希分片键。


FefineCollectionShardKey 的使用说明:


  • 新的 ShardKey 对应的索引在FefineCollectionShardKey执⾏前须已经创建完成;
  • FefineCollectionShardKey 只会修改 Config 节点上的元数据,不会有任何数据迁 移,数据的打散随后续正常分裂&迁移⽽完成;
  • 4.4 版本中⽀持了 ShardKey 缺失的情况(当做 Null 处理),为了应对并不是所有 ⽂档都存在新的 ShardKey 的所有字段;
  • 4.4 版本中⽀持复合哈希分⽚键,⽽在之前的版本中只能⽀持单字段的哈希分⽚键。


特定⽬标的操作(Targeted Operations)vs⼴播的操作(Broadcast Operations)


Mongos 是如何基于请求当中的分片键信息来做请求转发,有两种转发行为,一种叫 做特定目标的操作,一种叫做广播操作。


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

Targeted Operations.png

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


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


如图所示:

如图所示:.png

三、Chunk & Balancer

什么是 Chunk?

  • MongoDB 基于 ShardKey 将 Collection 拆分成多个 数据子集,每个子集称为一 个 Chunk;
  • shardedCollection 的数据按照 ShardKey 划分为 MinKey ~ MaxKey 的间;
  • 每个 Chunk 有自己负责的一个区间(前闭后开);
  • 存储 ShardedCollection 的 Shard 上有该 Collection 的一个或多个 Chunk ;

什么是 Chunk?.png

如上图所示:分片的集合是基于 x 的范围分片,数据被分成了 4 个 Chunk, Chunk 1 : [minKey, -75) ; Chunk2 : [-75, 25) ; Chunk3 : [25, 175) ; Chunk4 : [175, maxKey)是个前闭后开的区间。ShardA 是持有 Chunk1 和 Chunk2,而 ShardB 和 ShardC 则分别持有 Chunk3 和 Chunk4。


Chunk 分裂(Chunk Splits)

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

  • Chunk 分裂的⽅式
    ⼿动触发:
  • sh.splitAt(namespace, query)
  • sh.splitFind(namespace, query)

⾃动触发:只有 插⼊和更新 操作才会触发⾃动 Chunk Split。当 Chunk Size 被 调⼩时,不会⽴即发⽣Chunk Split。

  • JumboChunk 一个最小的 Chunk 可以只包含一个唯一的 ShardKey,这样的 Chunk 不可以再进 行分裂,称为 JumboChunk。

如下图所示:

如下图所示:.png

Chunk 分裂管理


Chunk 分裂管理包括:⼿动进⾏Chunk 分裂与调整 ChunkSize。

  • ⼿动进⾏Chunk 分裂
    场景举例:业务需要向集合中插⼊⼤量的数据,⽽这些数据只分布在较少的 Chunk 中。

    直接插⼊⽆法利⽤多 Shard 并发写⼊,并且插⼊后触发 Chunk 分裂,进⽽触发 Chunk 迁移,产⽣很多⽆效 IO。

    sh.splitAt(namespace, query) : 指定 Chunk 分裂点,
    例如:x: [0, 100) , sh.splitAt(ns, {x: 70}) 分裂后 x: [0, 70) , [70, 100)

    sh.splitFind(namespace, query) : 从中间分裂⽬标 Chunk,
    例如:x: [0, 100) , sh.splitFind(ns, {x: 70})分裂后 x: [0, 50) , [50, 100)

  • 调整 ChunkSize
    例如: use config; db.settings.save( { _id:"chunksize", value:  } );

这里调整 ChunkSize 的方式,是对 config 库的 settings 集合,增加一条文档,这个 文档的 ID 是 ChunkSize。

说明:

  • 只有在 插⼊和更新 操作才会触发对应Chunk分裂 -- 调ChunkSize会⽴即触 发所有 Chunk 分裂为新的⼤⼩;
  • ChunkSize 取值范围 : 1 ~ 1024 MB;
  • 调⼩ ChunkSize 可以让 Chunk 更均衡的分布,但是 Chunk 迁移次数会增加;
  • 调⼤ ChunkSize 会减少 Chunk 迁移,但会导致 Chunk 分布不均。

Chunk 迁移(Chunk Migration)

  • Chunk 迁移的定义:
    为了保证数据负载均衡,MongoDB 支持 Chunk 在 Shard 间迁移,称为 Chunk Migration。

  • Chunk 迁移的⽅式:
  • 自动触发:当 Chunk 在 Shard 之间分布不均时,Balancer 进程会自动触发 Chunk 迁移;
  • 手动触发:sh.moveChunk(namespace, query, destination)
  • Example : sh.moveChunk("records.people", { zipcode: "53187" }, "sha rd0019")。
  • Chunk 迁移的影响:
  • 影响 Shard 使用磁盘的大小;
  • 增加 网络带宽 及 系统负载,这些会对系统性能造成影响。


  • Chunk 迁移的约束:
  • 每个 Shard 同一时间只能有一个 Chunk 在进行迁移;
  • 不会迁移 Chunk中文档数量是平均Chunk文档数1.3倍的Chunk // 4.4 提供 选项支持。


Chunk 迁移.png

Balancer

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

Shard 上迁移。.png

如图所示:Chunk 的数量小于 20,迁移阈值是 2,随着 Chunk 数量增大,迁移阈值 分别增长为 4 和 8。


AutoSplit & Balancer 管理命令


  • 开启 Chunk⾃动分裂: sh.enableAutoSplit()。
  • 关闭 Chunk⾃动分裂: sh.disableAutoSplit()。
  • 查看 Balancer 是否开启: sh.getBalancerState()。
  • 查看 Balancer 是否正在运⾏: sh.isBalancerRunning()。
  • 开启 Balancer: sh.startBalancer() / sh.setBalancerState(true)
  • 4.2 版本开始,会同时开启 AutoSplit。
  • 关闭 Balancer: sh.stopBalancer() / / sh.setBalancerState(false)
  • 4.2 版本开始,会同时关闭 AutoSplit。
  • 开启某个集合⾃动迁移: sh.enableBalancing(namespace)。
  • 关闭某个集合⾃动迁移: sh.disableBalancing(namespace)。
  • 修改 Balancer Window:

use config; 
db.settings.update( 
{ _id: "balancer" }, 
{ $set: { activeWindow : { start : "<start-time>", stop : "<stop-time>" } }
},
{ upsert: true } 
); 。

JumboChunk


JumboChunk 的定义:一个最小的 Chunk 可以只包含一个唯一的 ShardKey,这 样的 Chunk 不可以再进行分裂。


JumboChunk 的产生:ShardKey 选择不合理才会产生 JumboChunk。如果这些 JumboChunk 是高频访问的,就会引起单 Shard 性能瓶颈。另外 Chunk 无法迁移,如 果再进行迁移,会引起 Shard 间数据不均。


随着 MongoDB 版本迭代,这些问题也在逐步的被解决,比如 4.4 版本当中为我们提 供了 RefineCollectionShardKey 的命令,重新设置 ShardKey 同时 4.4 当中也给 Balancer 提供了一些设置,给 MoveChunk 提供了一些 Option,来支持 Chunk 迁移。


在 4.2 和 4.0 的较新的小版本当中,也提供了命令来清理集群中的 JumboChunk 标

识。

在 4.2 和 4.0.png

四、集群管理

命令回顾

  • Balancer
  • sh.setBalancerState(state)
  • true : sh.startBalancer()
  • false : sh.stopBalancer()
  • sh.getBalancerState()
  • sh.isBalancerRunning()  sh.disableBalancing(namespace)  sh.enableBalancing(namespace)

  • Chunk
  • sh.disableAutoSplit()
  • sh.enableAutoSplit()
  • sh.moveChunk( … )
  • sh.splitAt( … )
  • sh.splitFind( … )

  • Sharding
  • sh.shardCollection()
  • sh.enableSharding()

集群状态查看 - sh.status()

sh.status().png

sh.status().png

如图所示:


Sharding Version:分片集群的版本信息。


Shards:分片集群中目前有 2 个 Shard,每个 Shard 的名称、链接信息以及当前状

态。


Most Recently Active Mongoses:目前分片集群中有2个4.2.1版本的Mongos。


Autosplit&balancer


  • 当前开启 Auto-Split
  • Balancer 状态为开启
  • Balancer 目前没有正在运行
  • 过去一段时间 Balancer 执行的成功、失败信息。


Records 库

  • Primary Shard : xxxx746b04
  • 开启 Sharding(EnableSharding)
  • 相关版本信息。


Records.people 集合

  • Shard Key 为 { "Zipcode" : "Hashed" },无须 Unique 约束
  • Balancer 可以针对该 集合 进行 Balance
  • 集合有 4 个 Chunk,平均分布在 2 个 Shard 上
  • 各 Chunk 所负责的范围以及所属的 Shard。

LogicalSession

3.6 版本开始,MongoDB driver 将所有的操作与 LogicalSession 关联

3.4 版本及以前,如图所示:

3.4 版本及以前,如图所示:.png

3.4 版本及以后,如图所示:

3.4 版本及以后,如图所示:.png

  • LogicalSession ID

{ 
// 唯一标识。可以由客户端生成,也可以由服务端生成
分片集群使用及原理介绍 < 62
"id" : UUID("32415755-a156-4d1c-9b14-3c372a15abaf"), 
// 目前登录用户标识 
"uid" : BinData(0,"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSu 
FU=") 
}
  • ⾃动清理机制
  • 持久存储: Config.System.Sessions。TTL 索引:默认 30 分钟
  • 默认每 5 分钟一次同步,关闭已被清理的 Session,同时关闭 Session 上的 Cursor

  • 使⽤⽅式
  • use config; db.system.sessions.aggregate( [ { $listSessions: { allUse rs: true } } ] )
  • db.runCommand( { killSessions: [ { id :  }, ... ] } )
  • startSession / refreshSessions / endSessions ...



快速掌握MongoDB核心技术干货目录

电子书下载:《玩转MongoDB从入门到实战》 https://developer.aliyun.com/article/780915
走进 MongoDB  https://developer.aliyun.com/article/781079
MongoDB聚合框架 https://developer.aliyun.com/article/781095
复制集使用及原理介绍  https://developer.aliyun.com/article/781137
分片集群使用及原理介绍  https://developer.aliyun.com/article/781104
ChangeStreams 使用及原理 https://developer.aliyun.com/article/781107
事务功能使用及原理介绍 https://developer.aliyun.com/article/781111
MongoDB最佳实践一 https://developer.aliyun.com/article/781139
MongoDB最佳实践二  https://developer.aliyun.com/article/781141
相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。 &nbsp; 相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
相关文章
|
3月前
|
存储 缓存 NoSQL
MongoDB内部的存储原理
这篇文章详细介绍了MongoDB的内部存储原理,包括存储引擎WiredTiger的架构、btree与b+tree的比较、cache机制、page结构、写操作流程、checkpoint和WAL日志,以及分布式存储的架构。
125 1
MongoDB内部的存储原理
|
6月前
|
存储 监控 NoSQL
MongoDB索引解析:工作原理、类型选择及优化策略
MongoDB索引解析:工作原理、类型选择及优化策略
|
4月前
|
存储 监控 NoSQL
震撼!揭秘高可用 MongoDB 分片集群搭建的神秘魔法,开启数据存储的无敌模式!
【8月更文挑战第9天】在数字化时代,数据至关重要。MongoDB作为流行非关系型数据库,通过搭建高可用分片集群确保系统稳定性和性能。分片技术将大数据集分布于多服务器以实现水平扩展。搭建集群需准备服务器资源,配置环境,启动配置服务器、路由服务器及分片服务器,并设置分片策略。例如,对特定数据库和集合启用分片。此架构适用于高流量应用如大型电商平台,确保数据高效处理和高可用性。搭建过程需持续监控和优化,合理规划分片策略以维持系统稳定运行。
43 3
|
5月前
|
存储 NoSQL MongoDB
MongoDB 索引原理与索引优化
MongoDB 索引原理与索引优化
123 1
|
6月前
|
存储 JSON NoSQL
深入解析MongoDB的存储原理
深入解析MongoDB的存储原理
深入解析MongoDB的存储原理
|
7月前
|
监控 NoSQL 容灾
MongoDB复制集原理:高可用性与数据一致性的保障
【4月更文挑战第30天】MongoDB复制集提供高可用性和数据一致性,通过在多个服务器间复制数据。复制集包含主节点和从节点,写操作在主节点执行,然后异步复制到从节点。优势包括故障切换、数据冗余、负载均衡和容灾备份。当主节点故障,其他节点会选举新主节点,确保服务连续性。配置复制集涉及规划节点、配置复制集、初始化和监控维护。复制集是实现数据库可靠性的核心。
|
7月前
|
存储 NoSQL MongoDB
【MongoDB】MongoDB 索引结构底层原理分析
【4月更文挑战第1天】【MongoDB】MongoDB 索引结构底层原理分析
|
7月前
|
存储 运维 负载均衡
MongoDB详解(二)——MongoDB架构与原理
MongoDB详解(二)——MongoDB架构与原理
282 2
|
存储 缓存 NoSQL
MongoDB基础及原理介绍
MongoDB基础及原理介绍
|
存储 NoSQL MongoDB
图解MongoDB集群部署原理(3)
MongoDB的集群部署方案中有三类角色:实际数据存储结点、配置文件存储结点和路由接入结点。
148 0

相关产品

  • 云数据库 MongoDB 版