Elasticsearch 从入门到精通:术语、索引、分片、读写流程与面试高频题一文搞懂

1. 核心术语

术语 含义说明
Index(索引) 是数据存储的逻辑单元,类似于数据库中的"表"。用户将数据写入某个 Index,每个 Index 可以被划分为多个分片。在 Elasticsearch 7.x 之后,默认每个索引只有一个主分片类型(_doc),且不再支持多类型(types)。
Shard(分片) 将一个 Index 的数据拆分成多个部分,实现分布式存储。一个 Index 至少要有一个主分片。每个分片是一个独立的搜索引擎实例(Lucene 实例)。
Primary Shard(主分片) 每个文档必须属于一个主分片。主分片负责处理所有的写操作,并将数据变更同步到副本分片。
Replica Shard(副本分片) 主分片的拷贝,提供数据冗余、高可用和读负载均衡。副本分片仅处理读请求(如 Get、Search),不接受写入。
Document(文档) 实际存储的数据,是 JSON 格式的对象,是 ES 中最小的数据单元。每个文档有唯一 _id,并归属于某个 _index

2. 分片详解

✅ 主分片(Primary Shard)

  • 每个文档必须属于一个主分片。
  • 数据写入时,先写入主分片,再同步到副本。
  • 数量在创建索引时指定,不可更改

📌 分片分配原则

文档通过哈希算法决定写入哪个主分片:
shard_num = hash(_routing) % number_of_primary_shards

其中 _routing 默认为文档的 _id,也可自定义(如 user_id)。

⚠️ 一旦主分片数确定,后续无法修改,否则哈希结果变化会导致数据无法定位。

✅ 副本分片(Replica Shard)

  • 提供高可用性和负载均衡。
  • 可随时增加或减少副本数量(通过 _settings API)。
  • 如果主分片损坏,副本可被提升为新的主分片。

⚠️ 注意:

  • 一个分片默认有 0 个副本。
  • 推荐生产环境至少设置 1 个副本,防止节点故障导致数据丢失。

3. 集群状态颜色(Cluster Health)

颜色 状态 含义
Green(绿色) ✅ 健康 所有主分片和副本分片都正常工作。
Yellow(黄色) ⚠️ 亚健康 所有主分片正常,但部分副本分片异常或未分配。可能导致数据丢失风险(无副本保护)。
Red(红色) ❌ 不健康 有主分片无法正常访问,部分数据不可用。

4. 高可用与容错机制(推荐奇数节点)

Elasticsearch 集群依赖多数派(Quorum)机制选举主节点(Master Node),确保集群元数据一致性和可用性。

容忍 N 台机器故障,至少需要 2N + 1 个主候选节点(master-eligible nodes)

✅ 容错能力对照表

节点总数 最大可容忍故障数 说明
1 0 单点故障,不推荐
2 0 平票,无法形成多数派
3 1 推荐最小高可用集群
5 2 生产常用规模
6 2 成本高,无优势
7 3 大型集群常用

✅ 为什么推荐奇数节点?

  • 避免脑裂(Split Brain):奇数节点更容易形成多数派(>50%),避免两个分区各自认为自己是主集群。
  • 成本最优:5 节点和 6 节点容错能力相同(最多容忍 2 台故障),但 6 节点成本更高。
  • 运维简单:奇数节点更直观,便于规划。

📌 最佳实践

  • 生产环境建议部署 3 或 5 个专用主候选节点node.roles: [master])。
  • 数据节点可为偶数,但主候选节点组应为奇数。
  • 正确配置 discovery.seed_hostscluster.initial_master_nodes

5. 文档写入流程(Indexing 流程)

当你使用 PUT /index/_doc/1 插入文档时,Elasticsearch 经历以下步骤:

✅ 1. 客户端请求

客户端发送请求到任意节点(该节点成为"协调节点")。

bash 复制代码
PUT /my-index/_doc/1
{
  "name": "Tom",
  "age": 25
}

✅ 2. 路由(Routing)

协调节点根据文档的 _id(或自定义路由字段)决定该文档属于哪个 主分片(Primary Shard)

  • Elasticsearch 默认使用公式:

    shard_num = hash(_id) % primary_shard_count

✅ 3. 写入主分片

协调节点将请求转发给主分片所在节点:

  1. 写入 Translog(事务日志) → 保证持久化(可配置是否立即刷盘)
  2. 更新 In-Memory Buffer → 缓存待索引文档
  3. (可选)通过 refresh=true 强制刷新,使文档可搜索

默认每秒执行一次 refresh,将 Buffer 中的文档刷新到 倒排索引(Lucene Segment),使其可搜索。

✅ 4. 同步副本分片

主分片写入成功后,协调节点将请求同步复制到所有副本分片节点(默认同步等待):

  • 副本节点同样执行:写 Translog + 更新 Buffer
  • 副本也会定期 refresh,但不保证与主分片完全同步

