MongoDB入门学习教程,从入门到精通,MongoDB分片配置完全指南(15)

MongoDB分片配置完全指南

目录

  1. 何时分片
  2. 启动服务器
  3. MongoDB如何追踪集群数据
  4. 均衡器
  5. 排序规则
  6. 变更流

何时分片

知识点详解

1.1 分片决策标准
javascript 复制代码
// ==========================================
// 分片决策检查清单
// ==========================================

// 1. 数据量评估 - 当集合超过3TB或索引工作集超过内存时考虑分片
// 2. 写入压力 - 当前写入量超过单个节点处理能力(>1000 writes/sec)
// 3. 读取压力 - 查询延迟超过可接受范围(如 >100ms)
// 4. 硬件限制 - 单个服务器的磁盘、内存、CPU达到瓶颈

// 示例:监控当前数据库状态
db.serverStatus().storageEngine
db.stats()  // 查看数据库统计信息

// 检查集合大小
db.collection.stats().size
db.collection.stats().avgObjSize

// 检查索引使用情况
db.collection.aggregate([
  { $indexStats: {} }
])
1.2 分片键选择原则
javascript 复制代码
// ==========================================
// 分片键选择的三种模式
// ==========================================

// 模式1:哈希分片键(适合均匀分布写入)
sh.shardCollection("mydb.orders", { order_id: "hashed" })

// 模式2:范围分片键(适合范围查询)
sh.shardCollection("mydb.products", { category: 1, price: 1 })

// 模式3:区域分片键(适合地理分布)
sh.shardCollection("mydb.users", { region: 1, user_id: 1 })

// 实际案例:电商系统分片设计
// 订单表 - 使用哈希分片保证写入均匀
sh.shardCollection("ecommerce.orders", { _id: "hashed" })

// 用户表 - 使用区域分片实现数据本地化
sh.addShardToZone("shard01", "asia")
sh.addShardToZone("shard02", "europe")
sh.updateZoneKeyRange("ecommerce.users", 
  { region: "asia" }, { region: "asia\xff" }, "asia")

启动服务器

2.1 配置服务器启动

bash 复制代码
# ==========================================
# 步骤1:启动配置服务器(Config Server)
# ==========================================

# 配置文件:config-server.conf
# ==========================================
systemLog:
  destination: file
  path: /var/log/mongodb/config-server.log
  logAppend: true
storage:
  dbPath: /data/configdb
  journal:
    enabled: true
processManagement:
  fork: true
  pidFilePath: /var/run/mongodb/config-server.pid
net:
  bindIp: localhost,192.168.1.100
  port: 27019
replication:
  replSetName: configReplSet
sharding:
  clusterRole: configsvr
# ==========================================

# 启动配置服务器
mongod --config /etc/mongod/config-server.conf

# 初始化配置副本集
mongo --port 27019
rs.initiate({
  _id: "configReplSet",
  configsvr: true,
  members: [
    { _id: 0, host: "config1.example.com:27019" },
    { _id: 1, host: "config2.example.com:27019" },
    { _id: 2, host: "config3.example.com:27019" }
  ]
})

2.2 分片服务器启动

bash 复制代码
# ==========================================
# 步骤2:启动分片服务器(Shard Server)
# ==========================================

# 分片1配置文件:shard1.conf
# ==========================================
systemLog:
  destination: file
  path: /var/log/mongodb/shard1.log
storage:
  dbPath: /data/shard1
  journal:
    enabled: true
processManagement:
  fork: true
  pidFilePath: /var/run/mongodb/shard1.pid
net:
  bindIp: localhost,192.168.1.101
  port: 27018
replication:
  replSetName: shard1ReplSet
sharding:
  clusterRole: shardsvr
# ==========================================

# 启动分片服务器
mongod --config /etc/mongod/shard1.conf

# 初始化分片副本集
mongo --port 27018
rs.initiate({
  _id: "shard1ReplSet",
  members: [
    { _id: 0, host: "shard1a.example.com:27018", priority: 2 },
    { _id: 1, host: "shard1b.example.com:27018", priority: 1 },
    { _id: 2, host: "shard1c.example.com:27018", priority: 1, arbiterOnly: true }
  ]
})

