第五章 副本集与分片 v1.0
本文以三节点副本集部署为例,基于 openEuler 24.03 (LTS-SP1) + MongoDB 7.0.11 进行说明
[一键部署脚本 init.sh]
bash
#!/bin/bash
set -e
### note
# 使用此脚本前请确保对应主机已正确配置对应IP与对应密码
# file path
file_dir=$(dirname "$(realpath "$0")")
distribute_sh="$file_dir/tools/distribute.sh"
config_path="$file_dir/config"
download_path="$file_dir/download"
ssh_config_file="$config_path/config.conf"
mongo_config_temp_file="$config_path/mongod.conf.temp"
# cluster conf
cluster_ips=("192.168.2.211" "192.168.2.212" "192.168.2.213")
username="root"
password="<password>"
# download source
resource_path="/root/download/resource/mongodb"
# mongodb version
redhat_version="8"
mongodb_major_version="7.0"
mongodb_full_version="7.0.11"
mongos_version="2.2.6"
# mongodb config
mongodb_port=27017
admin_username="admin"
admin_password="<password>"
# 生成 SSH 配置文件
function make_ssh_config() {
>"$ssh_config_file"
for ip in "${cluster_ips[@]}"; do
echo "$ip $username $password" >>"$ssh_config_file"
done
echo "SSH配置文件位置: $ssh_config_file"
}
# 生成配置
function make_configs() {
mkdir -p "$config_path"
make_ssh_config
}
function write_hosts() {
# 生成新的hosts映射
node_count=1
for ip in "${cluster_ips[@]}"; do
record="$ip node-$node_count"
bash $distribute_sh -c "$ssh_config_file" -e "if ! grep -q \"$record\" \"/etc/hosts\"; then echo \"添加hosts映射 /etc/hosts: $record\";bash -c \"echo '$record' >> /etc/hosts\";else echo \"已存在 $record 存在于 /etc/hosts 中,跳过添加。\" ;fi"
((node_count++))
done
}
function install_mongodb() {
mkdir -p "$download_path"
cd "$download_path"
# 获取 RPM URL(不修改全局变量)
base_url="https://repo.mongodb.org/yum/redhat/${redhat_version}/mongodb-org/${mongodb_major_version}/x86_64/RPMS/"
rpm_packages=(
# 核心包(必选):包含 MongoDB 元数据和依赖声明(实际安装的是下面几个包)
"mongodb-org-${mongodb_full_version}-1.el${redhat_version}.x86_64.rpm"
# 服务端(必选):mongod 守护进程、初始化脚本和管理工具
"mongodb-org-server-${mongodb_full_version}-1.el${redhat_version}.x86_64.rpm"
# Shell:新版 MongoDB 默认的交互式 JavaScript Shell(替代旧版 mongo 命令)
"mongosh-${mongos_version}.x86_64.rpm"
# 数据导出和导入、备份和恢复、mongodump 和 mongorestore 等
"mongodb-org-database-${mongodb_full_version}-1.el${redhat_version}.x86_64.rpm"
# mongos 路由服务(分片集群需要)
"mongodb-org-mongos-${mongodb_full_version}-1.el${redhat_version}.x86_64.rpm"
)
# 下载并分发 RPM
for package in "${rpm_packages[@]}"; do
download_url="${base_url}${package}"
echo "download: $download_url to $download_path/$package"
if [ ! -f "$download_path/$package" ]; then
wget "$download_url" -O "$download_path/$package"
fi
if [ $? -eq 0 ]; then
echo "$package 下载成功"
bash $distribute_sh -c "$ssh_config_file" -f "$download_path/$package" -d "$resource_path/$package"
if [ $? -eq 0 ]; then
echo "$package 分发成功"
else
echo "$package 分发失败,退出..."
exit 1
fi
else
echo "$package 下载失败,退出..."
exit 1
fi
done
# 安装 RPM
bash $distribute_sh -c "$ssh_config_file" -e "cd $resource_path && rpm -ivh --nodeps ${rpm_packages[*]}"
if [ $? -eq 0 ]; then
echo "$package 安装成功"
else
echo "$package 安装失败,退出..."
exit 1
fi
# 安装 libcrypto.so.*
bash $distribute_sh -c "$ssh_config_file" -e "yum install -y libcrypto.so.*"
if [ $? -eq 0 ]; then
echo "libcrypto.so.* 安装成功"
else
echo "libcrypto.so.* 安装失败,退出..."
exit 1
fi
}
# 设置认证(生成密码文件 + 配置 + 重启服务 + 验证)
function setup_authentication() {
# 创建密钥文件(内容为随机字符串)
bash $distribute_sh -c "$ssh_config_file" -e "mongosh --eval \"
db.createUser({
user: '$admin_username',
pwd: '$admin_password',
roles: [{ role: 'root', db: 'admin' }]
});
\" admin"
# 修改配置文件(添加认证配置)
bash $distribute_sh -c "$ssh_config_file" -e "mv /etc/mongod.conf /etc/mongod.conf.bak"
bash $distribute_sh -c "$ssh_config_file" -f "$mongo_config_temp_file" -d "/etc/mongod.conf"
bash $distribute_sh -c "$ssh_config_file" -e "chmod 644 /etc/mongod.conf"
# 重启 MongoDB 服务
bash $distribute_sh -c "$ssh_config_file" -e "systemctl restart mongod"
# 验证认证配置
bash $distribute_sh -c "$ssh_config_file" -e "mongosh -u '$admin_username' -p '$admin_password' --authenticationDatabase admin --eval 'db.version()'"
if [ $? -eq 0 ]; then
echo "MongoDB认证配置成功!"
else
echo "MongoDB认证配置失败,退出..."
exit 1
fi
}
function start_mongodb() {
echo "start mongodb"
bash $distribute_sh -c "$ssh_config_file" -e "firewall-cmd --zone=public --add-port=$mongodb_port/tcp --permanent"
bash $distribute_sh -c "$ssh_config_file" -e "firewall-cmd --reload"
# start and enable
bash $distribute_sh -c "$ssh_config_file" -e "systemctl start mongod"
bash $distribute_sh -c "$ssh_config_file" -e "systemctl enable mongod"
}
function install() {
write_hosts
install_mongodb
start_mongodb
setup_authentication
}
function main() {
make_configs
install
}
main一、副本集(Replica Set)
副本集是MongoDB实现高可用的核心机制,由一组维护相同数据集的mongod进程组成。
1.副本集架构
- Primary:接收所有写操作,数据变更通过oplog同步到Secondary
- Secondary:复制Primary的数据,Primary故障时可自动选举为新Primary
- 最少需要3个节点(1 Primary + 2 Secondary,或1 Primary + 1 Secondary + 1 Arbiter)
2.准备工作
[IP配置]
修改各节点 /etc/sysconfig/network-scripts/ifcfg-ens33 配置静态IP,例如:
bash
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=static
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=no
NAME=ens33
DEVICE=ens33
ONBOOT=yes
IPADDR=192.168.2.211
NETMASK=255.255.255.0
GATEWAY=192.168.2.1
DNS1=192.168.2.1使配置生效:
bash
systemctl restart network[KnowHost配置]
在各节点的 /etc/hosts 中添加IP与主机名的映射,脚本中会自动写入,也可以手动添加:
bash
192.168.2.211 node-1
192.168.2.212 node-2
192.168.2.213 node-33.安装MongoDB
实际部署中采用 RPM 离线安装,适用于内网环境;联网环境可直接
yum install mongodb-org
[RPM 离线安装]
需要下载以下 RPM 包(版本通过变量动态拼接):
bash
# 基础 URL
base_url="https://repo.mongodb.org/yum/redhat/${redhat_version}/mongodb-org/${mongodb_major_version}/x86_64/RPMS/"
# 以 7.0.11 为例,需要下载的包:
# mongodb-org-7.0.11-1.el8.x86_64.rpm # 元数据包,协调安装依赖
# mongodb-org-server-7.0.11-1.el8.x86_64.rpm # 核心服务 mongod
# mongodb-mongosh-2.2.6.x86_64.rpm # Shell 客户端
# mongodb-org-tools-7.0.11-1.el8.x86_64.rpm # 备份恢复工具(mongodump、mongorestore)
# mongodb-org-mongos-7.0.11-1.el8.x86_64.rpm # 分片集群路由(分片时才用)下载完成后在目标机器上安装:
bash
cd /root/download/resource/mongodb && rpm -ivh --nodeps mongodb-org-*.rpm
# 安装依赖库(RPM离线安装可能缺失)
yum install -y libcrypto.so.*4.配置与启动
bash
# 开放防火墙端口
firewall-cmd --zone=public --add-port=27017/tcp --permanent
firewall-cmd --reload
# 启动并设为开机自启
systemctl start mongod
systemctl enable mongod[默认配置文件 /etc/mongod.conf]
yaml
systemLog:
destination: file
logAppend: true
path: /var/log/mongodb/mongod.log
storage:
dbPath: /var/lib/mongo
net:
port: 27017
bindIp: 0.0.0.0
# 副本集名称(所有节点必须一致)
#replication:
# replSetName: myReplSet5.设置管理员密码
在启用认证之前,先连接到 admin 库创建管理员用户:
bash
# 此时尚未启用认证
mongosh --eval "
db.createUser({
user: 'admin',
pwd: '<your-admin-password>',
roles: [{ role: 'root', db: 'admin' }]
});
" admin然后在 mongod.conf 中启用认证并重启:
yaml
security:
authorization: enabledbash
systemctl restart mongod验证密码是否生效:
bash
mongosh -u 'admin' -p '<your-admin-password>' --authenticationDatabase admin --eval 'db.version()'
# MongoDB密码设置成功!6.初始化副本集
bash
mongosh -u 'admin' -p '<your-admin-password>' --authenticationDatabase adminjavascript
rs.initiate({
_id: "myReplSet",
members: [
{ _id: 0, host: "192.168.2.211:27017" },
{ _id: 1, host: "192.168.2.212:27017" },
{ _id: 2, host: "192.168.2.213:27017" }
]
})
// 查看副本集状态
rs.status()7.日常运维
| 操作 | 命令 |
|---|---|
| 查看副本集状态 | rs.status() |
| 查看当前是否主节点 | rs.isMaster() |
| 降级主节点(触发选举) | rs.stepDown() |
| 添加节点 | rs.add("192.168.2.214:27017") |
| 移除节点 | rs.remove("192.168.2.214:27017") |
[修改节点优先级]
javascript
cfg = rs.conf()
cfg.members[0].priority = 10
rs.reconfig(cfg)二、分片(Sharding)
分片是MongoDB实现水平扩展的机制,将数据分散存储到多个服务器上。
1.分片架构
Client
│
▼
mongos (路由)
│
├── Config Server (配置服务器,存储元数据)
│
├── Shard 1 (分片1:副本集)
├── Shard 2 (分片2:副本集)
└── Shard 3 (分片3:副本集)- mongos:路由服务,接收客户端请求并路由到正确的分片
- Config Server:存储集群元数据(分片键范围、数据分布等)
- Shard:每个分片是一个副本集,存储部分数据
2.启用分片
javascript
// 连接到 mongos
mongosh --port 27017
// 启用数据库分片
sh.enableSharding("mydb")
// 对集合启用分片(指定分片键)
sh.shardCollection("mydb.users", { userId: "hashed" })
// 查看分片状态
sh.status()3.分片键选择
| 类型 | 说明 | 特点 |
|---|---|---|
| 哈希分片 | sh.shardCollection("db.col", { field: "hashed" }) | 数据分布均匀,范围查询效率低 |
| 范围分片 | sh.shardCollection("db.col", { field: 1 }) | 支持范围查询,可能出现热点 |
| 区域分片 | 配合tag实现数据亲和性 | 符合数据本地化要求 |
三、副本集 vs 分片
| 对比项 | 副本集 | 分片 |
|---|---|---|
| 目的 | 高可用 | 高性能/可扩展 |
| 数据存储 | 所有节点完整副本 | 数据分散在不同分片 |
| 读写分离 | 支持 | 支持 |
| 适用场景 | 数据量不大,需要高可用 | 数据量大,需要水平扩展 |
| 组合使用 | 可以 | 每个分片通常是副本集 |