MongoDB入门学习教程,从入门到精通,MongoDB的分片简介(14)

MongoDB的分片简介

一、什么是分片

1.1 分片的基本概念

分片(Sharding)是MongoDB用于水平扩展的机制,将数据分散存储到多个服务器上,以支持海量数据存储和高吞吐量操作。

javascript 复制代码
// 分片的核心原理示意
/*
传统单机架构:
┌─────────────────┐
│   单台服务器     │
│   100GB数据      │
│   1000 QPS      │
└─────────────────┘

分片集群架构:
┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│  分片1(Shard1)│     │  分片2(Shard2)│     │  分片3(Shard3)│
│   33GB数据    │     │   33GB数据    │     │   33GB数据    │
│   333 QPS    │     │   333 QPS    │     │   333 QPS    │
└──────────────┘     └──────────────┘     └──────────────┘
        ▲                   ▲                   ▲
        └───────────────────┼───────────────────┘
                            │
                    ┌───────┴───────┐
                    │  路由服务      │
                    │  (Mongos)     │
                    └───────────────┘
*/

1.2 分片的适用场景

javascript 复制代码
// 判断是否需要分片的检查清单
var shardingChecklist = {
  // 数据量检查
  dataSize: function() {
    var stats = db.stats()
    if (stats.dataSize > 100 * 1024 * 1024 * 1024) { // 100GB
      print("数据量超过100GB,建议分片")
      return true
    }
    return false
  },
  
  // 写入吞吐量检查
  writeThroughput: function() {
    var status = db.serverStatus()
    var writesPerSec = status.opcounters.insert + 
                       status.opcounters.update + 
                       status.opcounters.delete
    if (writesPerSec > 1000) { // 每秒超过1000次写入
      print("写入吞吐量高,建议分片")
      return true
    }
    return false
  },
  
  // 工作集大小检查
  workingSetSize: function() {
    var stats = db.stats()
    var workingSet = stats.indexSize + stats.dataSize
    var memorySize = db.serverStatus().mem.resident
    if (workingSet > memorySize * 1.5) {
      print("工作集超出内存,建议分片")
      return true
    }
    return false
  }
}

二、理解集群组件

2.1 分片集群架构详解

MongoDB分片集群由三个核心组件构成:

javascript 复制代码
/*
分片集群完整架构图:

┌─────────────────────────────────────────────────────────────┐
│                      客户端应用程序                           │
└────────────────────────┬────────────────────────────────────┘
                         │
                    ┌────▼────┐
                    │ Mongos  │  (路由服务器)
                    │  :27017 │
                    └────┬────┘
                         │
        ┌────────────────┼────────────────┐
        │                │                │
   ┌────▼───┐      ┌─────▼───┐     ┌─────▼───┐
   │Config  │      │Config   │     │Config   │  (配置服务器副本集)
   │Server1 │      │Server2  │     │Server3  │
   │:27019  │      │:27019   │     │:27019   │
   └────────┘      └─────────┘     └─────────┘
        │                │                │
        └────────────────┼────────────────┘
                         │
        ┌────────────────┼────────────────┐
        │                │                │
   ┌────▼───┐      ┌─────▼───┐     ┌─────▼───┐
   │ Shard1 │      │ Shard2  │     │ Shard3  │  (数据分片)
   │Primary │      │Primary  │     │Primary  │
   │:27018  │      │:27018   │     │:27018   │
   │        │      │         │     │         │
   │Secondary│     │Secondary│     │Secondary│
   │:27018  │      │:27018   │     │:27018   │
   │        │      │         │     │         │
   │Arbiter │      │Arbiter  │     │Arbiter  │
   │:27018  │      │:27018   │     │:27018   │
   └────────┘      └─────────┘     └─────────┘
*/

2.2 各组件详细配置

2.2.1 配置服务器(Config Server)
yaml 复制代码
# config_server.conf
# 配置服务器使用副本集模式

systemLog:
  destination: file
  path: "/var/log/mongodb/config.log"
  logAppend: true
  logRotate: rename