2.3 路由服务器启动

bash 复制代码
# ==========================================
# 步骤3:启动路由服务器(Mongos)
# ==========================================

# mongos配置文件:mongos.conf
# ==========================================
systemLog:
  destination: file
  path: /var/log/mongodb/mongos.log
  logAppend: true
processManagement:
  fork: true
  pidFilePath: /var/run/mongodb/mongos.pid
net:
  bindIp: localhost,192.168.1.100
  port: 27017
sharding:
  configDB: configReplSet/config1.example.com:27019,config2.example.com:27019,config3.example.com:27019
# ==========================================

# 启动mongos
mongos --config /etc/mongod/mongos.conf

2.4 添加分片到集群

javascript 复制代码
// ==========================================
// 连接到mongos并添加分片
// ==========================================

mongo --host mongos.example.com --port 27017

// 添加分片到集群
sh.addShard("shard1ReplSet/shard1a.example.com:27018,shard1b.example.com:27018")
sh.addShard("shard2ReplSet/shard2a.example.com:27018,shard2b.example.com:27018")

// 查看分片状态
sh.status()

// 启用数据库分片
sh.enableSharding("ecommerce")

// 为集合设置分片键
sh.shardCollection("ecommerce.orders", { order_date: 1, _id: 1 })

MongoDB如何追踪集群数据

3.1 元数据存储结构

javascript 复制代码
// ==========================================
// 配置服务器中的核心集合
// ==========================================

// 连接到配置服务器
mongo --port 27019

// 1. config.shards - 存储所有分片信息
use config
db.shards.find().pretty()
// 输出示例:
{
  "_id": "shard1ReplSet",
  "host": "shard1ReplSet/shard1a:27018,shard1b:27018",
  "state": 1,
  "tags": ["asia"]
}

// 2. config.databases - 存储数据库分片信息
db.databases.find().pretty()
// 输出示例:
{
  "_id": "ecommerce",
  "primary": "shard1ReplSet",
  "partitioned": true
}

// 3. config.collections - 存储集合分片信息
db.collections.find().pretty()
// 输出示例:
{
  "_id": "ecommerce.orders",
  "lastmodEpoch": ObjectId("..."),
  "lastmod": ISODate("..."),
  "dropped": false,
  "key": { "order_date": 1, "_id": 1 },
  "unique": false
}

// 4. config.chunks - 存储块分布信息(核心表)
db.chunks.findOne()
// 输出示例:
{
  "_id": "ecommerce.orders-order_date_1_id_1_MinKey",
  "ns": "ecommerce.orders",
  "min": { "order_date": { "$minKey": 1 }, "_id": { "$minKey": 1 } },
  "max": { "order_date": ISODate("2023-01-01"), "_id": { "$maxKey": 1 } },
  "shard": "shard1ReplSet",
  "lastmod": Timestamp(4, 0),
  "history": [
    { "validAfter": Timestamp(3, 0), "shard": "shard2ReplSet" }
  ]
}

3.2 块分割与迁移机制

javascript 复制代码
// ==========================================
// 手动管理块(Chunk)
// ==========================================

// 查看当前块分布
use config
db.chunks.aggregate([
  { $match: { ns: "ecommerce.orders" } },
  { $group: { _id: "$shard", count: { $sum: 1 } } }
])

// 手动分割块(当块大小接近64MB时)
sh.splitAt("ecommerce.orders", { order_date: ISODate("2023-06-01"), _id: MinKey })

// 手动迁移块
sh.moveChunk("ecommerce.orders", 
  { order_date: ISODate("2023-01-01"), _id: MinKey },
  "shard2ReplSet")

// 查看块大小
db.runCommand({ dataSize: "ecommerce.orders", 
  keyPattern: { order_date: 1, _id: 1 },
  min: { order_date: ISODate("2023-01-01"), _id: MinKey },
  max: { order_date: ISODate("2023-02-01"), _id: MaxKey }
})

3.3 路由表缓存机制

javascript 复制代码
// ==========================================
// Mongos路由缓存管理
// ==========================================

