ES:数据一致性/和Lucene关系/中文分词/最小主节点与脑裂/路由选定特定节点/更删文档过程

这次面试的后半段,面试官抛出了一系列更深入的问题,涉及数据一致性、底层关系、中文分词、脑裂场景、客户端连接以及更新删除流程。以下是我对这些问题的回答复盘,整理成博客记录下来,也方便自己查漏补缺。

1. ES 如何保证数据一致性

面试官问:"ES 是怎么保证数据一致性的?"这个问题让我稍微停顿了一下,因为一致性在分布式系统中是个大话题。我整理了一下思路,回答如下:

ES 作为一个分布式系统,主要通过以下机制保证数据一致性:

  • 主分片与副本同步

    我提到,ES 的数据写入是先写主分片(Primary Shard),成功后再同步到副本分片(Replica Shard)。客户端可以设置 wait_for_active_shards 参数,确保一定数量的副本可用后再返回成功,这样提高了数据可靠性。

  • 版本控制

    每个文档都有一个版本号(_version),基于乐观锁机制。每次更新时,ES 会检查版本号是否匹配,如果不一致就拒绝操作,避免并发修改导致的数据覆盖。

  • 集群状态同步

    Master 节点负责维护全局的集群状态(Cluster State),包括分片分配和索引元数据。状态变更会广播到所有节点,确保大家看到的集群信息一致。如果 Master 挂了,新选举的 Master 会接管并同步状态。

面试官追问:"一致性是强一致性吗?"我说不是,ES 默认是最终一致性,因为副本同步有延迟。但可以通过参数调整(比如 refresh=wait_for)接近强一致性。这部分我觉得自己答得还算清晰,但可以再补充一些参数的实际应用场景。

2. ES 和 Lucene 的关系

接着面试官问:"ES 和 Lucene 什么关系?"这个问题相对简单,我之前正好复习过。

我回答说,ES 是建立在 Apache Lucene 之上的分布式搜索引擎。Lucene 是核心库,提供了底层的索引和搜索能力,比如倒排索引、查询解析和评分模型。ES 在 Lucene 上封装了一层分布式框架,增加了集群管理、分片、副本、REST API 等功能。简单来说,Lucene 是单机引擎,ES 把它扩展成了分布式系统。

面试官点了点头,没追问。我觉得自己这部分答得简洁明了,但如果能举个例子(比如 Lucene 的 FST 在 ES 中的应用),会更有说服力。

3. 分析 ES 的中文分词

第三个问题是:"ES 的中文分词是怎么处理的?"这个问题挺有针对性,因为中文分词和英文分词差异很大。

我回答说,ES 的分词依赖分析器(Analyzer),而中文分词需要专门的分词器。ES 默认没有内置中文分词器,但可以通过插件集成,比如常用的 IK 分词器

  • 分词原理

    中文不像英文有天然的空格分隔,IK 分词器会基于词库和算法把句子切分成词。比如"中华人民共和国"可以分成"中华""人民""共和国"。它支持两种模式:ik_smart(智能模式,粗粒度)和 ik_max_word(最大词量,细粒度)。

  • 配置与优化

    我提到,分词效果可以通过自定义词库优化,比如添加行业术语,或者停用词表过滤无意义的词。ES 的 Mapping 中可以指定字段用哪个分词器,搜索时会用同样的分词逻辑匹配。

面试官问:"分词对搜索性能有啥影响?"我说,分词越细,索引体积越大,查询时匹配的词也多,可能降低性能,但召回率会更高。我觉得自己这部分答得还可以,但没提到 HMM 模型或者 N-Gram,可能是个遗漏。

4. ES 的节点有 20 个,其中 10 个选了一个 Master,另外 10 个选了另一个 Master 怎么办?

这个问题让我有点紧张,因为它直指脑裂(Split Brain)问题。我尽量冷静地回答:

我说,这种情况说明集群发生了网络分区,导致 20 个节点分裂成两部分,每部分选了自己的 Master。这是典型的脑裂问题。ES 通过以下机制处理:

  • 最小主节点数(minimum_master_nodes)

    我提到,ES 有个参数 discovery.zen.minimum_master_nodes,通常设为集群节点数的一半加一(比如 20 个节点设为 11)。选举 Master 时,必须有至少这个数量的节点支持。如果分裂成 10 和 10,双方都达不到 11 个节点的支持,就不会有合法的 Master,集群会暂停工作,直到网络恢复。

  • 解决办法

    如果脑裂真的发生了(比如参数没设好),需要人工介入,检查网络问题,合并集群,或者重启一部分节点让它们加入正确的 Master。

