Skip to content

第五章 副本集与分片 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.副本集架构 ​

uml diagram
  • 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-3

3.安装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: myReplSet

5.设置管理员密码 ​

在启用认证之前,先连接到 admin 库创建管理员用户:

bash
# 此时尚未启用认证
mongosh --eval "
    db.createUser({
        user: 'admin',
        pwd: '<your-admin-password>',
        roles: [{ role: 'root', db: 'admin' }]
    });
" admin

然后在 mongod.conf 中启用认证并重启:

yaml
security:
  authorization: enabled
bash
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 admin
javascript
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 分片 ​

对比项副本集分片
目的高可用高性能/可扩展
数据存储所有节点完整副本数据分散在不同分片
读写分离支持支持
适用场景数据量不大,需要高可用数据量大,需要水平扩展
组合使用可以每个分片通常是副本集