当前位置: 首页 > news >正文

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)

✅ 容错能力对照表

节点总数最大可容忍故障数说明
10单点故障,不推荐
20平票,无法形成多数派
31推荐最小高可用集群
52生产常用规模
62成本高,无优势
73大型集群常用

✅ 为什么推荐奇数节点?

  • 避免脑裂(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. 客户端请求

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

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 要求成功数写入成功的最小成功数
112(1主+1副)(1+1)/2 + 1 = 22(主+副都成功)
123(1主+2副)(1+2)/2 + 1 = 22(主+至少1个副)
316(3主+3副)(3+3)/2 + 1 = 44(每个主分片组至少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 查询)

GET /my-index/_doc/1

步骤

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

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


✅ 2. Search API 流程(搜索查询)

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 端口分别有什么作用?

端口协议用途
9200HTTPRESTful API 端口,用于数据操作(CRUD)、集群管理等。
9300TCP节点间通信端口,用于集群内部节点之间的交互(如发现、选举、数据传输等),通常用于 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)以提升写入性能。
http://www.dtcms.com/a/305041.html

相关文章:

  • 青少年软件编程图形化Scratch等级考试试卷(四级)2025年6月
  • SZU大学物理实验报告|电位差计
  • 赋能低空未来|迪捷软件亮相2025国际低空经济博览会
  • 【tips】小程序css ➕号样式
  • Three.js 性能优化全面指南:从几何体合并到懒加载资源
  • OpenLayers 综合案例-台风风场模拟
  • MIAOYUN参编信通院《大模型API服务性能测试标准》
  • 营销活动效果分析与策略优化
  • 【JVM】常见的 Java 垃圾回收算法以及常见的垃圾回收器介绍及选型
  • ARM7微处理器的核心优势
  • Docker入门基础使用
  • 【vue(2)插槽】
  • ZKmall开源商城中台架构实践:API 网关与服务治理如何撑起电商技术骨架
  • vue3实战九、vue3+vue-cropper实现头像修改
  • 【Linux】批量处理多个用户的 sudo 权限问题
  • 【STM32开发】-基础开发笔记(STM32F103,HAL库开发)
  • 【ComfyUI学习笔记04】案例学习:局部重绘 - 上
  • 墨者:XPath注入漏洞实战
  • 第二十五节 MATLAB矩阵的加法和减法、除法(左,右)矩阵
  • Arduino声控RGB矩阵音乐节奏灯DIY全攻略
  • 解密数据结构之二叉树
  • Android11平台下rk3568的ATGM332D定位模块适配
  • 全志T507平台GPIO 控制(二)
  • OpenCV图像算数运算可莉版
  • bash命令创建新conda环境
  • Kubernetes自动扩容方案
  • 力扣-104. 二叉树的最大深度
  • Linux系统的虚拟控制台介绍(桌面卡死的拯救方案)
  • 深入探索爬虫与自动化脚本:释放效率的利器
  • 手写简易Spring框架