mongos负载不均并非Nginx/LVS所致,根本原因在于连接粘性缺失、客户端绕过代理、分片键设计缺陷或mongos资源不均;需启用ip_hash、验证SDK是否直连、检查分片键合理性并调优连接池参数。

mongos 负载不均不是 Nginx/LVS 的锅
四层负载均衡器(如 Nginx stream 或 LVS)本身不解析 MongoDB Wire Protocol,只做 TCP 流转发;只要后端 mongos 实例健康且配置一致,代理层不会主动造成倾斜。真正导致负载不均的,通常是以下情况:
- 没启用连接粘性(
ip_hash或hash $remote_addr consistent),导致一个客户端的事务、getMore请求被轮询打到不同mongos,触发重路由或失败重试,放大局部压力 - 客户端 SDK(如 Node.js Driver、Go Driver)启用了自动拓扑发现,绕过 Nginx 直连部分
mongos地址 - 应用侧硬编码多个
mongos地址,或做了 DNS 轮询,和 Nginx 形成双路径分流,流量不可控 - 某些
mongos所在节点 CPU/内存/网络带宽明显偏低,或混部了其他高负载服务
loadBalanced=true 必须显式开启,否则多 mongos 形同虚设
Spring Boot 或其他框架默认的 MongoClient 是单例,即使你部署了 3 个 mongos,所有请求仍可能只走其中一个——因为客户端没启用负载感知能力。
- 连接字符串必须显式包含多个地址并启用参数:
mongodb://mongos1:27017,mongos2:27017,mongos3:27017/chatdb?loadBalanced=true -
loadBalanced=true是 MongoDB Java Driver 4.11+ 才真正支持的特性,旧版本驱动忽略该参数 - 禁用默认超时(如
maxWaitTime),改用minPoolSize=50+maxPoolSize=200+maxConnectionLifeTime=0,否则连接池会成为瓶颈
分片键设计不当,会让 mongos 路由失效
写入热点不在 mongos 层,但在分片层,会导致某个 mongos 长期处理大量重定向请求(比如目标分片响应慢、chunk 拆分卡住),间接拉高其 CPU 和队列延迟。
- 避免用
userId、timestamp、自增_id等与业务逻辑或时间强相关的字段作分片键 - 推荐使用伪随机哈希前缀(如
Math.random().toString(36).substring(2, 10))作为独立字段,配合hashed分片策略 - 验证方式:插入 10 万条数据后执行
sh.status(),观察各分片chunks数量是否在均值 ±15% 内
mongos 连接池参数不调优,比负载不均更致命
默认 minConnsPerHost=0、maxConnsPerHost=100 在高并发下极易打满,引发排队、新建风暴甚至 connection refused by peer 错误。
- 用
db.adminCommand({ "connPoolStats": 1 })查看各 shard 的inUse值,若长期等于maxConnsPerHost,说明池已饱和 -
shard端的net.maxIncomingConnections必须 ≥mongos侧配置的maxConnsPerHost,否则建连直接被拒 - 同可用区部署建议
minConnsPerHost=10、maxConnsPerHost=200;跨 AZ(RTT 5–10ms)建议降到100–120
连接粘性、客户端驱动行为、分片键语义、连接池水位——这四个点里任意一个没对齐,mongos 的“多节点”就只是物理存在,不是实际生效的并发能力。最容易被忽略的是 loadBalanced=true 参数缺失和 minConnsPerHost=0 导致的冷启延迟放大。