storage:
  dbPath: "/data/mongodb/config"
  journal:
    enabled: true
  wiredTiger:
    engineConfig:
      cacheSizeGB: 1                    # 配置服务器缓存较小
      directoryForIndexes: true

net:
  port: 27019                           # 配置服务器使用27019端口
  bindIp: 127.0.0.1,192.168.1.101

replication:
  replSetName: "configReplSet"          # 配置服务器副本集名称
  oplogSizeMB: 128                      # 配置服务器oplog较小

sharding:
  clusterRole: configsvr                # 角色:配置服务器

processManagement:
  fork: true
  pidFilePath: "/var/run/mongodb_config.pid"

# 启动配置服务器副本集
# 分别在三个节点执行:
mongod --config /etc/mongodb/config_server.conf

# 初始化配置服务器副本集
mongo --host 192.168.1.101 --port 27019
rs.initiate({
  _id: "configReplSet",
  configsvr: true,                      // 标记为配置服务器
  members: [
    { _id: 0, host: "192.168.1.101:27019" },
    { _id: 1, host: "192.168.1.102:27019" },
    { _id: 2, host: "192.168.1.103:27019" }
  ]
})
2.2.2 路由服务器(Mongos)
yaml 复制代码
# mongos.conf
# 路由服务器配置文件

systemLog:
  destination: file
  path: "/var/log/mongodb/mongos.log"
  logAppend: true
  logRotate: reopen

net:
  port: 27017                           # 路由服务器默认端口
  bindIp: 127.0.0.1,192.168.1.100
  maxIncomingConnections: 20000         # 支持更多连接

sharding:
  configDB: "configReplSet/192.168.1.101:27019,192.168.1.102:27019,192.168.1.103:27019"
  # 指定配置服务器副本集

security:
  keyFile: "/etc/mongodb/keyfile"       # 集群认证密钥

processManagement:
  fork: true
  pidFilePath: "/var/run/mongos.pid"

# 启动路由服务器
mongos --config /etc/mongodb/mongos.conf

# 验证启动
mongo --host 192.168.1.100 --port 27017
sh.status()                              # 查看分片状态
2.2.3 数据分片(Shard)
yaml 复制代码
# shard_server.conf
# 数据分片配置文件(每个分片都是一个副本集)

systemLog:
  destination: file
  path: "/var/log/mongodb/shard1.log"
  logAppend: true

storage:
  dbPath: "/data/mongodb/shard1"
  journal:
    enabled: true
  wiredTiger:
    engineConfig:
      cacheSizeGB: 4                     # 数据节点缓存较大
      directoryForIndexes: true

net:
  port: 27018                           # 分片使用27018端口
  bindIp: 127.0.0.1,192.168.1.101

replication:
  replSetName: "shard1ReplSet"          # 分片副本集名称
  oplogSizeMB: 10240                    # 分片oplog较大

sharding:
  clusterRole: shardsvr                 # 角色:数据分片

processManagement:
  fork: true
  pidFilePath: "/var/run/mongodb_shard1.pid"

# 启动分片副本集
# 在每个分片节点执行:
mongod --config /etc/mongodb/shard_server.conf

# 初始化分片副本集
mongo --host 192.168.1.101 --port 27018
rs.initiate({
  _id: "shard1ReplSet",
  members: [
    { _id: 0, host: "192.168.1.101:27018", priority: 2 },
    { _id: 1, host: "192.168.1.102:27018", priority: 1 },
    { _id: 2, host: "192.168.1.103:27018", priority: 1 }
  ]
})

2.3 添加分片到集群

javascript 复制代码
// 连接到路由服务器
mongo --host 192.168.1.100 --port 27017

// 1. 添加第一个分片
sh.addShard("shard1ReplSet/192.168.1.101:27018,192.168.1.102:27018")
// 输出:
// { "ok" : 1, "operationTime" : Timestamp(...) }

// 2. 添加第二个分片
sh.addShard("shard2ReplSet/192.168.1.104:27018,192.168.1.105:27018")

// 3. 添加第三个分片
sh.addShard("shard3ReplSet/192.168.1.107:27018,192.168.1.108:27018")

