MongoDB-3 分片集群

MongoDB 分片集群(Sharded Cluster)详解

  • MongoDB 分片集群是一种水平扩展的数据库架构,用于处理海量数据和高吞吐量应用。它将数据分布在多个服务器上,使系统能够超越单台服务器的存储和性能限制。

1. 分片集群的核心组件

分片(Shard)

  • 功能:存储实际数据块(chunks)
  • 组成:每个分片可以是一个独立的 MongoDB 实例,但生产环境推荐使用副本集
  • 特点:
    • 每个分片存储部分数据
    • 可以动态添加更多分片来扩展容量

配置服务器(Config Servers)

  • 功能:存储集群的元数据和配置信息
  • 要求:
    • 必须部署为副本集(至少3个节点)
    • 存储分片键范围、数据块位置等元数据

查询路由器(Mongos)

  • 功能:作为应用程序的入口点。提供客户端应用程序和分片集群之间的接口

  • 特点:

    • 不存储数据
    • 将查询路由到正确的分片
    • 可以部署多个实例以提高可用性
  • 生产环境中,常见的分片集群架构
    image

  • 测试环境中,常见的分片集群架构
    image

2. 分片集群工作原理

2.1 数据分布机制

  • 数据根据分片键(Shard Key)被分成多个数据块(chunks)。shard key由文档中的一个或多个字段组成
  • 每个chunk默认大小为64MB(可配置)
  • 当chunk达到大小阈值时,会自动分裂
  • 平衡器(Balancer)会在分片间迁移chunk以保持数据块在集群所有分片上实现均匀分布

2.2 查询路由流程

  • 应用连接mongos发起查询
  • mongos检查查询是否包含分片键
  • 包含分片键:定向到特定分片(定向查询)
  • 不包含分片键:广播到所有分片(分散-聚集查询)
  • mongos合并结果并返回给客户端

3. 分片策略

3.1 分片键选择

  • 哈希分片:

    • 对分片键值计算哈希
    • 优点:数据分布均匀
    • 缺点:不支持范围查询
  • 范围分片:

    • 基于分片键的值范围
    • 优点:支持高效范围查询
    • 缺点:可能导致数据分布不均

4. 部署分片集群

架构

  • config server(配置服务器)、shard(分片)均以副本集形式构建,每个服务器上部署三个分片,每个服务器上部署一个mongos(路由器)
    image

4.1 部署config server副本集

修改配置文件

  • 不同节点修改IP即可
cat  <<EOF> /etc/mongod-config.conf
storage:
  dbPath: /apps/mongodb/config-data-27020
#  engine:
#  wiredTiger:
systemLog:
  destination: file
  logAppend: true
  path: /apps/mongodb/config-logs-27020/config.log
net:
  port: 27020
  bindIp: 192.168.40.31
processManagement:
  fork: true
  pidFilePath: /apps/mongodb/config-27020.pid
  timeZoneInfo: /usr/share/zoneinfo
#security:
#operationProfiling:
replication:
  replSetName: configserver
sharding:
  clusterRole: configsvr
EOF

创建目录

mkdir -p /apps/mongodb/config-{data,logs}-27020

启动config server 服务

# 在三台主机上分别启动config server
mongod --config /etc/mongod-config.conf

将config server配置成副本集

  • 连接config server,被连接的节点将成为主节点
mongosh --host mongo01:27020
  • 初始化config server
rs.initiate(
  {
    _id : "configserver",
    members: [
      { _id : 0, host : "mongo01:27020" },
      { _id : 1, host : "mongo02:27020" },
      { _id : 2, host : "mongo03:27020" }
    ]
  }
)

4.2 部署shard副本集

配置hosts文件

cat <<EOF>> /etc/hosts
192.168.40.31 mongo01
192.168.40.32 mongo02
192.168.40.33 mongo03
EOF

修改配置文件

  • shard1的副本集名称是rs1,端口号27017,主节点是mongo01
  • shard2的副本集名称是rs2,端口号27018,主节点是mongo02
  • shard3的副本集名称是rs3,端口号27019,主节点是mongo03
  • shard1、shard2、shard3的bindIp修改为对应主机的IP
shard1主节点的配置文件
cat <<EOF> /etc/mongod-shard1.conf
storage:
  dbPath: /apps/mongodb/shard1-data-27017