面试官问:"怎么预防?"我说,除了设置合理的 minimum_master_nodes,还得确保网络稳定,避免频繁分区。这部分我觉得答得不够深入,下次可以提一下仲裁节点(Arbiter)的概念。

5. ES 的客户端在和集群连接时,怎么选择特定的节点执行请求?

这个问题考察客户端和集群的交互,我之前看过 Java 客户端的源码,回答起来还算有底气。

我说,ES 客户端(比如 Java High-Level REST Client)连接集群时,通常会配置一个节点列表。选择节点的逻辑是这样的:

  • 节点发现

    客户端初始化时会通过配置的节点地址获取集群信息,包括所有数据节点的列表(嗅探机制,Sniffing)。之后客户端会动态维护这个列表。

  • 负载均衡

    请求发送时,客户端会用轮询(Round-Robin)或者随机的方式从可用节点中挑一个,避免单点压力。如果某个节点挂了,客户端会自动剔除它,尝试其他节点。

  • 特定节点选择

    如果请求有特殊需求(比如只查某个分片),客户端会根据路由信息(Routing)选择对应的节点。但一般情况下,客户端把请求发给一个协调节点(Coordinating Node),由它分发。

面试官没追问,我觉得这部分答得还行,但可以再补充一下嗅探的配置细节。

6. 详细描述 ES 的更新和删除文档的过程

最后一个问题是:"ES 更新和删除文档的过程是怎样的?"这个问题让我回忆了一下 ES 的写操作流程。

我回答说,ES 的更新和删除都是基于"先标记,后重建"的逻辑,因为 Lucene 的索引是不可变的。详细过程如下:

  • 更新文档

    1. 客户端发送更新请求(比如 PUT /index/_doc/1),带上新内容。
    2. 请求到达协调节点,路由到对应的主分片。
    3. 主分片拿到请求后,先标记旧文档为"已删除"(逻辑删除),然后把新文档写入内存缓冲区(Buffer)。
    4. 缓冲区满了或者触发刷新(Refresh,默认 1 秒),新文档写入新的段文件(Segment),生成倒排索引。
    5. 主分片同步到副本分片,完成后返回成功。
    6. 旧文档在合并(Merge)时才会被物理删除。
  • 删除文档

    1. 客户端发送删除请求(比如 DELETE /index/_doc/1)。
    2. 协调节点路由到主分片,主分片标记文档为"已删除",写入 .del 文件。
    3. 同步到副本分片,返回成功。
    4. 物理删除也在段合并时完成。

面试官问:"为什么不直接删?"我说因为 Lucene 的索引是只读的,直接改代价太高,所以用追加和标记的方式。这部分我觉得自己答得挺完整,但可以再提一下 refresh_interval 对性能的影响。


总结

这次面试让我对 ES 的分布式特性和底层机制有了更深的认识。数据一致性、脑裂和更新流程是我回答时稍显薄弱的地方,下次得重点复习这些点,尤其是参数调优和异常场景的处理。整体来说,面试过程还算顺利,但细节决定成败,得继续努力!

相关推荐
pengyu10 分钟前
【Java设计原则与模式之系统化精讲:壹】 | 编程世界的道与术(实战指导篇)
java·后端·设计模式
陈随易13 分钟前
一行代码,将网页元素变成图片!比 html2canvas 快 93 倍的截图神器来了!
前端·后端·程序员
Kookoos14 分钟前
性能剖析:在 ABP 框架中集成 MiniProfiler 实现性能可视化诊断
后端·c#·.net·abp vnext·miniprofiler
掉头发的王富贵16 分钟前
Arthas神器入门:动态调试Java应用,轻松搞定生产环境Bug!
java·后端·debug
汪子熙19 分钟前
解密 Fabric 体系 —— 架构与实践全解析
后端
oraen22 分钟前
一篇文章让你在根本上理解遗传算法,用牛刀杀鸡-使用遗传撕力扣
后端
程序员爱钓鱼23 分钟前
Go语言并发模型与模式:Worker Pool 模式
后端·go·排序算法
Victor35624 分钟前
MySQL(66)如何进行慢查询日志分析?
后端
程序小武24 分钟前
深入理解Python内置模块及第三方库的使用与管理
后端
陈随易26 分钟前
2025年100个产品计划之第12个(杰森排序) - 对 JSON 属性进行排序
前端·后端·程序员