分步指南:部署基本的 MongoDB 分片集群
MongoDB 作为一种流行的 NoSQL 文档数据库,在处理大量数据时表现出卓越的性能和灵活性。然而,随着数据量的增长,单个服务器或副本集可能会达到其扩展极限。这时,分片技术应运而生,它通过将数据分布到多个服务器(即分片)上来实现水平扩展。
本综合指南将引导您完成设置功能性 MongoDB 分片集群的整个过程。您将学习如何配置基本组件:配置服务器(config servers)、mongos 路由器和分片副本集。通过本教程,您将对部署旨在实现高水平可扩展性和可用性的分片集群有一个扎实的理解和实践经验。
理解 MongoDB 分片集群
MongoDB 分片集群由三个主要组件组成,它们协同工作以分发和路由数据:
- 分片副本集 (Shard Replica Sets):这些是实际存储数据的节点。每个分片都是一个副本集,以提供高可用性和数据冗余。数据在这些分片之间进行分区。
- 配置服务器 (Config Servers):这些服务器存储集群的元数据,包括数据块到分片的映射。从 MongoDB 3.2 开始,配置服务器必须作为副本集(CSRS - Config Server Replica Set)部署,以实现高可用性和一致性。
mongos路由器 (Routers):这些作为查询路由器,为客户端应用程序提供接口。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 4.2+。您可以在 MongoDB 文档中找到安装说明。 - 网络:确保所有机器都能在必要的端口上相互通信(配置服务器、分片和
mongos的默认端口分别为27017、27018、27019、27020,或自定义端口)。 - 目录结构:为每个
mongod和mongos实例创建专门的数据和日志目录。
为了简化本指南,我们将使用 localhost 和不同的端口及目录。在生产环境中,您将使用实际的主机名或 IP 地址。
推荐的目录结构(localhost 设置示例)
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:设置配置服务器(Config 副本集)
配置服务器存储分片集群的元数据。它们必须作为副本集运行。
-
启动配置服务器的
mongod实例:每个实例都需要--configsvr和--replSet选项。```bash
Config Server 1
mongod --configsvr --replSet cfgReplSet --dbpath /data/db/configdb01 --port 27019 --bind_ip localhost --logpath /data/log/config/configdb01.log --fork
Config Server 2
mongod --configsvr --replSet cfgReplSet --dbpath /data/db/configdb02 --port 27020 --bind_ip localhost --logpath /data/log/config/configdb02.log --fork
Config Server 3
mongod --configsvr --replSet cfgReplSet --dbpath /data/db/configdb03 --port 27021 --bind_ip localhost --logpath /data/log/config/configdb03.log --fork
```提示:对于生产环境,请将
localhost替换为实际的 IP 地址或主机名。 -
初始化配置副本集:连接到其中一个配置服务器实例并初始化副本集。
bash mongo --port 27019在 mongo shell 中:
javascript rs.initiate({ _id: "cfgReplSet", configsvr: true, members: [ { _id : 0, host : "localhost:27019" }, { _id : 1, host : "localhost:27020" }, { _id : 2, host : "localhost:27021" } ] });验证状态:
javascript rs.status();
步骤 2:设置分片副本集
集群中的每个分片都是一个副本集。我们将设置两个分片(shard01 和 shard02),每个分片有三个成员。
-
启动分片 1 成员的
mongod实例:每个实例都需要--shardsvr和--replSet选项。```bash
Shard 1 Member 1
mongod --shardsvr --replSet shard01 --dbpath /data/db/shard01-rs01 --port 27030 --bind_ip localhost --logpath /data/log/shard01/shard01-rs01.log --fork
Shard 1 Member 2
mongod --shardsvr --replSet shard01 --dbpath /data/db/shard01-rs02 --port 27031 --bind_ip localhost --logpath /data/log/shard01/shard01-rs02.log --fork
Shard 1 Member 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 的一个实例。
bash mongo --port 27030在 mongo shell 中:
javascript rs.initiate({ _id : "shard01", members: [ { _id : 0, host : "localhost:27030" }, { _id : 1, host : "localhost:27031" }, { _id : 2, host : "localhost:27032" } ] }); -
启动分片 2 成员的
mongod实例(对其他分片重复此步骤):```bash
Shard 2 Member 1
mongod --shardsvr --replSet shard02 --dbpath /data/db/shard02-rs01 --port 27040 --bind_ip localhost --logpath /data/log/shard02/shard02-rs01.log --fork
Shard 2 Member 2
mongod --shardsvr --replSet shard02 --dbpath /data/db/shard02-rs02 --port 27041 --bind_ip localhost --logpath /data/log/shard02/shard02-rs02.log --fork
Shard 2 Member 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 的一个实例。
bash mongo --port 27040在 mongo shell 中:
javascript 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选项,列出配置副本集成员。```bash
Mongos Router 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指定的自定义端口。bash mongo --port 27017 -
添加分片:使用
sh.addShard()命令,指定副本集名称及其一个成员。javascript sh.addShard("shard01/localhost:27030"); sh.addShard("shard02/localhost:27040");
步骤 5:为数据库和集合启用分片
添加分片后,您需要为特定数据库启用分片,然后为这些数据库中的特定集合启用分片。这需要选择一个 shard key。
-
为数据库启用分片:切换到要分片的数据库并运行
sh.enableSharding()。javascript use mydatabase; sh.enableSharding("mydatabase"); -
对集合进行分片:选择一个
shard key并使用sh.shardCollection()。警告:选择一个有效的分片键对于性能和均匀分布至关重要。一个糟糕的分片键可能导致热点或低效查询。常见的策略包括哈希键、范围键或复合键。
在本例中,我们假设一个名为
mycollection的集合,其中包含_id字段。```javascript
sh.shardCollection("mydatabase.mycollection"