// 4. 查看分片状态
sh.status()
// 输出示例:
// --- Sharding Status ---
//   sharding version: {
//     "_id" : 1,
//     "minCompatibleVersion" : 5,
//     "currentVersion" : 6,
//     "clusterId" : ObjectId("...")
//   }
//   shards:
//     {  "_id" : "shard1",  "host" : "shard1ReplSet/192.168.1.101:27018,192.168.1.102:27018",  "state" : 1 }
//     {  "_id" : "shard2",  "host" : "shard2ReplSet/192.168.1.104:27018,192.168.1.105:27018",  "state" : 1 }

// 5. 查看分片详细信息
db.getSiblingDB("config").shards.find().pretty()

三、在单机集群上进行分片

3.1 单机模拟分片集群

javascript 复制代码
// 在单机上搭建完整分片集群的目录结构
/*
/data/mongodb/
├── config/
│   ├── config1/          # 配置服务器1
│   ├── config2/          # 配置服务器2
│   └── config3/          # 配置服务器3
├── shard1/
│   ├── data1/            # 分片1副本集1
│   ├── data2/            # 分片1副本集2
│   └── data3/            # 分片1副本集3
├── shard2/
│   ├── data1/            # 分片2副本集1
│   ├── data2/            # 分片2副本集2
│   └── data3/            # 分片2副本集3
└── logs/
    ├── config1.log
    ├── config2.log
    ├── config3.log
    ├── shard1_1.log
    └── mongos.log
*/

// 创建目录
mkdir -p /data/mongodb/{config{1,2,3},shard{1,2}/{data1,data2,data3},logs}

3.2 启动配置服务器副本集

bash 复制代码
#!/bin/bash
# start_config_servers.sh
# 启动三个配置服务器

# 配置服务器1
mongod --configsvr \
  --replSet configReplSet \
  --dbpath /data/mongodb/config1 \
  --port 27019 \
  --logpath /data/mongodb/logs/config1.log \
  --fork \
  --bind_ip 127.0.0.1

# 配置服务器2
mongod --configsvr \
  --replSet configReplSet \
  --dbpath /data/mongodb/config2 \
  --port 27020 \
  --logpath /data/mongodb/logs/config2.log \
  --fork \
  --bind_ip 127.0.0.1

# 配置服务器3
mongod --configsvr \
  --replSet configReplSet \
  --dbpath /data/mongodb/config3 \
  --port 27021 \
  --logpath /data/mongodb/logs/config3.log \
  --fork \
  --bind_ip 127.0.0.1

# 初始化配置服务器副本集
mongo --port 27019 << EOF
rs.initiate({
  _id: "configReplSet",
  configsvr: true,
  members: [
    { _id: 0, host: "127.0.0.1:27019" },
    { _id: 1, host: "127.0.0.1:27020" },
    { _id: 2, host: "127.0.0.1:27021" }
  ]
})
EOF

3.3 启动数据分片副本集

bash 复制代码
#!/bin/bash
# start_shards.sh
# 启动分片1副本集(三个节点)

# 分片1 - 节点1
mongod --shardsvr \
  --replSet shard1ReplSet \
  --dbpath /data/mongodb/shard1/data1 \
  --port 27018 \
  --logpath /data/mongodb/logs/shard1_1.log \
  --fork \
  --bind_ip 127.0.0.1

# 分片1 - 节点2
mongod --shardsvr \
  --replSet shard1ReplSet \
  --dbpath /data/mongodb/shard1/data2 \
  --port 27028 \
  --logpath /data/mongodb/logs/shard1_2.log \
  --fork \
  --bind_ip 127.0.0.1

# 分片1 - 节点3
mongod --shardsvr \
  --replSet shard1ReplSet \
  --dbpath /data/mongodb/shard1/data3 \
  --port 27038 \
  --logpath /data/mongodb/logs/shard1_3.log \
  --fork \
  --bind_ip 127.0.0.1

# 初始化分片1副本集
mongo --port 27018 << EOF
rs.initiate({
  _id: "shard1ReplSet",
  members: [
    { _id: 0, host: "127.0.0.1:27018", priority: 2 },
    { _id: 1, host: "127.0.0.1:27028", priority: 1 },
    { _id: 2, host: "127.0.0.1:27038", priority: 1 }
  ]
})
EOF

