文档数据库 MongoDB 版支持分片集群实例架构,能够提供可横向扩展的 MongoDB 服务。分片集群通过将大型集合自动分割到不同节点,来满足大规模高性能场景下的容量和性能需求。本文介绍使用 MongoDB 分片集群的相关建议供您参考。
在如下场景中建议使用 MongoDB 分片集群:
Uniqueness can't be maintained unless shard key is a prefix
相关的报错。upsert:true
或者multi:false
,那么 update 请求会返回 An upsert on a sharded collection must contain the shard key and have the simple collation
错误。为避免影响线上业务,建议在业务低峰期执行修改。分片(Shard)和分片代理(Mongos)是 MongoDB 分片集群实例中的重要组成部分。您可以根据业务场景需要,参考以下方法确定 Shard 和 Monogs 数量:
说明
分片集群中数据的分片以集合为基础单位,集合中的数据通过分片键被分成多个部分。分片键是在集合中选择的一个或多个合适的字段,数据拆分时以该分片键的值为依据均衡地分布到所有分片中。如果您没有选择到合适的的分片键,可能会降低集群的使用性能,出现执行分片语句时执行过程卡住的问题。
说明
reshardCollection
命令来修改分片键,实现数据的重新分配。修改分片键的具体操作步骤,请参见 Reshard a Collection。支持的分片策略
MongoDB 分片集群支持如下两种分片策略。
分片策略 | 策略说明 | 注意事项 |
---|---|---|
范围分片 | 支持基于 shard key 的范围查询。 | 当使用范围分片或哈希分片时,如下场景会影响分片效果或性能:
|
哈希分片 | 能够将写入均衡分布到各个 shard。 |
理想的 shard key 应具备的特点
说明
如果所选分片键不具备以上所有特点,将会影响集群的读写扩展性。例如,某字段经常被更新或经常被查询,若将其作为分片键可能会导致数据分片不均衡从而出现读写热分片,严重限制分片的优势。因此,您需要根据业务的数据分片情况、常用查询及写入的数据等场景,调整您的分片键。
设置 shard key 时应考虑的因素
您可以参考如下信息判断设置的分片键是否能够满足业务需求。
说明
更多详情,请参见 Choose a Shard Key。
影响因素 | 说明 |
---|---|
分片键基数 |
|
分片查询模式 |
|
分片键限制 | 某些数据库可能对分片键有特定(最大长度或数据类型)的限制。在选择分片键时需要考虑这些限制。 |
Chunk size
MongoDB 5.0 及之前版本的 chunk size 默认值为 64 MB,您可以根据业务数据量和分片使用场景修改 chunk size 值,支持的取值范围为 1MB ~ 1024 MB。修改 chunk size 值时需要注意如下几点:
更多详情,请参见 Modify Chunk Size in a Sharded Cluster。
Jumbo chunk
当数据持续写入 chunk 并超过 chunk size 值时,且由于某些原因无法拆分(例如一个 chunk 即为单个分片键值)时,就会被标记为 jumbo chunk。Jumbo chunk 无法被 balancer 迁移,进而可能导致负载不均衡,影响数据库性能。
Chunk 被标记为 jumbo chunk 后,您可以参考如下方法进行处理:
sh.splitAt()
或 sh.splitFind()
命令将其拆分。拆分成功后,MongoDB 会自动清除该 chunk 的 jumbo 标记。关于命令的更多详情,请参见 sh.splitAt() 和 sh.splitFind() 。clearJumboFlag
命令手动清除该 chunk 的 jumbo 标记。关于命令的更多详情,请参见 clearJumboFlag。说明
MongoDB 均衡器(Balancer)会周期性的检查分片间的 chunk 数量是否存在不均衡,当各个 Shard 分片之间的 chunk 数量差异达到指定的迁移阈值时,均衡器会在分片间自动迁移数据,实现数据在分片上的均匀分布。
MongoDB 均衡器默认启用,您也可以通过 sh.stopBalancer()
命令手动关闭均衡器。更多详情,请参见 Disable the Balance。
均衡器支持在线数据迁移,但数据迁移过程会对集群负载有较大影响,建议将均衡器的迁移时间设置在业务低峰期。您可以通过如下命令中的 activeWindow
参数来指定均衡器的活动时间窗口。
db.settings.updateOne( { _id: "balancer" }, { $set: { activeWindow : { start : "<start-time>", stop : "<stop-time>" } } }, { upsert: true } )
说明
<start-time>
和 <stop-time>
换成指定的时间,例如 { start : "01:30", stop : "04:30" }
。更多详情,请参见 Modify the balancer's window。某汽车自动驾驶应用需要通过 MongoDB 分片集群存储海量的车辆自动驾驶日志。假设车辆数量在百万级别,车辆每 10 秒就会向 MongoDB 上传一次日志数据,日志包含车辆 ID(VehicleId)和时间戳(Timestamp)信息,业务需要查询某辆车在某个时间内的日志信息。
根据上述使用场景和查询要求,可选的 shard key 设置方案见下表。
可选方案 | 说明 |
---|---|
方案一(推荐): |
|
方案二: |
|
方案三: |
|
方案四: 若车辆 ID 无明显规则,也可进行范围分片。 |
|
本文根据上述使用场景和查询请求要求,以推荐的方案一(即组合车辆 ID 和时间戳作为 shard key,进行范围分片)为例,详细介绍 MongoDB 分片集群 shard key 的设置步骤。
说明
下述示例中以数据库 IoV
,集合 AutonomousCar
,字段 VehicleId
和 Timestamp
为例介绍相关操作步骤。
通过 Mongo Shell 工具登录目标分片集群实例。具体操作步骤,请参见通过 Mongo Shell 工具连接实例。
执行 use <数据库名称>
命令进入目标数据库。
示例如下。
use IoV
执行如下命令判断目标集合是否已分片。
db.<collection>.getShardDistribution()
若返回结果为 Collection <collection> is not sharded
表示当前集合未分片。更多详情,请参见 db.collection.getShardDistribution()。
命令示例如下:
db.AutonomousCar.getShardDistribution()
对集合所属的数据库启用分片功能。
您可以选择如下任意一种方法启用目标数据库的分片功能。
命令示例如下。sh.enableSharding("<database>")
sh.enableSharding("IoV")
use admin
命令进入 admin 数据库,然后执行如下命令:命令示例如下。db.runCommand({enablesharding:"<database>"})
db.runCommand({enablesharding:"IoV"})
确认 MongoDB 均衡器(Balancer)是否已开启,命令如下。
sh.getBalancerState()
若返回结果为 true
表示均衡器已启用,当各个 Shard 分片之间的 chunk 数量差异达到指定的迁移阈值时,均衡器会在分片间自动迁移数据,实现数据在分片上的均匀分布。更多详情,请参见 Check the Balancer State。
若返回结果为 false
表示均衡器未启用,您可以通过 sh.startBalancer()
命令开启均衡器。更多详情,请参见 Enable the Balancer。
说明
从 MongoDB 4.2起,通过 sh.startBalancer()
命令开启均衡器时,会默认打开分片集群的自动分裂功能,更多详情,请参见 sh.enableAutoSplit。
对集合进行分片。
您可以选择如下任意一种方法对目标集合进行分片。
说明
本文示例中使用了 VehicleId
和 Timestamp
字段组合作为 shard key,您需要先为这两个字段创建复合索引。创建索引的具体方法,请参见 db.collection.createIndex()。
说明
关于 sh.shardCollection
命令的更多详情,请参见 sh.shardCollection()。
命令示例如下。sh.shardCollection("<database>.<collection>",{"<keyname>":<value> })
sh.shardCollection("IoV.AutonomousCar",{"VehicleId":1,"Timestamp":1})
use admin
命令进入 admin 数据库,然后执行如下命令。说明
关于 shardcollection
命令的更多详情,请参见 shardCollection。
命令示例如下。db.runCommand({shardcollection:"<database>.<collection>",key:{"keyname":<value> }})
db.runCommand({shardcollection:"IoV.AutonomousCar",key:{"VehicleId":1,"Timestamp":1}})
参数 | 说明 |
---|---|
<database> | 目标数据库的名称。 |
<collection> | 目标集合的名称。 |
<keyname> | 分片键。集群实例将根据该值进行数据分片,请结合实际业务为集合选择合适的分片键。更多详情,请参见设置合适的 shard key。 |
| 基于分片键的分片策略。取值范围如下:
说明 关于分片策略的更多信息,请参见支持的分片策略。 |
numInitialChunks | 当使用Hash分片键对空集合进行分片时,指定初始创建的最小分片数。关于 numInitialChunks 的更多信息,请参见 sh.shardCollection()_option 或 shardCollection_command-fields。 |
在目标数据库中,执行如下命令查看数据库在各分片节点的数据存储情况。
sh.status()
更多详情,请参见 sh.status()。