阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 分片集群的扩容与缩容

分片集群的扩容与缩容

作者:陈川 阅读数:10040人阅读 分类: MongoDB

分片集群的扩容与缩容

MongoDB分片集群通过水平扩展解决单机性能瓶颈,但业务量波动时需要动态调整集群规模。分片扩容涉及新分片加入和数据迁移,缩容则需安全移除节点并重新平衡数据分布。

扩容分片集群

添加配置服务器

配置服务器存储集群元数据,建议部署为副本集。扩容时需先扩展配置服务器副本集成员:

// 连接到配置服务器主节点
conf = db.getSiblingDB("admin").getMongo().getDB("admin")
conf.add({_id: 3, host: "cfg3.example.net:27019"})
// 验证副本集状态
conf.rs.status()

加入新分片副本集

  1. 部署新的副本集并初始化
mongod --shardsvr --replSet shardC --dbpath /data/shardC --port 27018
  1. 将副本集加入集群
sh.addShard("shardC/rs1.example.net:27018,rs2.example.net:27018")

触发数据均衡

新分片加入后需手动触发均衡器:

sh.startBalancer()
// 查看迁移任务
use config
db.chunks.find({jumbo: true})  // 检查大块数据

典型数据迁移日志示例:

{"t":"2023-05-17T03:22:15.234+0000","s":"I", "c":"SHARDING","id":22194,
"ctx":"Balancer","msg":"Migration succeeded","attr":{"from":"shardA","to":"shardC"}}

缩容分片集群

数据迁移出目标分片

  1. 首先确保分片不是主分片:
use admin
db.runCommand({removeShard: "shardB"})
// 返回结果包含需要迁移的chunk数量
  1. 监控迁移进度:
mongos> db.adminCommand({balancerStatus: 1})
{
  "mode": "full",
  "inBalancerRound": false,
  "numBalancerRounds": 42,
  "migrations": {
    "shardB": {
      "chunksInProgress": 3,
      "bytesToMigrate": 157286400
    }
  }
}

移除空分片

当分片数据量降为0后完成移除:

// 再次执行移除命令
db.adminCommand({removeShard: "shardB"})
// 返回状态变为"completed"后即可下线节点

特殊场景处理

处理jumbo chunk

当存在超过默认64MB大小的chunk时:

  1. 手动拆分大chunk:
sh.splitAt("db.collection", {_id: ObjectId("5f4d7a9e6c3f2b1a")})
  1. 临时提高chunk大小阈值:
use config
db.settings.update(
  {_id: "chunksize"}, 
  {$set: {value: 128}},
  {upsert: true}
)

维护窗口操作

在业务低峰期执行缩容时,可控制迁移速率:

db.adminCommand({
  configureBalancer: {
    mode: "limited",
    maxParallelMigrations: 1,
    migrationThrottlingMs: 5000
  }
})

监控与验证

关键指标监控

  • 迁移队列积压:sh.getBalancerState()
  • 网络流量:db.serverStatus().network
  • 磁盘空间变化:db.stats(1024*1024) // MB单位

数据一致性检查

迁移完成后执行:

// 比对不同分片文档数
db.collection.getShardDistribution()

// 使用hash校验
function compareShards() {
  let mapFunc = function() { emit(this._id, hash(this)); };
  let reduceFunc = function(k, v) { return v[0]; };
  db.collection.mapReduce(mapFunc, reduceFunc, {out: "hashes"});
}

自动化运维实践

使用Ansible模板扩容

- name: Add new shard
  mongodb_shard:
    login_host: mongos1
    login_user: admin
    login_password: "{{vault_password}}"
    replica_set: shardD
    members:
      - host: shardD1:27018
        priority: 1
      - host: shardD2:27018 
        priority: 0.5
    shardsvr: yes

通过API动态调整

调用MongoDB管理API实现自动扩缩容:

async function resizeCluster(targetShard) {
  const status = await sh.status();
  if (status.shards.length > currentNeed) {
    await sh.drainShard(targetShard);
    await updateDNSRecord(targetShard, 'REMOVE');
  } else {
    await spinUpEC2Instance('shard-template');
    await sh.addShard(newShardURI);
  }
}

性能优化要点

  1. 预分裂集合:在插入数据前预先创建空chunk
for (let i=0; i<100; i++) {
  sh.splitFind("db.orders", {order_id: i*10000})
}
  1. 标签感知分片:按机房位置打标签
sh.addTagRange("db.orders", {_id: MinKey}, {_id: MaxKey}, "EU-West")
sh.addShardTag("shardC", "EU-West")
  1. 索引同步策略:确保所有分片建立相同索引
db.getSiblingDB("db").getCollectionNames().forEach(coll => {
  db.getSiblingDB("config").collections.findOne({_id: `db.${coll}`}).indexes.forEach(idx => {
    db.getSiblingDB("db").getCollection(coll).createIndex(idx.key, idx.options)
  })
})

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