外观
MongoDB 分片集群高可用性
分片集群架构设计
核心组件设计
配置服务器(Config Servers)
- 推荐配置:3 个成员的复制集
- 存储分片集群的元数据
- 确保配置数据的一致性和高可用性
分片(Shards)
- 每个分片都是一个复制集
- 推荐配置:3 个或 5 个成员的复制集
- 处理实际的数据读写操作
查询路由器(mongos)
- 部署多个 mongos 实例
- 客户端连接到 mongos 而非直接连接到分片
- 路由查询到正确的分片
高可用架构示例
[客户端应用]
↓
[负载均衡器]
↓
[mongos 1] [mongos 2] [mongos 3]
↓ ↓ ↓
[配置服务器复制集(3 个成员)]
↓
[分片 1 复制集(3 个成员)] [分片 2 复制集(3 个成员)] [分片 3 复制集(3 个成员)]配置服务器高可用性
配置服务器复制集部署
初始化配置服务器复制集
bash# 启动配置服务器节点 mongod --configsvr --replSet csrs --dbpath /data/configdb1 --port 27019 --fork --logpath /var/log/mongodb/configdb1.log mongod --configsvr --replSet csrs --dbpath /data/configdb2 --port 27020 --fork --logpath /var/log/mongodb/configdb2.log mongod --configsvr --replSet csrs --dbpath /data/configdb3 --port 27021 --fork --logpath /var/log/mongodb/configdb3.log # 初始化复制集 mongo --port 27019 --eval " rs.initiate({ _id: 'csrs', configsvr: true, members: [ { _id: 0, host: 'config1:27019' }, { _id: 1, host: 'config2:27020' }, { _id: 2, host: 'config3:27021' } ] }) "配置服务器监控
javascript// 检查配置服务器状态 use config db.serverStatus() // 检查复制集状态 rs.status() // 检查配置数据完整性 db.chunks.count() db.collections.count() db.databases.count()
配置服务器故障处理
单个配置服务器故障
- 复制集自动处理,其他成员继续提供服务
- 无需手动干预,只需监控故障成员的恢复
多个配置服务器故障
- 若多数成员故障,配置服务器复制集将不可用
- 此时 mongos 无法获取或更新元数据
- 建议:javascript
// 检查复制集状态 rs.status() // 恢复故障成员 // 1. 修复硬件或网络问题 // 2. 重启 mongod 实例 // 3. 等待复制集自动恢复
分片高可用性
分片复制集配置
初始化分片复制集
bash# 启动分片 1 节点 mongod --shardsvr --replSet shard1 --dbpath /data/shard1a --port 27018 --fork --logpath /var/log/mongodb/shard1a.log mongod --shardsvr --replSet shard1 --dbpath /data/shard1b --port 27022 --fork --logpath /var/log/mongodb/shard1b.log mongod --shardsvr --replSet shard1 --dbpath /data/shard1c --port 27023 --fork --logpath /var/log/mongodb/shard1c.log # 初始化分片 1 复制集 mongo --port 27018 --eval " rs.initiate({ _id: 'shard1', members: [ { _id: 0, host: 'shard1a:27018' }, { _id: 1, host: 'shard1b:27022' }, { _id: 2, host: 'shard1c:27023' } ] }) "添加分片到集群
javascript// 连接到 mongos mongo --port 27017 // 添加分片 sh.addShard("shard1/shard1a:27018,shard1b:27022,shard1c:27023") sh.addShard("shard2/shard2a:27024,shard2b:27025,shard2c:27026") sh.addShard("shard3/shard3a:27027,shard3b:27028,shard3c:27029")
分片故障处理
分片主节点故障
- 复制集自动选举新的主节点
- 选举过程通常在 10 秒内完成
- 应用程序可能会短暂中断写入操作
分片从节点故障
- 不影响分片的可用性
- 复制集仍可处理读写操作
- 监控复制延迟,确保剩余节点能够处理负载
整个分片故障
- 若整个分片不可用,该分片上的数据将无法访问
- 建议:javascript
// 检查分片状态 sh.status() // 检查受影响的集合 db.collection.getShardDistribution() // 恢复故障分片 // 1. 修复硬件或网络问题 // 2. 重启分片成员 // 3. 等待复制集恢复
mongos 高可用性
mongos 部署策略
多 mongos 实例部署
- 在多个服务器上部署 mongos 实例
- 推荐每个应用服务器部署一个 mongos 实例
- 或使用负载均衡器分发客户端连接
启动 mongos
bash# 启动 mongos mongos --configdb csrs/config1:27019,config2:27020,config3:27021 --port 27017 --fork --logpath /var/log/mongodb/mongos.log mongos --configdb csrs/config1:27019,config2:27020,config3:27021 --port 27030 --fork --logpath /var/log/mongodb/mongos2.log
mongos 故障处理
单个 mongos 故障
- 客户端自动连接到其他可用的 mongos 实例
- 建议在客户端实现 mongos 实例的自动发现和故障转移
所有 mongos 实例故障
- 客户端无法连接到分片集群
- 建议:bash
# 重启 mongos 实例 mongos --configdb csrs/config1:27019,config2:27020,config3:27021 --port 27017 --fork --logpath /var/log/mongodb/mongos.log # 检查 mongos 状态 mongo --port 27017 --eval "db.adminCommand({ ping: 1 })"
分片集群故障转移
自动故障转移
复制集自动故障转移
- 当主节点不可用时,复制集会自动选举新的主节点
- 适用于配置服务器复制集和分片复制集
mongos 自动故障转移
- 客户端需要实现 mongos 实例的自动发现和故障转移
- 建议使用负载均衡器或客户端驱动的自动重连机制
手动故障转移
手动切换复制集主节点
javascript// 在主节点上执行 rs.stepDown()手动恢复故障分片
javascript// 检查分片状态 sh.status() // 检查分片复制集状态 use admin
db.runCommand({ replSetGetStatus: 1, shard: "shard1" })
## 监控和告警
### 关键监控指标
1. **mongos 监控指标**
- 连接数:`db.serverStatus().connections`
- 查询速率:`db.serverStatus().opcounters`
- 路由耗时:`db.serverStatus().metrics.query.router`
- 配置服务器连接状态
2. **配置服务器监控指标**
- 复制集状态:`rs.status()`
- 复制延迟:`rs.printSlaveReplicationInfo()`
- 配置数据完整性
3. **分片监控指标**
- 复制集状态:`rs.status()`
- 复制延迟:`rs.printSlaveReplicationInfo()`
- 数据分布:`db.collection.getShardDistribution()`
- 分片负载:`db.serverStatus().globalLock`
### 告警设置
1. **mongos 告警**
- 连接数超过阈值
- mongos 实例不可用
- 配置服务器连接失败
2. **配置服务器告警**
- 复制集状态异常
- 复制延迟超过阈值
- 配置服务器成员不可用
3. **分片告警**
- 复制集状态异常
- 复制延迟超过阈值
- 分片成员不可用
- 单个分片负载过高
## 备份和恢复
### 分片集群备份策略
1. **分片级备份**
- 对每个分片的复制集进行备份
- 使用 `mongodump` 或文件系统快照
- 备份 oplog 用于时间点恢复
2. **配置服务器备份**
- 备份配置服务器复制集
- 确保配置数据的完整性
3. **一致性备份**
- 使用 `--oplog` 选项进行一致性备份
- 或在所有分片上使用相同的时间点进行备份
### 分片集群恢复流程
1. **恢复单个分片**
- 恢复分片复制集
- 确保分片数据与其他分片一致
- 更新分片集群元数据
2. **恢复整个集群**
- 恢复配置服务器复制集
- 恢复每个分片的复制集
- 启动 mongos 实例
- 验证集群状态
## 扩容和缩容
### 分片集群扩容
1. **添加新分片**
```javascript
// 连接到 mongos
mongo --port 27017
// 添加新分片
sh.addShard("shard4/shard4a:27031,shard4b:27032,shard4c:27033")
// 开启平衡器
sh.enableBalancing("mydb.mycollection")
// 检查平衡器状态
sh.getBalancerState()- 数据重平衡
- MongoDB 自动将数据迁移到新分片
- 监控平衡器状态
- 调整平衡器窗口
分片集群缩容
移除分片
javascript// 连接到 mongos mongo --port 27017 // 移除分片 sh.removeShard("shard4") // 检查移除状态 sh.status()数据迁移
- MongoDB 自动将数据从待移除分片迁移到其他分片
- 监控迁移进度
- 确认数据迁移完成
最佳实践
架构设计最佳实践
奇数个复制集成员
- 配置服务器复制集:3 个成员
- 每个分片复制集:3 个或 5 个成员
- 避免使用仲裁者
跨区域部署
- 将复制集成员分布在不同的数据中心
- 提高容灾能力
- 考虑使用多区域负载均衡
适当的硬件配置
- 配置服务器:中等配置即可
- 分片:根据数据量和负载选择适当的硬件
- mongos:轻量级,可部署在应用服务器上
运维最佳实践
定期监控
- 配置全面的监控和告警
- 定期检查集群状态
- 分析性能指标
定期备份
- 制定备份策略
- 定期测试恢复流程
- 确保备份数据的完整性
定期演练
- 定期进行故障演练
- 测试自动故障转移
- 验证恢复流程
升级策略
- 遵循推荐的升级顺序:配置服务器 → 分片 → mongos
- 在测试环境验证升级
- 制定回滚计划
常见问题(FAQ)
Q1: 分片集群最少需要多少台服务器?
A1: 推荐的最小配置:
- 3 台服务器用于配置服务器复制集
- 3 台服务器用于第一个分片的复制集
- 1 台服务器用于 mongos 实例
- 总共 7 台服务器
Q2: 如何选择分片键?
A2: 选择分片键的建议:
- 高基数:分片键值的分布范围广
- 低频率:分片键值的更新频率低
- 随机性:写入操作分布在多个分片上
- 查询模式:考虑常用的查询模式
Q3: 如何处理热点分片?
A3: 处理热点分片的方法:
- 优化分片键设计
- 使用更细粒度的分片键
- 考虑使用哈希分片
- 监控分片负载,及时扩容
Q4: 如何监控分片集群的平衡器?
A4: 监控平衡器的方法:
javascript
// 检查平衡器状态
sh.getBalancerState()
// 检查平衡器运行状态
sh.isBalancerRunning()
// 查看平衡器日志
db.adminCommand({ logs: 1, logComponent: "sharding" })Q5: 分片集群的写入关注点应该如何设置?
A5: 写入关注点建议:
- 生产环境:
{ w: "majority" } - 确保数据写入到大多数节点
- 平衡一致性和性能需求
Q6: 如何处理分片集群中的网络分区?
A6: 处理网络分区的方法:
- 设计跨区域架构
- 配置适当的投票成员
- 监控网络连接
- 准备手动干预方案
Q7: 如何验证分片集群的完整性?
A7: 验证集群完整性的方法:
javascript
// 检查集群状态
sh.status()
// 检查配置服务器状态
use config
db.serverStatus()
// 检查分片状态
db.adminCommand({ replSetGetStatus: 1, shard: "shard1" })
// 验证数据分布
db.collection.getShardDistribution()Q8: 如何优化分片集群的查询性能?
A8: 优化查询性能的方法:
- 创建合适的索引
- 优化查询语句
- 考虑使用覆盖索引
- 避免跨分片查询
- 优化分片键设计
Q9: 如何处理分片集群中的长时间运行操作?
A9: 处理长时间运行操作的方法:
javascript
// 查看当前操作
db.currentOp()
// 终止长时间运行的操作
db.killOp(opid)
// 优化长时间运行的查询
// 1. 分析查询执行计划
// 2. 创建适当的索引
// 3. 考虑使用分片键查询Q10: 如何升级分片集群?
A10: 升级分片集群的步骤:
- 升级配置服务器复制集
- 升级每个分片的复制集
- 升级 mongos 实例
- 验证集群状态
- 更新功能兼容性版本