#  engine:
#  wiredTiger:
systemLog:
  destination: file
  logAppend: true
  path: /apps/mongodb/shard1-logs-27017/shard1.log
net:
  port: 27017
  bindIp: 192.168.40.31
processManagement:
  fork: true
  pidFilePath: /apps/mongodb/shard1-27017.pid
  timeZoneInfo: /usr/share/zoneinfo
#security:
#operationProfiling:
replication:
  replSetName: rs1
sharding:
  clusterRole: shardsvr
EOF
shard2主节点的配置文件
cat <<EOF> /etc/mongod-shard2.conf
storage:
  dbPath: /apps/mongodb/shard2-data-27018
#  engine:
#  wiredTiger:
systemLog:
  destination: file
  logAppend: true
  path: /apps/mongodb/shard2-logs-27018/shard2.log
net:
  port: 27018
  bindIp: 192.168.40.32
processManagement:
  fork: true
  pidFilePath: /apps/mongodb/shard2-27018.pid
  timeZoneInfo: /usr/share/zoneinfo
#security:
#operationProfiling:
replication:
  replSetName: rs2
sharding:
  clusterRole: shardsvr
EOF
shard3主节点的配置文件
cat <<EOF> /etc/mongod-shard3.conf
storage:
  dbPath: /apps/mongodb/shard3-data-27019
#  engine:
#  wiredTiger:
systemLog:
  destination: file
  logAppend: true
  path: /apps/mongodb/shard3-logs-27019/shard3.log
net:
  port: 27019
  bindIp: 192.168.40.33
processManagement:
  fork: true
  pidFilePath: /apps/mongodb/shard3-27019.pid
  timeZoneInfo: /usr/share/zoneinfo
#security:
#operationProfiling:
replication:
  replSetName: rs3
sharding:
  clusterRole: shardsvr
EOF

创建目录

mkdir -p /apps/mongodb/shard1-{data,logs}-27017   # mongo01
mkdir -p /apps/mongodb/shard2-{data,logs}-27018   # mongo02
mkdir -p /apps/mongodb/shard3-{data,logs}-27019   # mongo03

启动shard服务

# 在三个节点上分别启动shard1、shard2、shard3
mongod --config /etc/mongod-shard1.conf
mongod --config /etc/mongod-shard2.conf
mongod --config /etc/mongod-shard3.conf

配置副本集

  • shard1
mongosh --host mongo01:27017
rs.initiate(
  {
    _id : "rs1",
    members: [
      { _id : 0, host : "mongo01:27017" },
      { _id : 1, host : "mongo02:27017" },
      { _id : 2, host : "mongo03:27017" }
    ]
  }
)
  • shard2
mongosh --host mongo02:27018
rs.initiate(
  {
    _id : "rs2",
    members: [
      { _id : 0, host : "mongo01:27018" },
      { _id : 1, host : "mongo02:27018" },
      { _id : 2, host : "mongo03:27018" }
    ]
  }
)
  • shard3
mongosh --host mongo03:27019
rs.initiate(
  {
    _id : "rs3",
    members: [
      { _id : 0, host : "mongo01:27019" },
      { _id : 1, host : "mongo02:27019" },
      { _id : 2, host : "mongo03:27019" }
    ]
  }
)

4.3 部署mongos路由器

修改配置文件

  • 三台主机分别修改bindIp
cat <<EOF> /etc/mongod-mongos.conf
systemLog:
  destination: file
  logAppend: true
  path: /apps/mongodb/mongos-logs-27021/mongos.log
net:
  port: 27021
  bindIp: 192.168.40.31
processManagement:
  fork: true
  pidFilePath: /apps/mongodb/mongos-27021.pid
  timeZoneInfo: /usr/share/zoneinfo
#security:
#operationProfiling:
sharding:
  configDB: configserver/mongo01:27020,mongo02:27020,mongo03:27020
EOF

创建目录

# 三台主机分别创建目录
mkdir -p /apps/mongodb/mongos-logs-27021

启动mongos

# 三台主机分别启动mongos
mongos --config /etc/mongod-mongos.conf

4.4 向分片集群中添加分片

  • 添加分片只需连接任意一个mongos,只需添加一次,即可同步到mongos集群的其他节点
