分片集群(Sharded Cluster)架构
分片集群(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 })
分片集群部署实践
典型生产环境部署示例:
- 配置服务器副本集(3节点)
mongod --configsvr --replSet configRS --port 27019
- 分片服务器(每个分片3节点副本集)
mongod --shardsvr --replSet shardRS1 --port 27018
- 启动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")
分片集群的限制
- 聚合管道某些阶段受限:
// $lookup在分片集合间有限制
db.orders.aggregate([
{ $lookup: {
from: "inventory", // 必须非分片或同分片键
localField: "item",
foreignField: "sku",
as: "inventory_docs"
}}
])
- 唯一索引必须包含分片键:
// 有效唯一索引
db.products.createIndex(
{ productId: 1, category: 1 }, // 包含分片键category
{ unique: true }
)
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:复制集监控与故障排查