1. MongoDB 分片集群概述
分片集群(Sharded Cluster)是 MongoDB 实现水平扩展的核心方案,通过将数据分布到多个服务器(分片)中,解决单机存储容量和性能瓶颈。其核心目标是实现数据的分布式存储与负载均衡。
2. 分片集群架构与核心组件
2.1 分片(Shard)
-
作用:存储实际数据片段,每个分片包含数据集的一个子集。
-
实现方式:推荐使用副本集(Replica Set)作为分片,以提高可用性和数据冗余。
2.2 配置服务器(Config Server)
-
作用:存储集群元数据(如分片键、数据分布、路由规则等)。
-
要求:必须为副本集形式,确保元数据高可用。
2.3 查询路由(Mongos)
-
作用:作为客户端访问集群的入口,负责路由请求到目标分片。
-
特性:无状态服务,可部署多个实例以提高并发能力。
3. 分片键(Shard Key)与数据分布
3.1 分片键定义
-
定义:用于划分数据的字段(如
user_id
或timestamp
)。 -
重要性:分片键的选择直接影响数据均衡性和查询性能。需满足高基数、低频率、值分布均匀。
3.2 Chunks(数据块)详解
-
定义:Chunk 是 MongoDB 分片集群中数据分片的基本单位,表示分片键值范围内的连续数据段。默认大小为 64MB~128MB(可配置)。
-
关键特性:
-
动态迁移:MongoDB 的平衡器(Balancer)会根据分片负载自动迁移 Chunk,确保数据均匀分布。
-
元数据记录:每个 Chunk 的边界信息(如最小 / 最大分片键值)存储在配置服务器中。
-
拆分机制:当 Chunk 大小超过阈值时,MongoDB 会自动将其拆分为多个更小的 Chunk。
-
-
操作流程:
-
数据写入时,根据分片键值分配到对应的 Chunk。
-
Chunk 达到阈值后触发拆分,生成新 Chunk。
-
平衡器监控各分片的 Chunk 数量,自动迁移 Chunk 以实现负载均衡。
-
4. 分片集群注意事项
4.1 容量规划与 Chunk 管理
-
注意点:当单个分片存储容量达到 60% 时,建议扩容新分片。
-
原因:容量超过阈值会导致 Chunk 迁移延迟,甚至触发频繁的自动拆分与迁移,增加集群负载,影响读写性能。
4.2 分片键设计
-
注意点:优先选择复合分片键(如
{region: 1, user_id: 1}
)。 -
原因:单调递增的分片键(如时间戳)会导致新数据集中在最新 Chunk,形成写入热点;复合分片键可分散写入压力,同时提升范围查询效率。
4.3 配置服务器保护
-
注意点:禁止直接操作配置服务器,仅通过
mongos
管理集群。 -
原因:配置服务器存储 Chunk 元数据,直接修改可能导致 Chunk 分布信息错误,引发数据路由混乱。
4.4 索引管理
-
注意点:在每个分片上为分片键创建索引。
-
原因:未创建索引时,查询会退化为全分片扫描,尤其是跨多个 Chunk 的查询会显著降低性能。
4.5 平衡器(Balancer)控制
-
注意点:在业务低峰期手动调整平衡器窗口时间。
-
原因:平衡器迁移 Chunk 时会占用大量 I/O 和网络资源,高峰期操作可能导致服务延迟。
5. Chunk 相关运维场景
5.1 Chunk 手动迁移
-
场景:分片负载不均时,可手动指定迁移特定 Chunk。
- 命令示例:
sh.moveChunk("database.collection", {shardKey: value}, "targetShard")
MongoDB 分片集群部署
共十一台机器
角色 | IP | 端口 |
---|---|---|
shard1 - Master | 192.168.80.11 | 27017 |
shard1 - slave | 192.168.80.22 | 27017 |
shard1 - slave | 192.168.80.33 | 27017 |
shard2 - Master | 192.168.80.44 | 27017 |
shard2 - slave | 192.168.80.55 | 27017 |
shard2 - slave | 192.168.80.66 | 27017 |
配置服务器 - Master | 192.168.80.77 | 27019 |
配置服务器 - slave | 192.168.80.88 | 27019 |
配置服务器 - slave | 192.168.80.99 | 27019 |
Mongos + Keepalived1 | 192.168.80.100 | 27017 |
Mongos + Keepalived2 | 192.168.80.200 | 27017 |
搭建 shard1 复制集
shard1 角色编辑配置文件:
systemLog:destination: filepath: "/mongodb/log/mongodb.log"logAppend: true storage:dbPath: "/mongodb/data/"journal:enabled: true processManagement:fork: true net:port: 27017bindIp: 0.0.0.0 replication:oplogSizeMB: 2048replSetName: shard1 sharding:clusterRole: shardsvr
shard1 主节点赋值 config 变量
config = { _id: 'shard1', members: [{_id: 0, host: '192.168.80.11:27017'},{_id: 1, host: '192.168.80.22:27017'} ,{_id: 2, host: '192.168.80.33:27017'}]} rs.initiate(config)
shard1 搭建完毕:
搭建 shard2 复制集
shard2 角色编辑配置文件:
systemLog:destination: filepath: "/mongodb/log/mongodb.log"logAppend: true storage:dbPath: "/mongodb/data/"journal:enabled: true processManagement:fork: true net:port: 27017bindIp: 0.0.0.0 replication:oplogSizeMB: 2048replSetName: shard2 sharding:clusterRole: shardsvr
shard2 主节点赋值 config 变量
config = { _id: 'shard2', members: [{_id: 0, host: '192.168.80.44:27017'},{_id: 1, host: '192.168.80.55:27017'} ,{_id: 2, host: '192.168.80.66:27017'}]} rs.initiate(config)
shard2 搭建完毕:
搭建 config Server 节点
配置 config 节点配置文件
systemLog:destination: filepath: "/mongodb/log/mongodb.log"logAppend: true storage:dbPath: "/mongodb/data/"journal:enabled: true processManagement:fork: true net:bindIp: 0.0.0.0 replication:oplogSizeMB: 2048replSetName: config sharding:clusterRole: configsvr
config Server 主节点赋值 config 变量
systemLog:destination: filepath: "/mongodb/log/mongodb.log"logAppend: true storage:dbPath: "/mongodb/data/"journal:enabled: true processManagement:fork: true net:bindIp: 0.0.0.0 replication:oplogSizeMB: 2048replSetName: config sharding:clusterRole: configsvr
搭建 Mongos 节点
配置 Mongos 节点配置文件
systemLog:destination: filepath: "/mongodb/log/mongodb.log" sharding:configDB: config/192.168.80.77:27019,192.168.80.88:27019,192.168.80.99:27019 processManagement:fork: true net:bindIp: 0.0.0.0
关闭 mongod 服务,启动 mongos 服务
systemctl stop mongod.service mongos -f /mongodb/conf/mongo.conf ss -nltp
mongos 两节点配置成功
mongos 添加分片
mongo adminsh.addShard("shard1/192.168.80.11:27017") sh.addShard("shard2/192.168.80.44:27017")
配置分片规则
启用 Range 分片规则
//启用数据库的分片 sh.enableSharding("test") //创建索引 use test db.vast.createIndex({id:1}) //开启range分片规则 sh.shardCollection("test.vase",{id:1}) //造数据 use test for(i=0;i<100000;i++){db.vase.insert({"id":i,"name":"kk","date":new Date()})}
启用 Hash 分片规则
//启用数据库的分片 sh.enableSharding("TestHash") //指定在TestHash库的testtable表上创建hash索引 use TestHash db.testtable.createIndex({id:"hash"}) //指定表分片基于hash规则 sh.shardCollection("TestHash.testtable",{id:"hashed"}) //造数据 use TestHash for(i=0;i<30000;i++){db.testtable.insert({"id":i,"name":"kk","date":new Date()})}
查看分片状态:
查看两节点数据分布:
Balance 操作
介绍
mongos 的 Balancer(平衡器) 是 MongoDB 分片集群的核心组件,负责监测所有分片节点上的数据块(chunk)分布,并自动执行数据块迁移以实现负载均衡。
Balancer 的工作时机
自动运行:当系统负载较低时触发迁移。 节点删除时:移除分片节点后立即触发迁移。 时间窗口限制:可配置为仅在指定时间段内运行。
何时需要关闭 / 开启 Balancer?
备份期间:避免因数据迁移导致备份不一致。 维护窗口:与高负载业务时段错开。
示例:手动控制 Balancer
// 停止 Balancer mongos.sh.stopBalancer() // 启动 Balancer mongos.sh.startBalancer()
自定义自动平衡的时间段
连接到 mongos 实例: mongo --port 27017 admin 启用 Balancer 并验证状态: use config sh.setBalancerState(true) // 启用 sh.getBalancerState() // 检查状态(返回 true 表示已启用) 设置时间窗口(例如 3:00 至 5:00): db.settings.update({ _id: "balancer" }, { $set: { activeWindow: { start: "3:00", stop: "5:00" } } }, { upsert: true } )
验证配置:
sh.getBalancerWindow() // 查看时间窗口 sh.status() // 检查集群状态 db.settings.find() // 查询详细配置
集合级别的 Balance 管理
关闭 / 开启指定集合的 Balance
// 关闭集合 test.vast 的 Balance sh.disableBalancing("XXXXX") // 开启集合 test.vast 的 Balance sh.enableBalancing("XXXXX")
检查集合的 Balance 状态
// 查询集合的 noBalance 字段(true 表示已关闭) db.getSiblingDB("config").collections.findOne({ _id: "XXXXX" }).noBalance
Mongos 节点配置 Keepalived 实现高可用
Mongos 本身是无状态的,并没有故障转移功能,所以在特定场景中需要配置 Keepalived 实现 Mongos 的高可用
装置 keepalived 后编辑两节点配置文件
Mongos1:global_defs {router_id LVS_DEVELvrrp_skip_check_adv_addrvrrp_garp_interval 0vrrp_gna_interval 0 }vrrp_instance VI_1 {state MASTERinterface ens33virtual_router_id 51priority 100advert_int 1authentication {auth_type PASSauth_pass 123456}virtual_ipaddress {192.168.80.50/24192.168.80.51/24192.168.80.52/24} }Mongos2:global_defs {router_id LVS_DEVELvrrp_skip_check_adv_addrvrrp_garp_interval 0vrrp_gna_interval 0 }vrrp_instance VI_1 {state BACKUPinterface ens33virtual_router_id 51priority 60advert_int 1authentication {auth_type PASSauth_pass 123456}virtual_ipaddress {192.168.80.50/24192.168.80.51/24192.168.80.52/24} }
查看 VIP 状态,并尝试 Mongos 故障切换:
例如此时 Mongos1 故障,VIP 切换到 Mongos2 所在节点: