适用版本: 6.8-7.15
1. 错误异常的基本描述 #
Trying to create too many buckets. Must be less than or equal to: [bucketLimit] but was [size] 是 Elasticsearch 在执行聚合请求时抛出的异常,表示当前请求试图创建的 bucket 数量超过了集群配置的上限。
与普通的 terms 聚合在运行中期才触发限制不同,composite 聚合会在初始化阶段就检查 size 参数。只要请求中指定的 size 大于 search.max_buckets,请求会直接被拒绝,不会进入实际执行阶段。
常见现象 #
- 发送 composite 聚合请求后立即返回 400 错误,响应体中包含
Trying to create too many buckets异常信息。 - 报错中的
was值恰好等于请求体中composite.aggs.size的值。 - 常见于业务方希望一次性拉取全量聚合结果,将
size设置为几万甚至更大的场景。 - 在 Kibana 或自定义 Dashboard 中配置大尺寸 composite 聚合时也容易触发此异常。
典型报错与异常栈 #
{
"error": {
"root_cause": [
{
"type": "too_many_buckets_exception",
"reason": "Trying to create too many buckets. Must be less than or equal to: [65536] but was [100000]. This limit can be set by changing the [search.max_buckets] cluster level setting."
}
],
"type": "search_phase_execution_exception",
"reason": "all shards failed",
"failed_shards": [
{
"reason": {
"type": "too_many_buckets_exception",
"reason": "Trying to create too many buckets. Must be less than or equal to: [65536] but was [100000]. This limit can be set by changing the [search.max_buckets] cluster level setting."
}
}
]
},
"status": 400
}
2. 为什么会发生这个错误 #
composite 聚合的设计初衷是分批、流式地遍历所有 bucket,而不是一次性返回全部结果。Elasticsearch 在构造 composite 聚合器时,会在 composite 的 size 参数与集群级设置 search.max_buckets 之间做校验:
int bucketLimit = context.multiBucketConsumer().getLimit();
if (size > bucketLimit) {
throw new MultiBucketConsumerService.TooManyBucketsException(
"Trying to create too many buckets. Must be less than or equal" +
" to: [" + bucketLimit + "] but was [" + size + "]. This limit can be set by changing the [" +
MAX_BUCKET_SETTING.getKey() + "] cluster level setting.", bucketLimit
);
}
常见触发原因包括:
- 误将 composite 聚合当作全量导出接口:composite 聚合的正确用法是通过
after_key分页迭代,而不是一次性设置超大size。 search.max_buckets设置过小:默认值(如 65536)对某些业务场景可能偏低,但这通常是合理的安全阈值。- 业务方未评估内存开销:每个 bucket 都会占用协调节点和数据节点的内存,无限制地拉取 bucket 会导致 JVM 堆压力骤增。
- 从 terms 聚合迁移时未调整用法:terms 聚合通过
size控制返回数量,而 composite 聚合的size是单页大小,两者语义不同。
3. 如何排查和解决这个异常 #
建议按以下顺序排查:
- 确认异常对应的请求:从报错信息中提取
was后的数值,即为请求中size的值。 - 查看集群当前限制:执行以下命令获取
search.max_buckets的当前值:GET _cluster/settings?include_defaults=true&flat_settings=true # 或精准查询 GET _cluster/settings?filter_path=*.search.max_buckets - 检查请求中的
size参数:确认 composite 聚合中size的设置是否合理。 - 评估数据规模:通过以下查询估算实际需要的 bucket 数量:
GET /your_index/_search { "size": 0, "aggs": { "distinct_count": { "cardinality": { "field": "your_composite_field" } } } }
排查时需要注意的问题 #
search.max_buckets是集群级设置,修改后会影响所有聚合请求,不宜随意调大。- composite 聚合的
size是单页大小,不是总 bucket 数上限。 - 如果报错中的
was值远大于bucketLimit,通常说明请求设计有问题,而不是限制有问题。
4. 如何解决这个错误 #
常用修复思路 #
方案一:降低 composite 聚合的 size,使用 after_key 分页
这是最推荐的做法。将 size 调整到 search.max_buckets 以内,然后通过 after_key 迭代获取全部结果:
# 第一页
GET /your_index/_search
{
"size": 0,
"aggs": {
"my_buckets": {
"composite": {
"size": 1000,
"sources": [
{ "keyword_field": { "terms": { "field": "category.keyword" } } }
]
}
}
}
}
# 后续页:使用上一页返回的 after_key
GET /your_index/_search
{
"size": 0,
"aggs": {
"my_buckets": {
"composite": {
"size": 1000,
"sources": [
{ "keyword_field": { "terms": { "field": "category.keyword" } } }
],
"after": {
"keyword_field": "上一个 bucket 的 key 值"
}
}
}
}
}
方案二:临时调高 search.max_buckets(需谨慎评估)
# 临时设置(重启后失效)
PUT _cluster/settings
{
"transient": {
"search.max_buckets": 100000
}
}
# 持久化设置
PUT _cluster/settings
{
"persistent": {
"search.max_buckets": 100000
}
}
注意: 调高此限制前,务必评估协调节点和数据节点的 JVM 堆内存是否充足,避免引发 OOM。
后续注意事项与推荐建议 #
- 封装分页 SDK:在业务层封装 composite 聚合的分页迭代逻辑,避免业务代码直接设置超大
size。 - 将
search.max_buckets视为安全阈值:该限制的存在是为了防止单个请求耗尽集群内存,不应被随意放大。 - 监控大聚合请求:通过慢查询日志或 INFINI Gateway 识别
size过大的聚合请求,及时干预。 - 优先使用
composite而非terms做深度分页聚合:composite 天然支持游标分页,更适合大规模遍历场景。
借助 INFINI 产品提升排障效率 #
- INFINI Console 可查看集群的聚合请求画像、慢查询趋势和节点内存使用情况,帮助判断是否存在异常的大聚合请求。
- INFINI Gateway 可部署在 Elasticsearch 前面,对
size过大的 composite 聚合请求进行拦截、限流或告警,防止单个请求拖垮整个集群。
5. 小结 #
Trying to create too many buckets 在 composite 聚合场景中,根因通常是请求的单页 size 超过了 search.max_buckets 限制。修复重点不在于调高限制,而在于正确使用 composite 聚合的分页机制:将 size 控制在合理范围内,通过 after_key 迭代获取全量数据。
只要建立规范的分页封装、将 search.max_buckets 视为保护阈值而非可随意调整的参数,大多数此类异常都可以从设计层面避免。
相关错误 #
附:日志上下文 #
下面保留当前页面中的源码片段,便于结合异常调用栈定位问题:
int bucketLimit = context.multiBucketConsumer().getLimit();
if (size > bucketLimit) {
throw new MultiBucketConsumerService.TooManyBucketsException("Trying to create too many buckets. Must be less than or equal" +
" to: [" + bucketLimit + "] but was [" + size + "]. This limit can be set by changing the [" + MAX_BUCKET_SETTING.getKey() +
"] cluster level setting.", bucketLimit);
}