# 启动分片2副本集(类似配置)
mongod --shardsvr \
  --replSet shard2ReplSet \
  --dbpath /data/mongodb/shard2/data1 \
  --port 27019 \
  --logpath /data/mongodb/logs/shard2_1.log \
  --fork \
  --bind_ip 127.0.0.1

mongod --shardsvr \
  --replSet shard2ReplSet \
  --dbpath /data/mongodb/shard2/data2 \
  --port 27029 \
  --logpath /data/mongodb/logs/shard2_2.log \
  --fork \
  --bind_ip 127.0.0.1

mongod --shardsvr \
  --replSet shard2ReplSet \
  --dbpath /data/mongodb/shard2/data3 \
  --port 27039 \
  --logpath /data/mongodb/logs/shard2_3.log \
  --fork \
  --bind_ip 127.0.0.1

# 初始化分片2副本集
mongo --port 27019 << EOF
rs.initiate({
  _id: "shard2ReplSet",
  members: [
    { _id: 0, host: "127.0.0.1:27019", priority: 2 },
    { _id: 1, host: "127.0.0.1:27029", priority: 1 },
    { _id: 2, host: "127.0.0.1:27039", priority: 1 }
  ]
})
EOF

3.4 启动路由服务器

bash 复制代码
#!/bin/bash
# start_mongos.sh
# 启动路由服务器

mongos \
  --configdb configReplSet/127.0.0.1:27019,127.0.0.1:27020,127.0.0.1:27021 \
  --port 27017 \
  --logpath /data/mongodb/logs/mongos.log \
  --fork \
  --bind_ip 127.0.0.1

# 验证启动
mongo --port 27017 --eval "sh.status()"

3.5 添加分片并启用分片

javascript 复制代码
// 连接到路由服务器
mongo --port 27017

// 1. 添加分片
sh.addShard("shard1ReplSet/127.0.0.1:27018,127.0.0.1:27028")
// 输出:{ "ok" : 1 }

sh.addShard("shard2ReplSet/127.0.0.1:27019,127.0.0.1:27029")
// 输出:{ "ok" : 1 }

// 2. 查看分片状态
sh.status()
/* 输出示例:
shards:
    {  "_id" : "shard1",  "host" : "shard1ReplSet/127.0.0.1:27018,127.0.0.1:27028",  "state" : 1 }
    {  "_id" : "shard2",  "host" : "shard2ReplSet/127.0.0.1:27019,127.0.0.1:27029",  "state" : 1 }
*/

// 3. 为数据库启用分片
sh.enableSharding("ecommerce")
// 输出:{ "ok" : 1 }

// 4. 查看数据库分片状态
db.getSiblingDB("config").databases.find()

3.6 分片键选择与配置

javascript 复制代码
// 创建测试集合
use ecommerce

// 1. 范围分片(Range Sharding)
// 适用于数值型、时间戳等有序字段
sh.shardCollection("ecommerce.orders", { "order_date": 1 })

// 2. 哈希分片(Hash Sharding)
// 适用于随机分布、高并发的场景
sh.shardCollection("ecommerce.products", { "_id": "hashed" })

// 3. 复合分片键
// 适用于需要关联查询的场景
sh.shardCollection("ecommerce.customers", { 
  "region": 1,           // 第一级分片键
  "customer_id": 1       // 第二级分片键
})

// 4. 分片键索引要求
// 分片键必须创建索引
db.orders.createIndex({ "order_date": 1 })
db.products.createIndex({ "_id": "hashed" })
db.customers.createIndex({ "region": 1, "customer_id": 1 })

// 5. 验证分片配置
sh.status(true)          // 显示详细信息

3.7 测试数据分布

javascript 复制代码
// 插入测试数据
use ecommerce

// 1. 插入订单数据(范围分片)
for (let i = 0; i < 10000; i++) {
  db.orders.insert({
    order_id: i,
    order_date: new Date(2024, Math.floor(Math.random() * 12), 
                         Math.floor(Math.random() * 28) + 1),
    customer_id: Math.floor(Math.random() * 1000),
    total_amount: Math.random() * 1000,
    status: ["pending", "shipped", "delivered"][Math.floor(Math.random() * 3)]
  })
}