// 查看mongos路由缓存
mongo --port 27017
use admin

// 刷新路由缓存
db.adminCommand({ flushRouterConfig: "ecommerce.orders" })

// 查看缓存统计
db.collection.getShardDistribution()

// 查看查询计划中的分片信息
db.orders.find({ order_date: { $gte: ISODate("2023-01-01") } })
  .explain("executionStats")

// 监控路由缓存命中率
db.serverStatus().shardingStatistics

均衡器

4.1 均衡器配置与管理

javascript 复制代码
// ==========================================
// 均衡器基础配置
// ==========================================

// 连接到mongos
mongo --port 27017

// 1. 查看均衡器状态
sh.getBalancerState()
sh.isBalancerRunning()

// 2. 开启/关闭均衡器
sh.setBalancerState(true)   // 开启
sh.setBalancerState(false)  // 关闭

// 3. 设置均衡器窗口(仅在凌晨2-6点运行)
db.settings.update(
  { _id: "balancer" },
  { $set: { activeWindow: { start: "02:00", stop: "06:00" } } },
  { upsert: true }
)

// 4. 设置块大小(默认64MB,范围1-1024MB)
use config
db.settings.save({ _id: "chunksize", value: 128 })

// 5. 禁用特定集合的均衡
sh.disableBalancing("ecommerce.orders")
sh.enableBalancing("ecommerce.orders")

4.2 均衡策略与算法

javascript 复制代码
// ==========================================
// 均衡器工作流程控制
// ==========================================

// 1. 手动触发均衡检查
sh.balancerCollectionStatus("ecommerce.orders")

// 2. 设置差异阈值(分片间块数差异)
db.settings.update(
  { _id: "balancer" },
  { $set: { 
    migrationThresholds: {
      "ecommerce.orders": 8,  // 差异超过8个块才迁移
      "ecommerce.users": 4
    }
  }},
  { upsert: true }
)

// 3. 设置迁移并发数
use admin
db.adminCommand({ setParameter: 1, 
  "migrationLockAcquisitionMaxWaitMS": 30000,
  "chunkMigrationConcurrency": 2 
})

// 4. 查看迁移历史
use config
db.changelog.find({ what: "moveChunk.commit" })
  .sort({ time: -1 })
  .limit(10)
  .pretty()

4.3 手动控制数据分布

javascript 复制代码
// ==========================================
// 区域(Zone)配置实现数据本地化
// ==========================================

// 1. 添加区域标签
sh.addShardToZone("shard1ReplSet", "north_america")
sh.addShardToZone("shard2ReplSet", "europe")
sh.addShardToZone("shard3ReplSet", "asia_pacific")

// 2. 定义区域范围
// 北美用户(user_id: 1-1000000)
sh.updateZoneKeyRange("ecommerce.users",
  { region: "north_america", user_id: 1 },
  { region: "north_america", user_id: 1000000 },
  "north_america")

// 欧洲用户(user_id: 1000001-2000000)
sh.updateZoneKeyRange("ecommerce.users",
  { region: "europe", user_id: 1000001 },
  { region: "europe", user_id: 2000000 },
  "europe")

// 3. 删除区域范围
sh.removeRangeFromZone("ecommerce.users",
  { region: "north_america", user_id: 1 },
  { region: "north_america", user_id: 1000000 })

// 4. 查看区域配置
sh.status({ verbose: true })

排序规则

5.1 排序规则基础语法

javascript 复制代码
// ==========================================
// 排序规则(Collation)配置
// ==========================================

// 1. 创建带排序规则的集合
db.createCollection("users", {
  collation: {
    locale: "zh",           // 中文区域
    strength: 1,            // 忽略大小写和变音符号
    caseLevel: false,
    caseFirst: "off",
    numericOrdering: true,  // 数字字符串按数值排序
    alternate: "non-ignorable",
    maxVariable: "punct",
    normalization: false,
    backwards: false,
    version: "57.1"
  }
})

// 2. 常用排序规则示例
// 大小写不敏感查询
db.users.find({ name: "john" })
  .collation({ locale: "en", strength: 1 })

