YCSB连不上MongoDB分片集群主因是连接字符串未指向mongos且缺失authSource=admin;分片键若用range(如{user_id:1})配递增ID会导致数据倾斜,应改用hashed;超时异常多因mongos队列满,需调优maxConns及ulimit;load快run慢源于元数据压力,须预分片并关闭balancer。

YCSB 连不上 MongoDB 分片集群:连接字符串和认证配置不对
YCSB 默认用 mongodb:// 协议直连单节点,但分片集群必须连 mongos,且不能写 shard01 或 configsvr 地址。常见错误是把 mongos 端口填成 27017(默认)却没确认它真在跑,或漏掉 ?authSource=admin 导致认证失败。
- 检查
mongos是否存活:mongo --host your-mongos-host --port 27018能否进 shell;端口常被改成27018或30000 - 连接字符串格式必须为:
mongodb://user:pass@host:port/?authSource=admin&replicaSet=rs0(若启用了副本集模式的mongos) - YCSB 的
-p mongodb.url=...值里不要加数据库名(如/ycsb),否则会创建新 DB,绕过分片逻辑 - 如果集群开了 x.509 认证,YCSB 不原生支持,得换
mongo-java-driver3.x+ 自定义 client,不推荐压测时用
分片键选错导致 YCSB 写入全打到一个 chunk:hash vs range 的实际影响
YCSB 默认用 user_id 当主键,若分片键设为 {user_id: 1}(range 分片),而测试数据 user_id 是递增整数(如 1,2,3,...),所有写请求都会落到最后一个 chunk —— 吞吐量看起来高,其实是单节点在扛,完全没测出分片效果。
- 用 hash 分片键最稳妥:
{user_id: "hashed"},YCSB 的递增 ID 会被均匀散列 - 避免用时间戳字段(如
timestamp)做 range 分片键,YCSB 插入集中在“最新”区间 - 压测前先运行
sh.status(),确认 chunks 在各 shard 上数量均衡(比如 3 个 shard,每个应有 ~⅓ 的 chunk) - 如果用复合分片键(如
{region: 1, user_id: 1}),YCSB 必须在 workload 中显式生成region字段,否则插入失败
YCSB 报 com.mongodb.MongoSocketReadTimeoutException:不是网络问题,是 mongos 队列满
这个错误表面看是超时,实则是 mongos 的并发连接/请求队列溢出。YCSB 线程数(-threads)设太高,而 mongos 默认 maxConns 是 65536,但内核 socket buffer、ulimit 和 net.maxIncomingConnections 才是瓶颈。
- 调大
mongos启动参数:--maxConns 100000 --net.maxIncomingConnections 100000 - YCSB 的
-threads别盲目拉到 512;先从 64 开始,配合mongostat -h mongos-host:port观察netIn/netOut和conn变化 - Linux 上检查:
ss -s看已用 socket 数,ulimit -n确保 > 100000 - 如果用 Docker 跑
mongos,记得加--ulimit nofile=100000:100000,否则容器内 ulimit 仍是默认 1024
为什么 load 阶段快、run 阶段吞吐跳变?YCSB 的 insert 和 read 混合策略暴露分片元数据压力
YCSB 的 workloada(50% read / 50% update)在分片集群上容易出现 run 阶段初期吞吐骤降,接着缓慢爬升。这不是业务逻辑问题,而是 mongos 频繁查询 config server 获取 chunk 分布,尤其当测试数据量远超当前 chunk 数时,自动 split + migrate 触发元数据更新风暴。
- 压测前预分片:用
sh.shardCollection("ycsb.usertable", {"user_id": "hashed"}, {"numInitialChunks": 128}),避免 run 时动态 split - 关闭 balancer:
sh.setBalancerState(false),等 load 完再开,防止 migrate 干扰 run 阶段 - YCSB 的
-p recordcount=1000000要和预分片 chunk 数匹配;太少(如 10k 条)会导致大量空 chunk,太多(如 1 亿)又让 config server 压力大 - 监控
config.locks集合,如果state: 2(balancer lock)长期存在,说明 balancer 卡住,直接 kill 它再重试
分片键设计和预分片动作,比调线程数或加机器更能决定你看到的数字是不是真实吞吐量。很多人跑完只看 summary 里的 ops/sec,却没打开 sh.status() 看 chunk 分布,结果压的是假集群。