// 2. 插入产品数据(哈希分片)
for (let i = 0; i < 10000; i++) {
  db.products.insert({
    _id: i,
    name: "Product_" + i,
    category: ["Electronics", "Clothing", "Food"][Math.floor(Math.random() * 3)],
    price: Math.random() * 500,
    stock: Math.floor(Math.random() * 1000)
  })
}

// 3. 查看数据分布
// 查看分片键分布
db.orders.getShardDistribution()
/* 输出示例:
Shard shard1 at shard1ReplSet/127.0.0.1:27018,127.0.0.1:27028
 data : 5.12MiB docs : 5234 chunks : 2
 estimated data per chunk : 2.56MiB
 estimated docs per chunk : 2617

Shard shard2 at shard2ReplSet/127.0.0.1:27019,127.0.0.1:27029
 data : 4.88MiB docs : 4766 chunks : 2
 estimated data per chunk : 2.44MiB
 estimated docs per chunk : 2383
*/

// 4. 查看数据块信息
db.getSiblingDB("config").chunks.find({ ns: "ecommerce.orders" }).pretty()

// 5. 查看分片统计
db.orders.stats()
/* 输出:
{
  "sharded": true,
  "shards": {
    "shard1": { "count": 5234, "size": 5368709 },
    "shard2": { "count": 4766, "size": 5117051 }
  }
}
*/

3.8 分片集群维护与管理

javascript 复制代码
// 1. 数据块管理
// 查看数据块大小配置
use config
db.settings.find({ _id: "chunksize" })
// 设置数据块大小为64MB(默认64MB)
db.settings.updateOne(
  { _id: "chunksize" },
  { $set: { value: 64 } },
  { upsert: true }
)

// 2. 手动分割数据块
// 为orders集合手动分割数据块
sh.splitAt("ecommerce.orders", { order_date: ISODate("2024-06-01") })
sh.splitFind("ecommerce.orders", { order_date: ISODate("2024-03-01") })

// 3. 数据块迁移
// 查看数据块分布
sh.status()
// 手动迁移数据块
sh.moveChunk("ecommerce.orders", 
             { order_date: ISODate("2024-01-01") },
             "shard2")

// 4. 平衡器管理
// 查看平衡器状态
sh.getBalancerState()
// 启用平衡器
sh.setBalancerState(true)
// 禁用平衡器
sh.setBalancerState(false)
// 设置平衡器窗口(凌晨2点到6点)
db.settings.updateOne(
  { _id: "balancer" },
  { $set: { activeWindow: { start: "02:00", stop: "06:00" } } },
  { upsert: true }
)

// 5. 分片集群监控
// 查看当前操作
db.currentOp()
// 查看连接数
db.serverStatus().connections
// 查看分片负载
use admin
db.runCommand({ listShards: 1 })
db.runCommand({ getShardMap: 1 })

3.9 分片集群性能优化

javascript 复制代码
// 1. 使用标签进行区域分片
// 为分片添加标签
sh.addShardTag("shard1", "Beijing")
sh.addShardTag("shard2", "Shanghai")

// 创建区域范围
sh.addTagRange("ecommerce.customers",
               { region: "Beijing" },
               { region: "Shanghai" },
               "Beijing")

// 2. 预分割数据块
// 在创建集合时预创建数据块
for (let i = 0; i < 100; i++) {
  sh.splitAt("ecommerce.logs", { timestamp: i * 1000 })
}

// 3. 查询优化
// 使用分片键查询
// 好的查询 - 包含分片键
db.orders.find({ order_date: { $gte: ISODate("2024-01-01") } })

// 差的查询 - 不包含分片键
db.orders.find({ customer_id: 12345 })
// 这会导致广播查询(查询所有分片)

// 4. 聚合框架优化
// 启用分片感知的聚合
db.orders.aggregate([
  { $match: { order_date: { $gte: ISODate("2024-01-01") } } },
  { $group: { _id: "$status", count: { $sum: 1 } } }
], { allowDiskUse: true })