// 音调符号不敏感(é = e)
db.users.find({ city: "José" })
  .collation({ locale: "es", strength: 1 })

// 数字字符串排序
db.products.find()
  .sort({ version: 1 })
  .collation({ locale: "en", numericOrdering: true })

5.2 分片集合中的排序规则

javascript 复制代码
// ==========================================
// 分片集合的排序规则要求
// ==========================================

// 重要:分片键字段不能使用带排序规则的索引

// 错误示例(会报错)
// sh.shardCollection("app.logs", { message: 1 })  // message有排序规则

// 正确做法1:分片键字段使用简单二进制排序
db.createCollection("logs", { collation: { locale: "simple" } })
sh.shardCollection("app.logs", { timestamp: 1, level: 1 })

// 正确做法2:分片键使用默认排序规则
sh.shardCollection("app.documents", { _id: "hashed" })

// 在分片集合上使用不同排序规则的查询
db.orders.find({ 
  product_name: { $regex: "^iphone", $options: "i" }
}).collation({ locale: "en", strength: 2 })

// 聚合框架中的排序规则
db.orders.aggregate([
  { $match: { status: "completed" } },
  { $group: { _id: "$customer_name", total: { $sum: "$amount" } } },
  { $sort: { _id: 1 } }
], { collation: { locale: "zh", strength: 1 } })

5.3 排序规则参数详解

javascript 复制代码
// ==========================================
// 排序规则参数完整示例
// ==========================================

// 创建多个测试文档
db.test.insertMany([
  { name: "apple", code: "100" },
  { name: "Apple", code: "20" },
  { name: "APPLE", code: "3" },
  { name: "café", code: "200" },
  { name: "cafe", code: "30" }
])

// 不同strength值的对比
// strength: 1 - 忽略大小写和变音符号
db.test.find().sort({ name: 1 })
  .collation({ locale: "en", strength: 1 })
// 结果:apple, Apple, APPLE, cafe, café

// strength: 2 - 区分变音符号,忽略大小写
db.test.find().sort({ name: 1 })
  .collation({ locale: "en", strength: 2 })
// 结果:apple, Apple, APPLE, cafe, café

// strength: 3 - 区分大小写和变音符号
db.test.find().sort({ name: 1 })
  .collation({ locale: "en", strength: 3 })
// 结果:APPLE, Apple, apple, cafe, café

// numericOrdering: true - 数字字符串排序
db.test.find().sort({ code: 1 })
  .collation({ locale: "en", numericOrdering: true })
// 结果:3, 20, 30, 100, 200

// caseFirst: "upper" - 大写字母优先
db.test.find().sort({ name: 1 })
  .collation({ locale: "en", caseFirst: "upper" })
// 结果:APPLE, Apple, apple

变更流

6.1 变更流基础使用

javascript 复制代码
// ==========================================
// 变更流(Change Streams)配置与使用
// ==========================================

// 1. 在分片集群上开启变更流
// 注意:需要副本集配置,且所有节点使用WiredTiger存储引擎

// 2. 监听整个数据库的变更
const pipeline = [
  { $match: { 
    operationType: { $in: ["insert", "update", "delete"] },
    "fullDocument.status": "active"
  }}
]

const changeStream = db.collection("orders").watch(pipeline)

// 3. 处理变更事件
changeStream.on("change", (change) => {
  console.log("检测到变更:", change.operationType)
  
  switch(change.operationType) {
    case "insert":
      console.log("新增文档:", change.fullDocument)
      // 触发后续处理逻辑
      processNewOrder(change.fullDocument)
      break
      
    case "update":
      console.log("更新文档:", change.documentKey)
      console.log("更新字段:", change.updateDescription)
      syncToCache(change.documentKey)
      break
      
    case "delete":
      console.log("删除文档:", change.documentKey)
      cleanupRelatedData(change.documentKey)
      break
      
    case "replace":
      console.log("替换文档:", change.fullDocument)
      break
  }
})

6.2 变更流高级配置

javascript 复制代码
// ==========================================
// 变更流高级特性
// ==========================================

