一、实战经验与架构设计
1. 【高频】请介绍你们公司 ES 的集群架构、数据规模及调优手段
考察点:真实项目经验、大规模数据处理能力、调优意识。
参考回答 :
我们线上 ES 集群共 13 个节点 (混合角色),管理 20+ 业务索引 ,按通道和日期划分,每日新增 20+ 索引 ,总数据量 日增 1 亿+ 条 ,单索引控制在 150GB 以内 ,分片数设为 10。
索引层面调优:
-
设计阶段:
- 基于日期模板 +
rolloverAPI 滚动创建索引; - 使用别名(alias)统一访问入口;
- 冷热分离:热数据存 SSD,冷数据定期
shrink+force_merge; - 用 Curator 自动化生命周期管理(删除/合并/归档);
- Mapping 精细化:仅对需检索字段启用
index: true,合理选择分词器。
- 基于日期模板 +
-
写入调优:
- 写前:副本数设为 0,
refresh_interval = -1; - 使用
bulk批量写入(每批 5--15MB); - 写后恢复副本和刷新间隔;
- 尽量使用自动生成 ID(避免版本冲突开销)。
- 写前:副本数设为 0,
-
查询调优:
- 禁用
wildcard和超大terms查询; - 高频字段用
keyword类型(利用倒排索引); - 先按时间范围锁定索引,再执行查询;
- 合理设置
_routing减少分片扫描。
- 禁用
-
部署调优:
- 主数据节点分离;
- SSD 存储 + RAID10;
- 监控 + 告警体系完善。
二、核心原理
2. 什么是倒排索引?
通俗解释 :
传统检索是"文章 → 词",而倒排索引是"词 → 文章"。它通过分词建立词典 + 倒排表,实现 O(1) 级别快速定位文档。
加分项 :
Lucene 4+ 使用 FST(Finite State Transducer) 存储词典:
- 空间小:共享前缀/后缀;
- 查询快:O(len(str)) 时间复杂度。
3. Master 选举机制是如何实现的?
ES 使用 ZenDiscovery 模块(7.x 后改为基于 Raft 的新协调层,但原理类似):
- 仅
node.master: true的节点可参选; - 所有候选节点按
nodeId字典序排序; - 每个节点投票给排序第一的节点;
- 若某节点得票 ≥
n/2 + 1且自己也投自己,则当选; - 通过
discovery.zen.minimum_master_nodes(旧版)或cluster.initial_master_nodes(新版)防脑裂。
⚠️ Master 节点只负责集群管理,不处理数据读写。
4. 如何解决脑裂问题?
- 候选主节点 ≥ 3 时,设置
minimum_master_nodes = (n/2)+1; - 候选节点 = 2 时,应改为 1 主 + 1 数据节点,避免对等选举。
5. 文档写入(索引)过程
单文档写入流程:
- 客户端请求任意节点(协调节点);
- 协调节点根据
_id(或_routing)计算目标分片:
shard = hash(_routing) % primary_shard_count; - 请求转发至主分片所在节点;
- 主分片写入成功后,并行转发至所有副本分片;
- 所有副本返回成功,协调节点向客户端确认。
底层细节:
- 数据先入 Memory Buffer;
- 每 1s
refresh到 Filesystem Cache(近实时可见); - 同时写入 translog 保证持久性;
- 每 30min 或 translog 达 512MB 触发
flush,落盘并清空 translog。
6. 搜索过程(Query Then Fetch)
分两阶段:
① Query 阶段:
- 广播到所有相关分片(主或副本);
- 每个分片本地查询,构建
from + size大小的优先队列(含 doc_id + score); - 返回结果给协调节点,合并成全局排序列表。
② Fetch 阶段:
- 协调节点向对应分片发起
GET请求; - 分片加载完整文档并返回;
- 最终结果返回客户端。
💡 近实时性源于 Filesystem Cache;DFS Query Then Fetch 可提升打分准确性(但性能差)。
7. 文档更新与删除机制
- ES 文档不可变;
- 删除 :在
.del文件中标记,段合并时物理清除; - 更新:旧文档标记删除,新文档写入新段(带新版本号)。
三、性能调优与运维
8. 【高频】大数据量下如何调优与部署?
- 动态索引:模板 + rollover,避免单索引过大(>TB);
- 冷热分离 :
- 热数据(近 3--7 天):SSD,高副本;
- 冷数据:定期
force_merge+shrink(减少分片数);
- 部署扩展:动态加节点(无需重启),主节点规划合理;
- 生命周期管理:Curator 自动清理过期索引。
9. Linux 系统级优化建议
- 关闭 swap:防止内存交换导致性能雪崩;
- 堆内存 ≤ 32GB 且 ≤ 物理内存 50%(留内存给 Lucene);
- 增大文件描述符 :
ulimit -n 65536; - 使用 SSD:显著提升 I/O 性能;
- 避免跨机房部署:网络延迟影响集群稳定性;
- 禁用组播,使用单播发现;
- 谨慎调整线程池和 GC(默认 CMS 较稳)。
10. 写入性能优化手段
bulk批量写入(5--15MB/批);- 写前:
number_of_replicas=0,refresh_interval=-1; - 写后恢复配置;
- 使用自动生成 ID;
- 提高
translog.flush_threshold_size(如 1GB); - SSD + 关闭合并限流(批量导入场景)。
11. 查询性能优化建议
- 避免
wildcard、regexp、超大terms; - 高频过滤字段用
keyword; - 先按时间范围缩小索引集;
- 合理使用
_routing定向查询; - 不需要近实时?
refresh_interval=30s。
12. GC 与内存注意事项
- 监控 Segment Memory(无法 GC);
- 合理设置各类缓存(field/filter/indexing cache);
- 避免返回大量结果:用
scroll替代深度分页; - 超大集群考虑拆分 + Tribe Node;
- 配置 Circuit Breaker 防 OOM。
四、高级特性与扩展
13. 大数据量聚合如何实现?
- 使用 近似算法 ,如
cardinality(基于 HLL); - HLL 特点:
- 内存固定,与数据量无关;
- 可配置精度(精度↑ → 内存↑);
- 小数据集精度极高。
14. 如何保证读写一致性?
- 写一致性 :默认
quorum(多数分片写入成功); - 读一致性 :
- 默认同步复制(主+副本都完成才返回);
- 或查询时指定
_preference=primary读主分片;
- 乐观锁 :通过
_version控制并发更新。
15. 如何监控集群状态?
- 官方方案:Elastic Stack(Kibana + Monitoring);
- 开源替代:Prometheus + Elasticsearch Exporter;
- 关键指标:集群健康(green/yellow/red)、JVM 内存、CPU、分片分布、慢查询日志。
16. 个性化搜索方案(电商场景)
- 基于 Word2Vec 训练商品/用户行为向量;
- 在 ES 中存储向量,结合脚本评分(script_score)实现语义召回;
- 效果:点击率 & 转化率显著提升;
- 延伸:可用于"相似商品推荐";
- 局限:仅依赖点击序列,未融合多维用户画像。
五、数据结构与算法
17. 字典树(Trie)了解吗?
- 核心思想:空间换时间,利用公共前缀加速查询;
- 性质 :
- 根节点无字符;
- 路径 = 字符串;
- 子节点字符互异。
- 中文优化:子节点用 HashMap 存储,查询 O(1)。
18. 拼写纠错如何实现?
- 基于 编辑距离(插入/删除/替换最小步数);
- 构建 BK 树(Burkhard-Keller Tree) :
- 节点间边权 = 编辑距离;
- 查询时剪枝:仅遍历
[d-n, d+n]范围内的子树;
- 满足度量空间三定律(非负、对称、三角不等式)。
六、补充知识
19. Lucene 内部结构
- 索引过程:文档 → 分词 → 倒排索引(Segment);
- 搜索过程:查倒排表 → 打分(TF-IDF/BM25)→ 排序;
- Segment 特性 :
- 不可变,支持增量写入;
- 多 Segment 影响查询性能;
- 后台自动合并(merge)。
20. Elasticsearch 是什么?
一个分布式、RESTful 的全文搜索与分析引擎,特点:
- 快:近实时搜索;
- 可扩展:从单机到 PB 级集群;
- 灵活:支持结构化、非结构化、地理、指标数据;
- 生态强:与 Hadoop/Spark/Kibana 无缝集成。
21. 典型应用场景
- 电商商品搜索 + 自动补全;
- 日志分析(ELK);
- 价格监控 + Percolator 反向搜索;
- BI 报表 + Kibana 可视化。
22. 客户端如何连接集群?
- TransportClient(已弃用):轮询连接初始化地址;
- RestHighLevelClient(推荐):基于 HTTP,轻量、兼容云服务。