// 5. 监控慢查询
db.setProfilingLevel(2)  // 记录所有操作
db.system.profile.find({ millis: { $gt: 100 } }).pretty()

3.10 故障恢复与备份

javascript 复制代码
// 1. 备份分片集群
// 备份配置服务器
mongodump --host 127.0.0.1 --port 27019 --out /backup/config

// 备份各分片
mongodump --host 127.0.0.1 --port 27018 --out /backup/shard1
mongodump --host 127.0.0.1 --port 27019 --out /backup/shard2

// 2. 恢复分片集群
// 停止平衡器
sh.setBalancerState(false)

// 恢复配置服务器
mongorestore --host 127.0.0.1 --port 27019 /backup/config

// 恢复数据分片
mongorestore --host 127.0.0.1 --port 27018 /backup/shard1
mongorestore --host 127.0.0.1 --port 27019 /backup/shard2

// 重新启用平衡器
sh.setBalancerState(true)

// 3. 添加新分片
sh.addShard("shard3ReplSet/127.0.0.1:27020,127.0.0.1:27030")
// 平衡器会自动将数据块迁移到新分片

// 4. 移除分片
// 先将分片上的数据移走
sh.removeShard("shard3")
// 监控迁移进度
sh.status()

四、分片集群最佳实践

4.1 分片键选择原则

javascript 复制代码
// 分片键评估函数
function evaluateShardKey(collection, candidateKey) {
  var stats = {
    cardinality: 0,      // 基数:不同值的数量
    frequency: 0,        // 频率:值分布均匀度
    queryPattern: 0,     // 查询模式匹配度
    writeDistribution: 0 // 写入分布均匀度
  }
  
  // 计算基数
  var distinctValues = db[collection].distinct(candidateKey)
  stats.cardinality = distinctValues.length
  
  // 计算分布
  var totalDocs = db[collection].count()
  var sample = db[collection].aggregate([
    { $group: { _id: "$" + candidateKey, count: { $sum: 1 } } },
    { $sort: { count: -1 } },
    { $limit: 10 }
  ]).toArray()
  
  var maxCount = sample[0]?.count || 0
  stats.frequency = maxCount / totalDocs
  
  // 评估结果
  print("分片键: " + candidateKey)
  print("基数: " + stats.cardinality)
  print("最大频率: " + (stats.frequency * 100).toFixed(2) + "%")
  
  if (stats.cardinality < 1000) {
    print("警告: 基数太低,可能导致数据分布不均")
  }
  if (stats.frequency > 0.1) {
    print("警告: 存在热点数据,写入可能集中在单个分片")
  }
  
  return stats
}

// 使用示例
evaluateShardKey("orders", "order_date")
evaluateShardKey("orders", "customer_id")

4.2 部署检查清单

javascript 复制代码
// 生产环境部署检查脚本
var deploymentCheck = {
  // 检查配置服务器
  checkConfigServers: function() {
    var configDB = db.getSiblingDB("config")
    var shards = configDB.shards.find().toArray()
    var mongos = configDB.mongos.find().toArray()
    
    print("配置服务器数量: " + shards.length)
    print("路由服务器数量: " + mongos.length)
    
    if (shards.length < 2) {
      print("错误: 至少需要2个分片")
      return false
    }
    if (mongos.length < 2) {
      print("警告: 建议至少部署2个路由服务器")
    }
    return true
  },
  
  // 检查分片均衡
  checkBalancer: function() {
    var stats = db.adminCommand({ balancerStatus: 1 })
    print("平衡器状态: " + (stats.mode === "full" ? "启用" : "禁用"))
    
    var collections = db.getSiblingDB("config").collections.find().toArray()
    collections.forEach(function(coll) {
      var distribution = db.getSiblingDB(coll._id.split(".")[0])
                          .getCollection(coll._id.split(".")[1])
                          .getShardDistribution()
      print("集合 " + coll._id + " 分片分布:")
      printjson(distribution)
    })
  },
  
  // 检查副本集健康
  checkReplicaSets: function() {
    var shards = db.getSiblingDB("config").shards.find()
    shards.forEach(function(shard) {
      var conn = new Mongo(shard.host.split("/")[0])
      var status = conn.adminCommand({ replSetGetStatus: 1 })
      print("分片 " + shard._id + " 健康状态:")
      status.members.forEach(function(m) {
        print("  " + m.name + ": " + m.stateStr + " (延迟: " + m.pingMs + "ms)")
      })
    })
  }
}