// 1. 指定开始时间(从特定时间点开始监听)
const resumeToken = db.getCollection("orders")
  .find()
  .sort({ $natural: -1 })
  .limit(1)
  .next()
  ._id

const changeStream2 = db.collection("orders").watch([], {
  resumeAfter: resumeToken,
  startAtOperationTime: Timestamp(1672531200, 1)
})

// 2. 过滤特定字段的变更
const pipeline2 = [
  { $match: { 
    "updateDescription.updatedFields.price": { $exists: true },
    operationType: "update"
  }},
  { $project: {
    order_id: "$documentKey._id",
    new_price: "$updateDescription.updatedFields.price",
    old_price: "$updateDescription.removedFields"
  }}
]

const changeStream3 = db.collection("orders").watch(pipeline2)

// 3. 使用完整文档查找(需要fullDocument选项)
const changeStream4 = db.collection("orders").watch([], {
  fullDocument: "updateLookup"  // 获取更新后的完整文档
})

changeStream4.on("change", (change) => {
  if (change.operationType === "update") {
    // 获取更新后的完整文档
    console.log("更新后的完整文档:", change.fullDocument)
  }
})

6.3 分片集群中的变更流

javascript 复制代码
// ==========================================
// 分片环境下的变更流最佳实践
// ==========================================

// 1. 监听分片集合的变更(需要指定完整的分片键)
const pipeline3 = [
  { $match: { 
    operationType: "insert",
    "fullDocument.region": "asia"
  }}
]

// 分片键必须在过滤条件中以提高性能
const changeStream5 = db.collection("users").watch(pipeline3)

// 2. 跨多个分片的全局变更流
const allCollections = ["orders", "users", "products"]
const changeStreams = []

allCollections.forEach(col => {
  const stream = db.collection(col).watch()
  stream.on("change", (change) => {
    console.log(`${col} 发生变更:`, change.operationType)
    handleChange(col, change)
  })
  changeStreams.push(stream)
})

// 3. 实现变更数据的可靠消费
class ChangeStreamConsumer {
  constructor(collection, handler) {
    this.collection = collection
    this.handler = handler
    this.resumeToken = null
    this.stream = null
  }
  
  async start() {
    const options = this.resumeToken ? { resumeAfter: this.resumeToken } : {}
    this.stream = this.collection.watch([], options)
    
    this.stream.on("change", async (change) => {
      try {
        // 保存当前token用于故障恢复
        this.resumeToken = change._id
        
        // 处理业务逻辑
        await this.handler(change)
        
        // 确认处理完成(可以记录到数据库)
        await this.saveProgress(change._id)
      } catch (error) {
        console.error("处理变更失败:", error)
        // 实现重试逻辑
        await this.retryHandler(change)
      }
    })
    
    this.stream.on("error", (error) => {
      console.error("变更流错误:", error)
      this.restart()
    })
  }
  
  async saveProgress(token) {
    await db.checkpoints.updateOne(
      { consumer: "order_processor" },
      { $set: { resumeToken: token, lastUpdate: new Date() } },
      { upsert: true }
    )
  }
  
  restart() {
    console.log("重新启动变更流...")
    setTimeout(() => this.start(), 5000)
  }
}

// 使用示例
const consumer = new ChangeStreamConsumer(
  db.collection("orders"),
  async (change) => {
    if (change.operationType === "insert") {
      await processNewOrder(change.fullDocument)
    }
  }
)

consumer.start()

6.4 变更流与聚合框架集成

javascript 复制代码
// ==========================================
// 变更流与聚合管道高级应用
// ==========================================

// 1. 使用$match过滤操作类型和文档内容
const pipeline4 = [
  { $match: { 
    $or: [
      { operationType: "insert", "fullDocument.amount": { $gte: 1000 } },
      { operationType: "update", "updateDescription.updatedFields.amount": { $gte: 1000 } }
    ]
  }},
  { $addFields: {
    alertLevel: { 
      $cond: [{ $gt: ["$fullDocument.amount", 10000] }, "critical", "warning"]
    }
  }}
]

const highValueStream = db.collection("transactions").watch(pipeline4)

