一条查询是怎么被 mongos 路由到分片的?带不带分片键差多少负载?这篇用 3 个分片逐种查询看 explain 的 stage、涉及的分片,再统计 100 次查询带给每个分片的负载。
sh0 [MinKey(), 1000) sh1 [1000, 2000) sh2 [2000, MaxKey())
条件里有分片键的等值或落在单个 chunk 范围内的范围查询,mongos 只问一个分片(SINGLE_SHARD)。
uid = 1500 stage=SINGLE_SHARD 分片 ['sh1'] uid ∈ [500, 800) stage=SINGLE_SHARD 分片 ['sh0'] uid ∈ [900, 1100)(跨 sh0、sh1)stage=SHARD_MERGE 分片 ['sh0', 'sh1'] uid $in [10, 1100, 2100] stage=SHARD_MERGE 分片 ['sh0', 'sh1', 'sh2'] city = 7(不含分片键) stage=SHARD_MERGE 分片 ['sh0', 'sh1', 'sh2'] 空条件(全表) stage=SHARD_MERGE 分片 ['sh0', 'sh1', 'sh2'] city = 7, sort uid stage=SHARD_MERGE_SORT分片 ['sh0', 'sh1', 'sh2']
跨 chunk 的范围、$in 多值、不含分片键的查询要问所有相关分片(SHARD_MERGE),集群总负载约乘以分片数。
查询(各 100 次) sh0 sh1 sh2 uid = 1500(targeted) 0 100 0 uid 范围 [0, 100) 100 0 0 city = 7(无分片键) 100 100 100 空条件 limit 1 100 100 100
各 100 次查询时,targeted 查询只给一个分片带来 100 次 query,无分片键的查询给三个分片各带来 100 次。
stage = SHARD_MERGE_SORT;各分片返回 nReturned: [('sh1', 5), ('sh2', 5), ('sh0', 5)];最终 nReturned 5sort + limit:每个分片各自排序取 limit 个,mongos 归并后再取前 limit 个。
update_one 带分片键 uid 成功(matched=1) update_one 只带 _id 以外的字段 city 成功(matched=1) update_many 不带分片键 成功(matched=60) delete_one 不带分片键 成功(matched=1)
9.0.2 上不带分片键的 update_one、delete_one 也能成功,服务端会自己找到文档所在的分片。
uid = 1500 涉及 1 个分片;每个分片(名, 检查的键, 检查的文档, 返回): [('sh1', 1, 1, 1)];合计检查键 1
city = 7 涉及 3 个分片;每个分片(名, 检查的键, 检查的文档, 返回): [('sh0', 20, 20, 20), ('sh1', 20, 20, 20), ('sh2', 20, 20, 20)];合计检查键 60targeted 查询只检查 1 个键,scatter-gather 在每个分片上各检查一遍(这里共 60 个键)。