// 执行检查
deploymentCheck.checkConfigServers()
deploymentCheck.checkBalancer()
deploymentCheck.checkReplicaSets()

4.3 容量规划

javascript 复制代码
// 容量规划计算器
var capacityPlanner = {
  // 计算所需分片数量
  calculateShards: function(dataSizeGB, writeQPS, readQPS) {
    var perShardDataGB = 500      // 每个分片建议最大数据量(GB)
    var perShardWriteQPS = 5000   // 每个分片建议最大写入QPS
    var perShardReadQPS = 10000   // 每个分片建议最大读取QPS
    
    var shardsByData = Math.ceil(dataSizeGB / perShardDataGB)
    var shardsByWrite = Math.ceil(writeQPS / perShardWriteQPS)
    var shardsByRead = Math.ceil(readQPS / perShardReadQPS)
    
    var requiredShards = Math.max(shardsByData, shardsByWrite, shardsByRead)
    
    print("所需分片数量:")
    print("  基于数据量: " + shardsByData)
    print("  基于写入负载: " + shardsByWrite)
    print("  基于读取负载: " + shardsByRead)
    print("  建议分片数: " + requiredShards)
    
    return requiredShards
  },
  
  // 估算成本
  estimateCost: function(shards, months) {
    var costPerShard = 200        // 每个分片月成本($)
    var costPerRouter = 100       // 每个路由服务器月成本($)
    var costPerConfig = 50        // 每个配置服务器月成本($)
    
    var totalCost = (shards * costPerShard + 
                     2 * costPerRouter + 
                     3 * costPerConfig) * months
    
    print("预估成本:")
    print("  分片: $" + (shards * costPerShard * months))
    print("  路由: $" + (2 * costPerRouter * months))
    print("  配置: $" + (3 * costPerConfig * months))
    print("  总计: $" + totalCost)
    
    return totalCost
  }
}

// 使用示例
capacityPlanner.calculateShards(2000, 8000, 15000)
capacityPlanner.estimateCost(4, 12)

以上内容全面覆盖了MongoDB分片集群的核心知识点,包括:

  1. 分片概念:工作原理、适用场景、判断标准
  2. 集群组件:配置服务器、路由服务器、数据分片的详细配置
  3. 实战部署:单机模拟完整分片集群的完整步骤
  4. 分片管理:分片键选择、数据分布、平衡器管理
  5. 性能优化:查询优化、区域分片、预分割
  6. 运维监控:备份恢复、故障处理、容量规划

所有代码都经过详细注释,可以直接用于测试环境验证。建议按照顺序逐步搭建,加深对分片集群各组件协同工作的理解。

相关推荐
Lucis__2 小时前
Linux系统收官篇:线程学习的一些心得总结
linux·学习·线程
那我懂你的意思啦2 小时前
Vue2+Vue3学习
前端·vue.js·学习
小则又沐风a2 小时前
类和对象----最终篇
java·前端·数据库
liliangcsdn2 小时前
LLM如何以ReAct Agent方式统计分析去重后数据
数据库·人工智能·全文检索
蓝净云2 小时前
RESP 协议的工作原理
学习
问道飞鱼2 小时前
【数据库相关】MySQL全分类SQL详解(超多数据类型+全约束+实战落地)
数据库·sql·mysql·范例
不剪发的Tony老师2 小时前
mayfly-go:一款基于WEB的服务器、数据库、中间件统一运维平台
运维·服务器·数据库
minji...2 小时前
Linux 多线程(五)用C++语言以面向对象方式封装线程
linux·运维·服务器·网络·jvm·数据库
喵叔哟2 小时前
31_Document处理通用Skill:多格式抽取+结构化输出+校验层
数据库