// 2. 聚合变更数据进行实时分析
const pipeline5 = [
  { $match: { operationType: "insert" } },
  { $group: {
    _id: { $dateToString: { format: "%Y-%m-%d", date: "$fullDocument.created_at" } },
    count: { $sum: 1 },
    totalAmount: { $sum: "$fullDocument.amount" }
  }},
  { $sort: { _id: -1 } }
]

// 注意:变更流不支持$group,需要在应用层实现
const stats = { daily: {} }
const realtimeStream = db.collection("sales").watch()

realtimeStream.on("change", (change) => {
  if (change.operationType === "insert") {
    const date = change.fullDocument.created_at.toISOString().split('T')[0]
    if (!stats.daily[date]) {
      stats.daily[date] = { count: 0, total: 0 }
    }
    stats.daily[date].count++
    stats.daily[date].total += change.fullDocument.amount
    
    console.log(`实时统计 - ${date}: ${stats.daily[date].count}笔, 总计: ${stats.daily[date].total}`)
  }
})

// 3. 实现多阶段变更处理
const processingPipeline = [
  { $match: { operationType: "insert" } },
  { $addFields: { 
    processingTime: "$$NOW",
    priority: {
      $switch: {
        branches: [
          { case: { $gte: ["$fullDocument.amount", 10000] }, then: "high" },
          { case: { $gte: ["$fullDocument.amount", 5000] }, then: "medium" }
        ],
        default: "low"
      }
    }
  }}
]

const processor = db.collection("orders").watch(processingPipeline)

processor.on("change", async (change) => {
  const order = change.fullDocument
  const priority = change.priority
  
  // 根据优先级分发到不同的处理队列
  await dispatchToQueue(order, priority)
})

完整实战案例

电商平台分片架构实现

javascript 复制代码
// ==========================================
// 电商平台完整分片配置案例
// ==========================================

// 1. 初始化分片集群
// 连接到mongos
mongo --host mongos.prod.com --port 27017

// 2. 添加分片
sh.addShard("shard01/shard01-1:27018,shard01-2:27018")
sh.addShard("shard02/shard02-1:27018,shard02-2:27018")
sh.addShard("shard03/shard03-1:27018,shard03-2:27018")

// 3. 配置区域
sh.addShardToZone("shard01", "asia")
sh.addShardToZone("shard02", "europe")
sh.addShardToZone("shard03", "america")

// 4. 启用分片并配置集合
sh.enableSharding("ecommerce")

// 订单表 - 哈希分片保证写入均衡
sh.shardCollection("ecommerce.orders", { order_id: "hashed" })

// 用户表 - 区域分片实现数据本地化
sh.shardCollection("ecommerce.users", { region: 1, user_id: 1 })
sh.updateZoneKeyRange("ecommerce.users",
  { region: "asia", user_id: MinKey },
  { region: "asia", user_id: MaxKey },
  "asia")
sh.updateZoneKeyRange("ecommerce.users",
  { region: "europe", user_id: MinKey },
  { region: "europe", user_id: MaxKey },
  "europe")
sh.updateZoneKeyRange("ecommerce.users",
  { region: "america", user_id: MinKey },
  { region: "america", user_id: MaxKey },
  "america")

// 5. 创建索引支持分片键
db.orders.createIndex({ order_id: "hashed" })
db.users.createIndex({ region: 1, user_id: 1 })

// 6. 配置均衡器窗口(业务低峰期)
use config
db.settings.update(
  { _id: "balancer" },
  { $set: { activeWindow: { start: "02:00", stop: "06:00" } } },
  { upsert: true }
)

// 7. 设置变更流监控
const monitorStream = db.orders.watch([
  { $match: { operationType: "insert" } }
])

monitorStream.on("change", (change) => {
  console.log(`新订单: ${change.fullDocument.order_id}, 金额: ${change.fullDocument.amount}`)
  // 触发库存更新、消息通知等后续处理
})

// 8. 验证分片配置
sh.status()

// 9. 测试数据分布
for(let i = 1; i <= 10000; i++) {
  db.orders.insert({
    order_id: i,
    user_id: Math.floor(Math.random() * 1000000),
    amount: Math.random() * 5000,
    region: ["asia", "europe", "america"][Math.floor(Math.random() * 3)],
    created_at: new Date()
  })
}

