面试知识库
困难

ES性能调优#

一句话答案#

ES 调优三板斧:写入优化(bulk 批量 + refresh_interval 调大 + 关闭副本)、查询优化(filter 缓存 + routing 避免跨分片 + search_after 替代深分页)、集群优化(分片规划 + 冷热分离 + JVM 堆 ≤ 31GB)。

核心要点

写入优化#

手段效果场景
Bulk 批量写入减少网络开销所有写入场景
refresh_interval: ”30s”减少 segment 生成频率写入量大时
number_of_replicas: 0写入时不同步副本全量导入阶段
translog.durability: async异步刷盘允许少量丢失
合理 Mapping不需要搜索的字段设 index:false所有场景
// 全量导入时的临时设置
PUT /my_index/_settings
{
  "refresh_interval": "-1",
  "number_of_replicas": 0
}

// 导入完成后恢复
PUT /my_index/_settings
{
  "refresh_interval": "1s",
  "number_of_replicas": 1
}
json

查询优化#

深分页问题#

from + size 的问题:
  from=10000, size=10
  → 每个 Shard 取 Top 10010
  → Coordinating 节点合并 5×10010=50050 条
  → 取第 10001-10010 条
  → 内存爆炸 + 响应慢

解决方案:
  方案1: search_after (推荐)
    {"search_after": [上一页最后一条的 sort value], "size": 10}
    → 每个 Shard 只取 10 条

  方案2: Scroll API (废弃中,用 PIT 替代)
    适合全量导出,不适合实时搜索
plaintext

集群级优化#

JVM 设置:
  -Xms 和 -Xmx 设为相同(避免 resize)
  堆内存 ≤ 31GB(超过则无法用 Compressed OOP,浪费内存)
  建议给 OS 留一半内存(Page Cache 缓存 Lucene 文件)

分片规划:
  单 Shard: 10-50GB
  每 GB heap 最多 20 个 Shard
  避免超大 Shard(恢复慢)和超多小 Shard(Master 压力大)

冷热分离:
  热数据 → SSD 节点(node.attr.box_type: hot)
  冷数据 → HDD 节点(node.attr.box_type: cold)
  通过 ILM (Index Lifecycle Management) 自动迁移
plaintext

Segment Merge 优化#

问题:大量小 Segment 影响查询性能(每次查询需要遍历所有 Segment)

策略:
  - max_num_segments: force merge 到指定数量(写入完成后执行)
  - merge.scheduler.max_thread_count: 控制合并线程数
  - 不在高峰期做 force merge

POST /my_index/_forcemerge?max_num_segments=1
plaintext
面试回答(2分钟版)

ES 调优分写入和查询两方面。写入优化:用 bulk 批量提交减少网络开销,全量导入时把 refresh_interval 设为 -1 且副本设为 0,导完再恢复,吞吐量可以提升数倍。查询优化:不需要评分的过滤条件放 filter(有 Bitset 缓存),按 routing 路由避免全分片扫描,深分页必须用 search_after 替代 from+size(否则每个分片取 from+size 条再合并,内存爆炸)。集群层面:JVM 堆不超过 31GB(Compressed OOP 边界),给 OS 留一半内存用于 Page Cache 缓存 Lucene 文件。冷热分离用 ILM 自动管理——热数据在 SSD,超过 7 天移到 HDD。Segment 合并在低峰期 force merge 减少 segment 数量提升查询效率。

追问与易错

追问方向:

  • “为什么堆不能超过 31GB?”→ JVM Compressed OOP 临界点,超过后指针从 4 字节变 8 字节,等效容量反而下降
  • “深分页为什么慢?”→ 每个 Shard 都要取 from+size 条做全局排序,Shard 越多越慢
  • “怎么监控 ES 性能?”→ _cat/nodes, _cat/shards, _nodes/stats + Prometheus/Grafana
  • “force merge 有什么风险?”→ IO 密集,高峰期做会影响查询,且不可中断

易错点:

  • ❌ “堆内存越大越好”——超过 31GB 性能反而下降(失去 Compressed OOP)
  • ❌ “search_after 能跳页”——只能逐页向后翻,不支持跳到第 N 页
  • ❌ “refresh_interval=0 就是实时”——0 不是关闭,-1 才是关闭;0 表示每次写入都 refresh(性能极差)