# 连接到mongos
mongosh --host mongo01:27021

# 添加分片
sh.addShard("rs1/mongo01:27017,mongo02:27017,mongo03:27017")
sh.addShard("rs2/mongo01:27018,mongo02:27018,mongo03:27018")
sh.addShard("rs3/mongo01:27019,mongo02:27019,mongo03:27019")

启用数据库分片

  • 启用分片后,可以在Navicat中连接mongos查看到对应的数据库和集合
// 启用数据库分片
sh.enableSharding("mydatabase")

// 对集合进行分片
sh.shardCollection("mydatabase.mycollection", { "shardKey": 1 })

5. 分片集群管理

5.1 监控集群状态
javascript
// 查看分片状态
sh.status()

// 查看平衡器状态
sh.getBalancerState()

// 查看数据分布
db.mycollection.getShardDistribution()
5.2 添加新分片
javascript
sh.addShard("shardReplSet2/shard2a.example.net:27018,shard2b.example.net:27018,shard2c.example.net:27018")
5.3 平衡器管理
javascript
// 停止平衡器
sh.stopBalancer()

// 启动平衡器
sh.startBalancer()

// 设置平衡窗口
use config
db.settings.update(
{ _id: "balancer" },
{ $set: { activeWindow: { start: "23:00", stop: "6:00" } } },
{ upsert: true }
)
6. 分片集群最佳实践
6.1 分片键选择原则
基数高(大量不同值)

写分布均匀

匹配查询模式

避免单调递增的分片键(如时间戳、自增ID)

6.2 性能优化
为分片键创建索引

监控热点分片

合理设置chunk大小(默认64MB)

使用预分割(pre-splitting)避免初始写入热点

6.3 容量规划
每个分片应保留30%的可用空间

监控磁盘使用情况

提前规划分片扩展

  1. 常见问题与解决方案
    7.1 分片键无法修改
    问题:一旦选择分片键就无法更改

解决方案:

创建新集合并设置新分片键

将数据从旧集合迁移到新集合

更新应用使用新集合

7.2 数据分布不均
问题:某些分片负载过高

解决方案:

重新评估分片键选择

使用哈希分片代替范围分片

手动迁移热点chunk

7.3 跨分片查询性能
问题:无分片键查询性能差

解决方案:

尽可能在查询中包含分片键

为常用查询创建复合索引

考虑使用$or替代分散-聚集查询

启动脚本

cat <<EOF> start-mongo-cluster.sh
#!/bin/bash
mongod --config /etc/mongod-config.conf
sleep 5
mongod --config /etc/mongod-shard1.conf
sleep 5
mongod --config /etc/mongod-shard2.conf
sleep 5
mongod --config /etc/mongod-shard3.conf
sleep 5
mongos --config /etc/mongos.conf
EOF

关闭脚本

cat <<EOF> stop-mongo-cluster.sh
#!/bin/bash
mongo_home=/apps/mongodb

declare -A pid_map
pid_map["mongos"]=$(cat ${mongo_home}/mongos*.pid 2>/dev/null | tr '\n' ' ' | xargs)
pid_map["shard"]=$(cat ${mongo_home}/shard*.pid 2>/dev/null | tr '\n' ' ' | xargs)
pid_map["config"]=$(cat ${mongo_home}/config*.pid 2>/dev/null | tr '\n' ' ' | xargs)

for component in mongos shard config; do
    pid=${pid_map[$component]}
    if [ -z "$pid" ]; then
        continue  # 无PID直接跳过,不输出任何提示
    fi
    echo "正在关闭 $component(PID:$pid)"
    kill -15 $pid >/dev/null 2>&1
    sleep 15
    case $component in
        mongos)
            ps_out=$(ps -ef | grep mongos | grep -v grep | wc -l)
            ;;
        shard)
            ps_out=$(ps -ef | grep mongod | grep shard | grep -v grep | wc -l)
            ;;
        config)
            ps_out=$(ps -ef | grep mongod | grep config | grep -v grep | wc -l)
            ;;
    esac
    if [ $ps_out -eq 0 ]; then
        echo "$component 已成功关闭"
    fi
done
EOF
posted @ 2026-03-27 11:26  立勋  阅读(48)  评论(0)    收藏  举报