这里示例集群一共三台机器,主机名分别为:ecs12
,ecs13
,ecs14
当前部署的 MongoDB 版本为 6.0.13,安装包名称为:mongodb-6.0.13-docker.tar.gz,其中每个节点均包含:router(mongos)
、configsvr
以及 shard
这 3 个角色。这里的 shard
都是单个独立的分片,不包含对应的副本集。configsvr
包含 3 个副本集。
每个节点都安装 Docker 以及 Docker Compose 插件,Docker 版本必须大于 20.10.10,Docker Compose 网络采用 host 模式部署。
其中每个角色对应的端口如下:
所有节点执行安装镜像操作:
tar -xvzf mongodb-6.0.13-docker.tar.gz -C /opt
cd /opt/mongodb-6.0.13-docker
./install.sh
每个机器都执行后镜像就导入完毕了。
之后操作需要进入 Docker Compose 项目具体的安装目录,当前是 /opt/mongodb-6.0.13-docker
目录:
cd /opt/mongodb-6.0.13-docker
编辑 Docker Compose 的配置文件:docker-compose.yml
,其中的默认配置如下:
version: '3'
services:
router:
image: mongo:6.0.13
container_name: mongodb-router
command: mongos --port 27017 --configdb rs-config-server/node1:27019,node2:27019,node3:27019 --bind_ip_all --keyFile=/etc/mongodb/mongodb.key
restart: always
network_mode: "host"
environment:
- TZ=Asia/Shanghai
volumes:
- ./scripts:/scripts
- ./security:/etc/mongodb
- /data/mongodb-router/db:/data/db
- /data/mongodb-router/configdb:/data/configdb
configsvr:
image: mongo:6.0.13
container_name: mongodb-configsvr
command: mongod --port 27019 --configsvr --replSet rs-config-server --keyFile=/etc/mongodb/mongodb.key --auth
restart: always
network_mode: "host"
environment:
- TZ=Asia/Shanghai
volumes:
- ./scripts:/scripts
- ./security:/etc/mongodb
- /data/mongodb-config/db:/data/db
- /data/mongodb-config/configdb:/data/configdb
shard:
image: mongo:6.0.13
container_name: mongodb-shard
command: mongod --port 27018 --shardsvr --replSet rs-shard-01 --keyFile=/etc/mongodb/mongodb.key --auth
restart: always
network_mode: "host"
environment:
- TZ=Asia/Shanghai
volumes:
- ./scripts:/scripts
- ./security:/etc/mongodb
- /data/mongodb-shard/db:/data/db
- /data/mongodb-shard/configdb:/data/configdb
其中分为三个服务,分别是 router
、configsvr
以及 shard
。
在 router
中的 command
配置中要修改其中的主机列表 node1
、node2
和 node3
为我们当前的主机,即 ecs12
、ecs13
以及 ecs14
,端口号默认不需要修改。
修改 shard
中的 command
配置 --replSet
指定的参数按照节点递增,比如当前 ecs12
设置为 rs-shard-01
,那么 ecs13
节点上就要设置为 rs-shard-02
,ecs14
节点上设置为 rs-shard-03
,依此类推。
最后是这 3 个服务的数据目录都要根据实际的设置,要将目录放到专门的数据盘上,推荐使用 SSD 存储,只修改 :
前面的目录即可。
当前 3 个节点全部修改完成之后,所有节点依次执行命令启动:
./mongodb-server.sh start
# 启动后查看状态
./mongodb-server.sh status
如果启动没有问题可以进入下一步的配置了。
我们首先初始化 Config Server,在任意一个节点上即可,当前我们在 ecs12
节点上操作,首先编辑 scripts/init-configserver.js
文件,修改其中的主机名例如:
rs.initiate({_id: "rs-config-server", configsvr: true, version: 1, members: [ { _id: 0, host : 'ecs12:27019' }, { _id: 1, host : 'ecs13:27019' }, { _id: 2, host : 'ecs14:27019' } ] })
修改后保存,然后我们执行:
docker-compose -f docker-compose.yml exec configsvr sh -c "mongosh --port 27019 < /scripts/init-configserver.js"
执行成功之后,我们进入客户端确认状态:
./mongodb-client.sh config
# 进入客户端后执行
> rs.status()
即可看到 Config Server 副本集的状态。
然后我们在每个节点都编辑 scripts/init-shard.js
,分别修改内容如下:
// ecs12
rs.initiate({_id: "rs-shard-01", version: 1, members: [ { _id: 0, host : "ecs12:27018" } ] })
// ecs13
rs.initiate({_id: "rs-shard-02", version: 1, members: [ { _id: 0, host : "ecs13:27018" } ] })
// ecs14
rs.initiate({_id: "rs-shard-03", version: 1, members: [ { _id: 0, host : "ecs14:27018" } ] })
修改之后保存文件,由于开启了集群认证,因此需要在每个节点单独运行:
# 所有节点都要执行
docker-compose -f docker-compose.yml exec shard sh -c "mongosh --port 27018 < /scripts/init-shard.js"
初始化 mongos 只需要在一个节点执行即可,我们这里在 ecs12
上执行,首先编辑 scripts/init-router.js
,修改内容为实际的节点如下:
sh.addShard("rs-shard-01/ecs12:27018")
sh.addShard("rs-shard-02/ecs13:27018")
sh.addShard("rs-shard-03/ecs14:27018")
这个配置要和上一步初始化的名称和节点完全保持一致,修改无误后保存并退出,然后运行:
docker-compose -f docker-compose.yml exec router sh -c "mongosh --port 27017 < /scripts/init-router.js"
然后我们需要在集群中创建管理用户:
# 进入到 mongos
./mongodb-client.sh router
进入后执行创建管理用户的操作:
db.getSiblingDB("admin").createUser(
{
user: "admin",
pwd: passwordPrompt(),
roles: [{ role: "root", db: "admin" }]
})
执行后输入密码即可完成创建,但是要注意创建完成后立即生效,必须认证后才可以进行下一步的访问:
use admin
db.auth('admin', '<password>')
认证后即可正常操作,比如查看集群状态:
sh.status()
同样我们访问 Config Server 也是使用相同的管理用户,但是这个用户仅用于管理员维护使用,由于 root 这个 role 权限太高,它包括了集群所有的管理和访问权限,所以我们需要为应用程序创建单独的用户,例如:
db.getSiblingDB("admin").createUser(
{
user: "web",
pwd: passwordPrompt(),
roles: [{ role: "readWrite", db: "dev" }]
})
然后程序可以使用这个示例的 web
用户进行访问。
我们通常都是访问 mongos 角色进行数据的读写,一般不会访问 shard 服务,但是有时候我们可能需要单独的排查 shard 的状态,这个时候只能通过本机 localhost 网络接口访问,远程访问则必须认证,但是这个认证的用户和上面我们创建的管理用户是不一样的,我们也可以为 shard 创建专门的用户,这步是可选的,但是这个用户只用来管理状态,不需要读写数据,例如:
# 必须从本机连接 shard 服务
./mongodb-client.sh shard
然后创建用户:
// 每个 shard 都需要单独创建用户
db.getSiblingDB("admin").createUser(
{
user: "manager",
pwd: passwordPrompt(),
roles: [ { role: "clusterAdmin", db: "admin" } ]
})
然后就可以查看 shard 的状态了:
use admin
db.auth('manager', 'password')
rs.status()
这个用户只能用来连接 shard 且必须每个 shard 从本地单独创建。
到这里 MongoDB 分片集群就搭建完毕并正常运行了,我们可以创建分片的 Collection 测试一下是否正常。
任意节点机器连接 MongoDB 集群的 mongos 服务:
./mongodb-client.sh router
认证并设置 Collection 的分片策略:
use admin
db.auth('admin', '<password>')
// 例如设置 hash 分片策略,设置时会自动创建 Database 和 Collection
sh.shardCollection("test.col", { _id : "hashed" } )
插入一批测试数据:
use test
for(i = 0; i < 100; i++) {
var doc = {_id: i};
if(i % 2 == 0)
doc.value = "even";
else
doc.value = "odd";
db.col.insertOne(doc);
}
// 或者批量写入
var arr = [];
for(i = 0; i < 100; i++) {
var doc = {_id: i};
if(i % 2 == 0)
doc.value = "even";
else
doc.value = "odd";
arr.push(doc);
}
db.col.insertMany(arr);
然后可以查看 Collection 的数据分布情况:
// 可以看到总条数以及每个节点的条数情况
db.col.getShardDistribution()
删除测试的 Collection:
db.col.drop()
Reference: