必须用DNS轮询指向多个mongos并禁用keepalive,配合预分片和合理分片键设计,才能使YCSB请求真正均匀打到所有分片;否则流量集中于单个mongos及分片,压测结果失真。

YCSB压测时如何让请求真正打到所有分片?
默认配置下,YCSB会复用单个连接,所有请求都走同一个mongos实例,流量根本不会分散到后端分片——你看到的“吞吐量”其实是单个mongos的转发能力,不是分片集群的真实水平。
- 必须用
mongodb.url指向多个 mongos 的 DNS 名称(如mongodb://mongos-a,mongos-b,mongos-c/),不能写死单个 IP;DNS 必须配置为轮询解析,否则客户端只连第一个 - 加参数
-p mongodb.connections.per.host=4,避免单连接瓶颈;-threads 100不等于 100 个有效并发,实际连接数由connections.per.host × mongos 实例数决定 - 禁用连接池复用:加
-p mongodb.socketKeepAlive=false,否则 TCP 连接复用会掩盖分片间负载不均 - 验证是否生效:压测中执行
sh.status(),观察各分片的chunks分布和balancer状态;同时在每个 shard 上运行mongostat --host <shard-host> -n 1,确认 ops/sec 在多个分片上同步上升
分片键设计不当会导致压测结果完全失真
压测吞吐量上不去、延迟飙升,90% 是因为分片键没选对——不是数据库慢,是所有写入全挤在一个分片上。
- 绝对避免用单调递增字段(如
timestamp、ObjectId)做范围分片键,否则新写入永远落到同一 chunk,其他分片全程闲置 - 如果业务允许,优先用
{_id: "hashed"};若需范围查询,改用复合键,例如{region: 1, created_at: 1},把高基数字段放在前面 - 压测前必须预分片:先
sh.enableSharding("db.col"),再sh.shardCollection("db.col", {"region": "hashed"}),最后才 load 数据;否则数据加载完成前 balancer 还没切分完 chunk,压测期间大量 moveChunk 操作会严重拖慢写入 - 检查是否生效:压测中执行
db.col.getShardDistribution(),各分片文档数偏差不应超过 20%
为什么写入延迟突增但 CPU 和磁盘都很低?
这是分片集群特有的元数据瓶颈,跟硬件无关,只跟 config server 负载有关。
- 现象:YCSB
updateproportion> 0 时,平均延迟跳到 200ms+,但所有 shard 和 mongos 的 CPU - 根因:每次写操作都要查 config server 的
config.chunks表确认目标分片,高并发下 config server 成为单点锁竞争热点 - 快速定位:登录任意 config server,执行
db.currentOp({secs_running: {$gt: 0.5}}),看是否有大量阻塞在find或updateonconfig.chunks - 缓解手段:降低写入频率(加
-p mongodb.writeConcern=w:1)、升级 config server 到 6.0+(支持更细粒度锁)、或临时关闭 balancer(sh.setBalancerState(false))只用于压测阶段
mongoreplay 重放真实流量时怎么避免打偏分片?
原始流量若来自直连分片的旧客户端,重放时请求会绕过 mongos,直接发到错误分片,压测结果毫无参考价值。
- 录制前确认:用
mongostat --host <mongos-addr>观察netIn是否有持续流量,且insert/query数值与应用日志匹配;若只有conn变化,说明客户端没走 mongos - 重放时强制走 mongos:用
--mongo-url mongodb://<mongos-dns>/,别用mongodb://<shard-ip>:27017/ - 跳过危险操作:加
--exclude-admin --no-js,否则$where或 admin 命令可能触发 config server 元数据变更,干扰压测 - 并发打散:必须加
--connections 16 --no-keepalive,否则重放仍复用原始连接,流量粘在单个 mongos 上
sh.status() 和各分片的 mongostat 实时指标,就等于闭着眼睛调油门。


















