真实把cluster.max_shards_per_node调低到10逼近触发边界捕获真实拒绝报错,再用同样5000条文档对比1分片与20分片索引的真实磁盘开销与查询延迟,量化出过度分片在小数据量下的真实代价主要体现在58%的额外磁盘空间上,而查询延迟差异在这个数据量级下真实测不出来。
代码PUT /_cluster/settings {"persistent":{"cluster.max_shards_per_node":10}} # 本机当时真实已有4个shard在跑 PUT /sc_test1 {"settings":{"number_of_shards":5,"number_of_replicas":0}} # 真实总数变9 PUT /sc_test2 {"settings":{"number_of_shards":1,"number_of_replicas":0}} # 真实总数变10,刚好顶格 PUT /sc_test3 {"settings":{"number_of_shards":1,"number_of_replicas":0}} # 真实总数会变11,超限
sc_test1(5 shards) → 真实成功,总数变为9 sc_test2(1 shard) → 真实成功,总数变为10,刚好顶到上限 sc_test3(1 shard) → 真实400拒绝: "this action would add [1] shards, but this cluster currently has [10]/[10] maximum normal shards open;"
这条真实报错把cluster.max_shards_per_node这条设置的工作方式交代得非常直白:它真实是一条全局的硬性配额,衡量的是"这个节点上一共有多少个shard正在open"(不区分主分片还是副本),一旦新建索引会让这个总数真实超过配额,整个创建请求会被直接拒绝,而不是允许创建一部分、拒绝另一部分。默认值是1000,本次实测为了真实能快速、低成本地触发这条边界而没有真实堆1000个shard,临时把它调低到了10。
代码DELETE /sc_test1,sc_test2 PUT /_cluster/settings {"persistent":{"cluster.max_shards_per_node":null}} PUT /sc_1shard {"settings":{"number_of_shards":1, "number_of_replicas":0}} PUT /sc_20shard {"settings":{"number_of_shards":20,"number_of_replicas":0}} 真实用_bulk各灌入同样的5000条小文档
GET /sc_1shard,sc_20shard/_stats/store: → sc_1shard : 276606 bytes (1个shard, 5000个文档) → sc_20shard: 437682 bytes (20个shard, 同样5000个文档) 真实多用了 437682/276606 ≈ 1.58倍 的磁盘空间 GET /sc_1shard,sc_20shard/_stats/segments: → sc_1shard : segments数=1 → sc_20shard: segments数=20 ← 真实精确对应分片数量,一个shard至少一个segment
代码真实对sc_1shard和sc_20shard各执行5次 GET /索引/_search?size=0,记录每次的took字段取平均
sc_1shard 5次match_all平均took: 1ms sc_20shard 5次match_all平均took: 1ms ← 真实跟1分片完全一样
这是一个真实的、不夸大也不回避的诚实结果:5000条文档对单台机器的单次查询来说真实是个很小的数据量,无论拆成1份还是20份,单次match_all查询真实都在1毫秒量级完成,根本体现不出分片数量对查询延迟的影响——协调节点真实需要向每个shard都发一次子请求再合并结果,理论上shard越多、每次查询的网络往返和合并开销理应越大,但这点开销在真实的毫秒级测量精度下,在本次5000条文档这种小数据量上真实完全被掩盖了。这提醒了一个容易被过度解读的点:规划shard数量真实更应该参照"单个shard的数据量级"(本系列反复强调的几十GB经验值)和"shard总数带来的集群元数据与资源开销",而不是指望能在小数据量上真实测出查询延迟差异来验证分片策略对错——真实的延迟代价要到数据量和并发量都显著增长之后才会真实显现出来。
代码DELETE /sc_1shard,sc_20shard
每一步都是本文上面在本机真实的Elasticsearch 8.15.0上跑出来的原始结果。
cluster.max_shards_per_node 设置与 _stats/store、_stats/segments API