阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 分片集群(Sharded Cluster)架构

分片集群(Sharded Cluster)架构

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

分片集群(Sharded Cluster)架构

MongoDB的分片集群是一种水平扩展方案,通过将数据分散到多个服务器上来解决单机存储容量和吞吐量瓶颈。它由三个核心组件构成:分片(Shard)、配置服务器(Config Server)和查询路由(mongos)。

核心组件与工作原理

每个分片包含数据集的一个子集,可以是独立的mongod实例或副本集。配置服务器存储集群的元数据,包括数据分片位置信息。mongos作为查询路由器,将客户端请求路由到正确的分片。

数据分发的关键机制是分片键(Shard Key),例如按用户ID范围分片:

// 启用分片
sh.enableSharding("userdb")

// 创建基于用户ID哈希的分片键
db.adminCommand({
  shardCollection: "userdb.profiles",
  key: { userId: "hashed" }
})

分片策略选择

范围分片(Ranged Sharding)

适合连续值查询的场景,如时间序列数据:

// 按创建时间范围分片
sh.shardCollection("logs.events", { createdAt: 1 })

可能导致"热分片"问题,即新数据集中写入单个分片。

哈希分片(Hashed Sharding)

确保数据均匀分布:

// 使用哈希分片键
sh.shardCollection("userdb.sessions", { sessionId: "hashed" })

但范围查询需要访问所有分片。

复合分片键

结合两者优势:

// 先按地域再按时间分片
sh.shardCollection("sales.orders", { region: 1, orderDate: 1 })

分片集群部署实践

典型生产环境部署示例:

  1. 配置服务器副本集(3节点)
mongod --configsvr --replSet configRS --port 27019
  1. 分片服务器(每个分片3节点副本集)
mongod --shardsvr --replSet shardRS1 --port 27018
  1. 启动mongos路由
mongos --configdb configRS/config1:27019,config2:27019,config3:27019

性能优化技巧

预分割分片区间

预先创建空分片区间避免迁移开销:

// 预先创建10个分片区间
for (let i = 0; i < 10; i++) {
  sh.splitAt("userdb.profiles", { userId: i * 10000 })
}

读写关注设置

分片集群需要更严格的写入确认:

db.products.insert(
  { sku: "xyz123", qty: 250 },
  { writeConcern: { w: "majority", wtimeout: 5000 } }
)

常见问题解决方案

分片键不可变性

错误示例:

// 尝试更新分片键会导致失败
db.orders.update(
  { _id: 123 },
  { $set: { customerId: "newValue" } }  // customerId是分片键
)

解决方案是采用插入新文档+删除旧文档的模式。

跨分片事务

需要4.2+版本支持:

session.startTransaction()
try {
  db.accounts.update({ _id: "A" }, { $inc: { balance: -100 } })
  db.accounts.update({ _id: "B" }, { $inc: { balance: 100 } })
  session.commitTransaction()
} catch (error) {
  session.abortTransaction()
}

监控与维护

关键监控指标:

// 检查分片平衡状态
db.adminCommand({ balancerStatus: 1 })

// 查看数据分布
db.collection.getShardDistribution()

定期运行整理命令:

// 整理分片元数据
db.adminCommand({ flushRouterConfig: 1 })

特殊集合处理

非分片集合

存储在primary shard上:

// 显式指定未分片集合
db.createCollection("system.config", { shardKey: false })

小集合处理

对于配置类小集合,可设置zone避免分散:

sh.addShardTag("shardRS1", "configZone")
sh.addTagRange("config.settings", { _id: MinKey }, { _id: MaxKey }, "configZone")

分片集群的限制

  1. 聚合管道某些阶段受限:
// $lookup在分片集合间有限制
db.orders.aggregate([
  { $lookup: {
    from: "inventory",  // 必须非分片或同分片键
    localField: "item",
    foreignField: "sku",
    as: "inventory_docs"
  }}
])
  1. 唯一索引必须包含分片键:
// 有效唯一索引
db.products.createIndex(
  { productId: 1, category: 1 },  // 包含分片键category
  { unique: true }
)

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

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

前端川

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