// 10. 查看数据分布情况
db.orders.getShardDistribution()

故障恢复与监控

javascript 复制代码
// ==========================================
// 分片集群监控与故障处理
// ==========================================

// 1. 监控分片状态
function checkClusterHealth() {
  const shards = db.adminCommand({ listShards: 1 }).shards
  let unhealthy = []
  
  shards.forEach(shard => {
    const status = rs.status()
    if (!status.ok) {
      unhealthy.push(shard._id)
    }
  })
  
  return { healthy: unhealthy.length === 0, unhealthyShards: unhealthy }
}

// 2. 自动故障处理脚本
async function handleShardFailure(shardId) {
  console.log(`处理分片故障: ${shardId}`)
  
  // 检查是否有可用副本
  const backupShard = await findAvailableShard()
  
  // 重新分配块
  const chunks = db.config.chunks.find({ shard: shardId })
  for await (const chunk of chunks) {
    await sh.moveChunk(chunk.ns, chunk.min, backupShard)
  }
  
  // 移除故障分片
  await sh.removeShard(shardId)
  
  console.log(`分片 ${shardId} 已成功迁移到 ${backupShard}`)
}

// 3. 定期执行均衡检查
setInterval(async () => {
  const stats = db.orders.getShardDistribution()
  const chunks = stats.shards.map(s => s.chunks)
  const maxChunks = Math.max(...chunks)
  const minChunks = Math.min(...chunks)
  
  if (maxChunks - minChunks > 10) {
    console.log("分片分布不均,触发手动均衡")
    sh.balancerCollectionStatus("ecommerce.orders")
  }
}, 3600000)  // 每小时检查一次

总结与最佳实践

关键知识点回顾

  1. 分片决策:数据量>3TB或写入>1000 ops/s时考虑分片
  2. 分片键选择:高基数、低频率、单调不增或哈希分片
  3. 元数据管理:配置服务器存储所有路由信息,必须部署为副本集
  4. 均衡器:默认开启,设置时间窗口避免影响业务
  5. 排序规则:分片键不能使用带排序规则的索引
  6. 变更流:需要副本集配置,支持故障恢复

性能优化建议

javascript 复制代码
// 预分割块以避免初始热点
for (let i = 0; i < 100; i++) {
  sh.splitAt("ecommerce.orders", { order_id: i * 10000 })
}

// 使用合适的块大小
db.settings.save({ _id: "chunksize", value: 128 })  // 128MB

// 批量写入时使用ordered:false提高性能
db.orders.bulkWrite(operations, { ordered: false })

以上是MongoDB分片配置的完整知识点和实战代码,涵盖了从基础概念到高级应用的各个方面。

相关推荐
y = xⁿ2 小时前
【MySQL】数据库的脏读,不可重复读和幻读,覆盖索引是什么,索引类型有哪些
数据库·mysql
小冷coding2 小时前
【面试】结合项目整理的场景面试题,覆盖 Java 基础、锁、多线程、数据库、分布式锁 / 事务、消息中间件等核心维度
java·数据库·面试
kcuwu.3 小时前
Python 正则表达式从入门到实战
数据库·python·正则表达式
卓怡学长3 小时前
m319个人网站的设计与实现
java·数据库·spring·tomcat·maven·intellij-idea
Dyanic3 小时前
AMSFusion:一种基于注意力机制的自适应多尺度红外与可见光图像融合网络
图像处理·人工智能·学习
羊小蜜.3 小时前
Mysql 07: 正则表达式查询(REGEXP)全解
数据库·mysql·正则表达式
Dxy12393102163 小时前
正则表达式如何匹配提取文章日期
数据库·mysql·正则表达式
少许极端3 小时前
算法奇妙屋(四十三)-贪心算法学习之路10
学习·算法·贪心算法
小陈工3 小时前
Python Web开发入门(十六):前后端分离架构设计——从“各自为政”到“高效协同”
开发语言·前端·数据库·人工智能·python