📣 极限科技诚招搜索运维工程师(Elasticsearch/Easysearch)- 全职/北京 👉 : 立即申请加入

为什么这个错误发生 #

circuit_breaking_exception 表示断路器被触发。断路器是 Easysearch 的内存保护机制,防止操作消耗过多内存导致 OutOfMemoryError。

这个错误可能由以下原因引起:

  1. 请求过大:单个请求尝试加载过多数据到内存
  2. 聚合数据过多:聚合操作产生的桶数量过多
  3. 字段数据缓存:字段数据(fielddata)缓存占用过多内存
  4. 请求级断路器:单个请求的内存使用超过限制
  5. 父级断路器:所有请求的总内存使用超过限制
  6. JVM 堆内存不足:JVM 堆内存设置过小
  7. 高并发:并发请求过多导致总内存使用超限
  8. 深度分页:from + size 值过大

如何修复这个错误 #

1. 查看断路器状态 #

# 查看所有断路器的状态
GET /_nodes/stats/breaker?pretty

# 查看特定节点的断路器
GET /_nodes/<node_id>/stats/breaker

2. 增加断路器限制 #

# 调整断路器限制(谨慎使用)
PUT /_cluster/settings
{
  "persistent": {
    "indices.breaker.total.limit": "70%",
    "indices.breaker.fielddata.limit": "40%",
    "indices.breaker.request.limit": "40%"
  }
}

3. 减少请求大小 #

# 使用分页而不是一次获取大量数据
GET /<index>/_search
{
  "size": 100,
  "from": 0,
  "query": {
    "match_all": {}
  }
}

# 或使用 scroll API
POST /<index>/_search?scroll=1m
{
  "size": 1000,
  "query": {
    "match_all": {}
  }
}

4. 优化聚合查询 #

# 使用 composite aggregation 处理大量数据
GET /<index>/_search
{
  "size": 0,
  "aggs": {
    "my_buckets": {
      "composite": {
        "size": 1000,
        "sources": [
          { "field_name": { "terms": { "field": "field" } } }
        ]
      }
    }
  }
}

# 使用 after_key 获取下一页

5. 处理字段数据断路器 #

# 查看字段数据缓存使用
GET /_indices/<index>/fielddata?fields=field_name

# 清理字段数据缓存
POST /<index>/_cache/clear?fielddata=true

# 使用 doc_values 而不是 fielddata
PUT /<index>/_mapping
{
  "properties": {
    "field": {
      "type": "keyword",
      "doc_values": true
    }
  }
}

6. 减少聚合精度 #

# 使用 cardinalinality 近似聚合
GET /<index>/_search
{
  "aggs": {
    "unique_count": {
      "cardinality": {
        "field": "field",
        "precision_threshold": 100
      }
    }
  }
}

7. 分批处理大量数据 #

# 使用 update_by_query 分批处理
POST /<index>/_update_by_query?conflicts=proceed&scroll_size=1000
{
  "query": {
    "range": {
      "timestamp": {
        "gte": "2023-01-01"
      }
    }
  },
  "script": {
    "source": "ctx._source.new_field = 'value'"
  }
}

8. 增加 JVM 堆内存 #

如果频繁触发断路器,考虑增加堆内存:

# 修改 config/jvm.options
-Xms16g
-Xmx16g

# 注意:堆内存不应超过 31GB,且应为物理内存的 50% 左右

9. 使用 search_after 代替深度分页 #

# 使用 search_after 进行深度分页
GET /<index>/_search
{
  "size": 100,
  "query": { "match_all": {} },
  "sort": [
    {"date": "asc"},
    {"_id": "asc"}
  ],
  "search_after": [1625097600000, "doc_id"]
}

10. 监控内存使用 #

# 查看节点内存使用
GET /_nodes/stats/jvm?human&pretty

# 查看字段数据使用
GET /_cat/fielddata?v&fields=*

预防措施 #

  • 合理设置断路器限制(通常为堆内存的 40-70%)
  • 使用 doc_values 而不是 fielddata
  • 避免在文本字段上使用聚合或排序
  • 使用 search_after 或 scroll API 代替深度分页
  • 使用 composite aggregation 处理大量桶
  • 定期清理不需要的缓存
  • 监控断路器状态,及早发现问题
  • 对大型操作进行分批处理
  • 考虑使用更小的时间窗口进行数据聚合