可通过 ?replication=async 改为异步复制(不推荐,降低一致性)

✅ 5. 返回成功响应

当主分片和 足够数量的副本分片 (由 write consistency 决定)都确认写入后,协调节点返回成功。

consistency 可设为:one(主分片)、quorum(多数)、all(全部副本)

这是一个非常关键的问题!Elasticsearch 并不是必须"所有副本写入成功"才算整体写入成功。是否成功,取决于你设置的 写一致性级别(Write Consistency) ,也叫 写关注(Write Concern)


✅ 6.写入成功的判定标准:由 consistency 参数决定

当你执行一个写操作(如 PUT /index/_doc/1),可以通过 URL 参数指定 consistency,它决定了需要多少个分片副本确认写入,协调节点才向客户端返回成功。

三个可选值:
值(consistency 含义说明
one 只要主分片 写入成功即可返回。最快,但最不安全(副本可能未同步,主分片宕机则数据丢失)。
quorum (默认) 必须有多数派(quorum) 的分片写入成功。这是默认且最常用的设置。
all 必须所有分片 (主分片 + 所有副本分片)都写入成功才返回。最安全,但最慢,任何一个副本失败都会导致写入失败。

quorum(多数派)是如何计算的?

quorum = int((primary + replica) / 2) + 1

也就是说:超过一半的分片必须成功。

📌 举几个例子:

主分片数 副本数 总分片数(主+副) quorum 要求成功数 写入成功的最小成功数
1 1 2(1主+1副) (1+1)/2 + 1 = 2 2(主+副都成功)
1 2 3(1主+2副) (1+2)/2 + 1 = 2 2(主+至少1个副)
3 1 6(3主+3副) (3+3)/2 + 1 = 4 4(每个主分片组至少2个成功)

💡 关键点 :Elasticsearch 是按 每个主分片及其副本组 来计算 quorum 的,而不是整个索引。


✅ 举个实际例子

假设你有一个索引:

  • number_of_primary_shards: 1
  • number_of_replicas: 2 (即有 2 个副本分片)

那么总共有 3 个分片(1主 + 2副)。

  • quorum = (1 + 2) / 2 + 1 = 2.5 → 取整为 2?
  • 正确计算quorum = int((primary_count + replica_count) / 2) + 1 = int(3/2) + 1 = 1 + 1 = 2

所以,只要 主分片 + 至少一个副本分片 写入成功,协调节点就会返回成功。

✅ 即使有一个副本分片失败或延迟,写入仍然成功。


✅ 总结:写入多少才算成功?
场景 成功条件
consistency=one 主分片成功即可
consistency=quorum(默认) 主分片 + 多数派副本 成功(即 int((primary+replica)/2) + 1
consistency=all 主分片 + 所有副本都必须成功

📌 生产环境建议
  • 绝大多数场景使用默认 quorum:在性能、可用性和数据安全之间取得了最佳平衡。
  • 高安全场景 (如金融交易日志):可考虑 all,但要接受性能下降和更高的失败率。
  • 高吞吐写入场景 (如日志采集):可使用 one + 异步处理,但需接受一定的数据丢失风险。

🔍 附加说明:replication=async 参数

你提到的 ?replication=async 是旧版本(v1.x)的参数,在新版本中已被废弃

现在的复制行为由 consistency 和集群配置决定,复制本身在 quorum 模式下是同步阻塞的(协调节点会等待足够数量的副本响应),但这个"同步"是为了保证一致性,并不意味着所有副本必须同时完成。


一句话概括

写入成功 = 主分片成功 + 满足 consistency 规则的副本数量成功 ,不一定要所有副本都成功。默认 quorum 模式下,只要"多数派"成功即可。


6. 文档读取流程(Search / Get 流程)

Elasticsearch 支持两种读取方式:

  • Get API :根据文档 ID 获取单个文档(如 GET /index/_doc/1
  • Search API :根据条件搜索多个文档(如 POST /index/_search

✅ 1. Get API 流程(根据 ID 查询)

bash 复制代码
GET /my-index/_doc/1

步骤

  1. 协调节点接收请求
  2. 根据 _id 计算目标分片(主或副本)
  3. 使用轮询策略选择一个可用分片节点(实现负载均衡)
  4. 分片节点从 Lucene 读取文档(默认实时查询,合并内存更新)
  5. 返回结果

✅ 优势:Get 是 实时(real-time) 操作,即使文档刚写入未 refresh 也能读到。


bash 复制代码
POST /my-index/_search
{
  "query": { "match_all": {} }
}

分为两个阶段:

阶段一:查询(Query Phase)
  1. 协调节点将查询广播到索引的每个分片(主或副本)
  2. 每个分片本地执行查询,返回 Top N 文档 ID + 分数
  3. 协调节点合并结果,进行全局排序、分页
阶段二:取回(Fetch Phase)
  1. 协调节点根据排序后的文档ID,向包含这些文档的分片发送请求
  2. 分片返回完整文档内容
  3. 协调节点组装最终结果并返回

⚠️ 深分页(如 from=10000)性能差,建议使用 search_afterscroll


7. 关键概念补充

概念 说明
Translog(事务日志) 写入时先写日志,用于故障恢复和 refresh 前的数据持久化。可通过 index.translog.durability 控制刷盘策略。
Refresh 将内存 Buffer 内容刷新到 Lucene Segment,使其可搜索。默认 1s 一次,可配置 refresh_interval
Flush 将内存 Buffer 和 Translog 写入磁盘,生成新的 Segment 并清空 Translog。默认 30min 或 Translog 过大时触发。
副本一致性(Consistency) 控制写入需多少分片确认:one / quorum(默认)/ all
副本读取(Replica Read) Get/Search 可从副本读取,实现读负载均衡。协调节点自动轮询选择。

8. 总结:写流程 vs 读流程

阶段 写流程(Indexing) 读流程(Search/Get)
定位分片 通过 _id 路由到主分片 通过 _id 或广播到所有分片
主分片操作 写 Translog + Buffer 从 Lucene 读取
副本操作 同步复制(默认 quorum 可从副本读取(负载均衡)
响应确认 主分片 + 足够副本成功 返回查询结果
实时性 默认异步(1s refresh),可 refresh=true 强制 Get 实时,Search 依赖 refresh 间隔

9. 面试题彩蛋(高频考点)

🔹 Q1: ES 集群的 9200 和 9300 端口分别有什么作用?

端口 协议 用途
9200 HTTP RESTful API 端口,用于数据操作(CRUD)、集群管理等。
9300 TCP 节点间通信端口,用于集群内部节点之间的交互(如发现、选举、数据传输等),通常用于 Java 客户端连接。

🔹 Q2: ES 集群的几种颜色代表什么含义?

已在上文"集群状态颜色"中详细说明。


🔹 Q3: 主分片和副本分片的区别是什么?

对比项 主分片(Primary Shard) 副本分片(Replica Shard)
写操作 ✅ 支持 ❌ 不支持
读操作 ✅ 支持 ✅ 支持
数据来源 原始写入数据 来自主分片的复制
数量限制 创建时指定,不能修改 可动态调整
故障恢复 不可替代 可升级为新的主分片

🔹 Q4: 如何理解 Elasticsearch 中文档的"不可变"特性?

  • 文档一旦写入主分片,就不可直接修改。
  • 更新操作实际上是:删除旧文档 + 插入新版本文档。
  • 这是为了保证副本的一致性与性能优化。文档写入后,底层 Lucene 不允许修改,只能标记删除。更新操作本质是:先标记旧文档为"已删除",再写入新版本文档。删除和更新操作会在后续的 Segment Merge 过程中被物理清理。

10. 温馨提示 / 最佳实践

  • 📌 一个索引最少要有 一个主分片
  • 📌 建议生产环境至少设置 1 个副本,提高可用性。
  • 📌 分片数创建后 不能更改,需根据数据量预估(如每分片 30-50GB)。
  • 📌 副本数可动态调整:PUT /index/_settings { "number_of_replicas": 2 }
  • 📌 避免过多分片(如 > 1000),会增加集群开销。
  • 📌 使用 _cat/health_cat/shards 监控集群状态。
  • 📌 对于日志类场景,可关闭自动 refresh("refresh_interval": -1)以提升写入性能。
相关推荐
天氰色等烟雨2 分钟前
Antlr4入门学习及实用案例(二)
大数据
天氰色等烟雨3 分钟前
Antlr4入门学习及实用案例(一)
大数据
武子康3 分钟前
大数据-57 Kafka 高级特性 Producer 消息发送流程与核心配置详解
大数据·后端·kafka
Ms_lan4 分钟前
邢台市某区人民医院智慧康养平台建设项目案例研究
大数据·人工智能·物联网·蓝牙网关·桂花网
知其然亦知其所以然4 分钟前
MySQL社招面试题:索引有哪几种类型?我讲给你听的不只是答案!
后端·mysql·面试
白鲸开源12 分钟前
从日志到告警,带你用好 SeaTunnel 的事件监听能力
大数据·数据分析·开源
王中阳Go13 分钟前
灵活分库分表,面试的时候这么说,加分!
后端·面试
Entropless18 分钟前
我想纠正99.9%的人对协程的认知!
面试
charlie11451419141 分钟前
计算机网络八股文——TCP,UDP
网络·网络协议·tcp/ip·计算机网络·面试·udp·八股文
Fireworkitte1 小时前
es的histogram直方图聚合和terms分组聚合
大数据·elasticsearch·搜索引擎