分步指南:部署基本 MongoDB 分片集群
部署一个包含配置服务器、分片副本集、mongos 路由器和分片验证的基本 MongoDB 分片集群。
分步指南:部署基本 MongoDB 分片集群
MongoDB 是一款流行的 NoSQL 文档数据库,在处理大量数据时具有高性能和灵活性。然而,随着数据增长,单个服务器或副本集可能达到其扩展极限。这时分片技术便发挥作用,通过将数据分布到多个服务器(即分片)来实现水平扩展。
本指南将引导您在本地主机上搭建一个基本的 MongoDB 分片集群以进行学习。您将配置配置服务器、分片副本集和 mongos 路由器,然后为集合启用分片。
理解 MongoDB 分片集群
MongoDB 分片集群由三个主要组件组成,它们协同工作以分发和路由数据:
- 分片副本集:这些是实际承载数据的节点。每个分片都是一个副本集,以提供高可用性和数据冗余。数据在这些分片之间进行分区。
- 配置服务器:这些服务器存储集群的元数据,包括数据块到分片的映射。从 MongoDB 3.2 开始,配置服务器必须部署为副本集(CSRS - 配置服务器副本集),以实现高可用性和一致性。
mongos路由器:这些充当查询路由器,为客户端应用程序提供接口。mongos实例根据集群的元数据将客户端操作定向到适当的分片。应用程序连接到mongos,而不是直接连接到分片。
MongoDB 分片集群的概念图(图片来源:MongoDB 官方文档)
前提条件
在开始之前,请确保您具备以下条件:
- 多台机器/虚拟机:对于真正分布式的分片集群,您至少需要 6-9 台机器/虚拟机/Docker 容器。在本基础教程中,我们可以使用不同端口在单台机器上模拟,但请记住生产环境需要专用资源。
- 3 台用于配置服务器(configSrv01、configSrv02、configSrv03)
- 每个分片至少 2-3 台(例如,Shard01-RS01、Shard01-RS02、Shard01-RS03;Shard02-RS01、...)
- 1 台以上用于
mongos路由器
- MongoDB 安装:在每台将运行
mongod或mongos的机器上安装受支持的 MongoDB 服务器版本。使用mongosh执行 shell 命令。 - 网络:确保所有机器能在必要端口上相互通信(配置服务器、分片和
mongos的默认端口分别为27017、27018、27019、27020,或使用自定义端口)。 - 目录结构:为每个
mongod和mongos实例创建专用的数据和日志目录。
为简化本指南,我们将使用 localhost 和不同端口及目录。在生产环境中,您应使用实际的主机名或 IP 地址。
推荐的目录结构(本地主机设置示例)
mkdir -p /data/db/configdb01 /data/db/configdb02 /data/db/configdb03
mkdir -p /data/db/shard01-rs01 /data/db/shard01-rs02 /data/db/shard01-rs03
mkdir -p /data/db/shard02-rs01 /data/db/shard02-rs02 /data/db/shard02-rs03
mkdir -p /data/log/config /data/log/shard01 /data/log/shard02 /data/log/mongos
部署步骤
步骤 1:设置配置服务器(配置副本集)
配置服务器存储分片集群的元数据。它们必须作为副本集运行。
启动配置服务器的
mongod实例:每个实例需要--configsvr和--replSet选项。# 配置服务器 1 mongod --configsvr --replSet cfgReplSet --dbpath /data/db/configdb01 --port 27019 --bind_ip localhost --logpath /data/log/config/configdb01.log --fork # 配置服务器 2 mongod --configsvr --replSet cfgReplSet --dbpath /data/db/configdb02 --port 27020 --bind_ip localhost --logpath /data/log/config/configdb02.log --fork # 配置服务器 3 mongod --configsvr --replSet cfgReplSet --dbpath /data/db/configdb03 --port 27021 --bind_ip localhost --logpath /data/log/config/configdb03.log --fork提示:对于生产环境,将
localhost替换为实际的 IP 地址或主机名。初始化配置副本集:连接到其中一个配置服务器实例并初始化副本集。
mongosh --port 27019在 mongo shell 中:
rs.initiate({ _id: "cfgReplSet", configsvr: true, members: [ { _id : 0, host : "localhost:27019" }, { _id : 1, host : "localhost:27020" }, { _id : 2, host : "localhost:27021" } ] });验证状态:
rs.status();
步骤 2:设置分片副本集
集群中的每个分片都是一个副本集。我们将设置两个分片(shard01 和 shard02),每个分片包含三个成员。
启动分片 1 成员的
mongod实例:每个实例需要--shardsvr和--replSet选项。# 分片 1 成员 1 mongod --shardsvr --replSet shard01 --dbpath /data/db/shard01-rs01 --port 27030 --bind_ip localhost --logpath /data/log/shard01/shard01-rs01.log --fork # 分片 1 成员 2 mongod --shardsvr --replSet shard01 --dbpath /data/db/shard01-rs02 --port 27031 --bind_ip localhost --logpath /data/log/shard01/shard01-rs02.log --fork # 分片 1 成员 3 mongod --shardsvr --replSet shard01 --dbpath /data/db/shard01-rs03 --port 27032 --bind_ip localhost --logpath /data/log/shard01/shard01-rs03.log --fork初始化分片 1 副本集:连接到其中一个分片 1 实例。
mongosh --port 27030在 mongo shell 中:
rs.initiate({ _id : "shard01", members: [ { _id : 0, host : "localhost:27030" }, { _id : 1, host : "localhost:27031" }, { _id : 2, host : "localhost:27032" } ] });启动分片 2 成员的
mongod实例(对其他分片重复):# 分片 2 成员 1 mongod --shardsvr --replSet shard02 --dbpath /data/db/shard02-rs01 --port 27040 --bind_ip localhost --logpath /data/log/shard02/shard02-rs01.log --fork # 分片 2 成员 2 mongod --shardsvr --replSet shard02 --dbpath /data/db/shard02-rs02 --port 27041 --bind_ip localhost --logpath /data/log/shard02/shard02-rs02.log --fork # 分片 2 成员 3 mongod --shardsvr --replSet shard02 --dbpath /data/db/shard02-rs03 --port 27042 --bind_ip localhost --logpath /data/log/shard02/shard02-rs03.log --fork初始化分片 2 副本集:连接到其中一个分片 2 实例。
mongosh --port 27040在 mongo shell 中:
rs.initiate({ _id : "shard02", members: [ { _id : 0, host : "localhost:27040" }, { _id : 1, host : "localhost:27041" }, { _id : 2, host : "localhost:27042" } ] });
步骤 3:设置 mongos 路由器
mongos 实例是客户端应用程序的入口点。它们需要知道配置服务器的位置。
启动
mongos实例:提供--configdb选项,列出配置副本集成员。# Mongos 路由器 1 mongos --configdb cfgReplSet/localhost:27019,localhost:27020,localhost:27021 --port 27017 --bind_ip localhost --logpath /data/log/mongos/mongos01.log --fork注意:您可以启动多个
mongos实例以实现负载均衡和高可用性。它们都连接到相同的配置服务器。
步骤 4:连接到 mongos 并添加分片
现在,连接到 mongos 实例并将分片副本集添加到集群。
连接到
mongos:使用默认的 MongoDB 端口27017或您为mongos指定的自定义端口。mongosh --port 27017添加分片:使用
sh.addShard()命令,指定副本集名称及其一个成员。sh.addShard("shard01/localhost:27030"); sh.addShard("shard02/localhost:27040");
步骤 5:为数据库和集合启用分片
添加分片后,您需要为特定数据库启用分片,然后为该数据库中的特定集合启用分片。这需要选择一个 分片键。
为数据库启用分片:切换到要分片的数据库并运行
sh.enableSharding()。use mydatabase; sh.enableSharding("mydatabase");分片一个集合:选择一个
分片键并使用sh.shardCollection()。警告:选择有效的分片键对于性能和均匀分布至关重要。糟糕的分片键可能导致热点或低效查询。常见策略包括哈希键、范围键或复合键。
在本示例中,假设有一个包含字段
_id的集合mycollection。sh.shardCollection("mydatabase.mycollection", { _id: "hashed" });对于教程来说,哈希
_id分片键很简单,因为它比单调递增的范围_id键能更好地分散插入操作。对于实际应用,应根据查询模式和写入分布选择分片键,而不仅仅为了方便。
步骤 6:验证集群
在连接到 mongos 的 mongosh 中运行以下命令:
sh.status();
db.adminCommand({ listShards: 1 });
然后插入示例文档并检查分片集合是否存在:
use mydatabase;
db.mycollection.insertMany([
{ _id: 1, name: "alpha" },
{ _id: 2, name: "beta" },
{ _id: 3, name: "gamma" }
]);
db.mycollection.getShardDistribution();
小的测试数据集可能不会立即拆分,因此不要期望在仅插入几个文档后就能完美分布。重要的第一步检查是 sh.status() 列出两个分片并显示 mydatabase.mycollection 已分片。
生产环境注意事项
此本地主机设置有助于学习各个组件,但生产环境需要更多关注:
- 使用真实主机名,而不是
localhost,因为副本集成员名称存储在集群元数据中。 - 将配置服务器作为三个成员的副本集运行。
- 将每个分片作为副本集运行,成员分布在不同的故障域中。
- 在暴露集群之前启用身份验证和内部密钥文件或 x.509 身份验证。
- 作为集群感知备份计划的一部分,备份配置服务器元数据和分片数据。
- 监控块分布、均衡器活动、复制延迟和磁盘增长。
最终要点
MongoDB 分片集群有三个任务:配置服务器跟踪元数据,分片副本集存储数据,mongos 路由客户端流量。首先让这些角色正常工作,然后将大部分设计时间花在分片键上,因为这一选择决定了您的集群是均匀分布负载还是产生热点分片。