基本概念
- 文档型存储的中间件,以 JSON 格式进行数据存储
- 支持对文档数据的增删改查,即 CRUD 操作
- 使用分片和复制技术,支持处理超大规模数据
- 基于 Java 编写,天然支持分布式,主副分片自动分配和复制
- 基于 Hash 模式进行分片路由
- 全文检索功能强大,字段自动建立倒排索引
- 适合用于搜索及日志存储场景,但写入数据并非实时可见,取决于
refresh_interval参数的配置
集群核心概念

- 集群(cluster):由一个或多个节点组成,通过集群名称与其他集群区分。
- 节点(node):单个 Elasticsearch 实例,通常运行在一个隔离的容器或虚拟机中。
- 索引(index):一组文档的集合,类似关系型数据库中的"表"。
- 分片(shard):索引被拆分为多个分片,分布在不同节点上。ES 自动管理分片的分配和再平衡,用户无需关心细节。
- 副本(replica):主分片的完整拷贝。ES 默认为每个索引创建 5 个主分片,并为每个主分片创建 1 个副本。主分片和副本均可处理查询请求,但只有主分片能处理写入请求。副本可随时动态增减,额外副本能带来更大容量、更高吞吐及更强的故障恢复能力。
- 注意:主分片数量在索引创建时确定,之后不可变更。一旦修改,所有已路由的文档将无法被找到。
分片配置建议
分配分片时,首要考虑数据集的增长趋势。每个分片都有额外的资源开销:
- 每个分片本质上是一个 Lucene 索引,会消耗文件句柄、内存和 CPU 资源
- 每次搜索请求会分发到所有分片;分片竞争相同硬件资源时,性能会逐步下降
- ES 使用词频统计来计算相关性,若大量分片上数据量很少,最终文档相关性会较差
Elasticsearch 推荐的最大 JVM 堆空间是 30~32 GB,建议将单个分片的最大容量控制在 30 GB 以内。例如,数据量预计达到 200 GB,推荐分配 7~8 个分片。
实践建议:
- 初始阶段,按节点数量的 1.5~3 倍创建分片。例如 3 个节点,分片数不超过 9 个。
- 单个索引数据量在 1 GB 以内时,只需分配 1 个分片。
- 使用 ES 默认配置(5 个分片)且有基于日期的索引时,6 个月后分片数可能达到 890 个,集群将难以工作——除非配置了 15 个以上的节点。
分片与副本
分片
- Elasticsearch 将每个索引划分为多个分片,分布在不同节点上,支持水平扩展和并行查询。
- 主分片数量在创建索引时指定(默认 5 个),之后不可变更。
副本
- 副本是主分片的完整拷贝,提供数据冗余和读取扩展能力。
- 副本数量默认为 1,可动态调整。
- 副本与主分片均衡分布在不同节点,避免单点故障。
ES 各节点职责
Elasticsearch 集群中有三类主要节点角色:
- 主节点(master node):负责集群管理,包括创建/删除索引、追踪集群成员、分配分片到节点。主节点对 CPU 要求高,内存要求相对较低。建议生产环境设置 3 台以上专用 master 节点,不存储数据,只维护集群状态。
- 数据节点(data node):负责存储索引数据,处理文档的增删改查及聚合操作。对 CPU、内存、I/O 要求都较高,资源不足时需横向扩容。
- 协调节点(coordinating node / client node):当
node.master和node.data均为false时,节点只负责路由请求、分发搜索、合并结果,相当于智能负载均衡器。在大规模集群中,建议单独设置一批协调节点,避免与主节点和数据节点的业务互相干扰。
生产集群推荐职责分离:master 节点专注集群管理,data 节点专注数据存储,coordinating 节点专注请求路由,各自按对应的硬件需求部署。
Elasticsearch 查询流程
- 客户端发送请求:客户端向任意一个协调节点发送查询请求。
- 分发到分片:协调节点将请求分发到涉及的所有分片(scatter phase,分散阶段)。
- 分片本地执行:每个分片在本地执行查询并返回结果给协调节点。
- 合并返回:协调节点汇总、排序各分片结果(gather phase,聚集阶段),最终返回给客户端。
副本在查询中的作用
- 负载均衡:协调节点会将查询请求分发到不同节点上的副本分片,均摊查询压力。
- 容错保障:若某分片的主分片不可用,协调节点自动将请求转发到对应的副本分片,保证服务连续性。
由于每个分片都有主分片和多个副本,查询请求可以并行分发到多个副本上,既提高了吞吐量,也增强了系统容错性。需要注意:
- 主分片负责写入操作,副本分片主要用于读操作和容错。
- 副本数量设置会影响查询性能、数据冗余度和存储成本,需根据实际场景权衡。
- Elasticsearch 会根据查询条件和分片路由算法,将请求路由到合适的分片。
集群脑裂问题
集群职责划分
Elasticsearch 集群节点有不同的职责划分:

默认情况下,集群中任何节点都同时具备上述四种角色。生产环境中建议将职责分离:
- master 节点:对 CPU 要求高,内存要求低
- data 节点:对 CPU 和内存要求都高
- coordinating 节点:对网络带宽和 CPU 要求高
职责分离可以针对不同节点的需求配置不同硬件,并避免业务之间互相干扰。典型的 ES 集群职责划分如下图:

脑裂问题
脑裂是因为集群中的节点失联导致的。例如,主节点与其他节点失联:

此时,node2 和 node3 认为 node1 宕机,重新发起选主:

当 node3 当选后,node2 和 node3 形成一个集群,node1 自成一个集群,两个集群数据不再同步。当网络恢复后,集群中存在两个 master 节点,出现脑裂:

解决方案:要求选票超过 (eligible 节点数 + 1) / 2 才能当选为主,因此 eligible 节点数量最好为奇数。对应配置项是 discovery.zen.minimum_master_nodes,在 ES 7.0 之后已成为默认配置,因此一般不会再发生脑裂问题。
例如:3 个节点的集群,选票必须超过 2 票。node3 获得 node2 和 node3 的选票当选,node1 只有 1 票未当选,集群中依然只有 1 个主节点。
各节点职责小结
| 节点类型 | 主要职责 |
|---|---|
| master eligible 节点 | 参与集群选主;主节点负责管理集群状态、分片信息、索引的创建与删除 |
| data 节点 | 数据的 CRUD 操作 |
| coordinator 节点 | 路由请求到其他节点,合并查询结果后返回给用户 |
集群分布式存储
当新增文档时,coordinating node 通过以下 hash 算法确定数据应存储到哪个分片:

_routing默认值为文档的_id- 算法结果与分片数量直接相关,因此索引一旦创建,分片数量不能修改
分片存储测试
插入三条数据:

三条数据分别落在不同分片:

新增文档的完整流程

- 新增一个
id=1的文档 - 对
id做 hash 运算,假设结果为 2,则存储到 shard-2 - shard-2 的主分片在 node3,将数据路由到 node3
- node3 保存文档
- 将数据同步给 shard-2 的副本 replica-2(在 node2)
- 返回结果给 coordinating node
集群分布式查询
Elasticsearch 的查询分为两个阶段:
- scatter phase(分散阶段):coordinating node 将请求分发到每一个相关分片
- gather phase(聚集阶段):coordinating node 汇总各 data node 的搜索结果,处理为最终结果集后返回给用户

集群故障转移
集群的 master 节点持续监控各节点状态。若发现某节点宕机,会立即将其上的分片数据迁移到其他节点,确保数据安全,这一过程称为故障转移。
以下是一个典型的故障转移过程:

初始状态:node1 为主节点,node2 和 node3 为从节点。node1 发生故障:

集群重新选主,node2 当选新的主节点:

node2 检测到 shard-1 和 shard-0 缺少副本,将 node1 上的数据迁移到 node2 和 node3:

实现读写分离(类主从模式)
在 Elasticsearch 中,可通过以下配置实现类似 MySQL 主从的效果,将查询请求引导到特定节点。
配置主节点和数据节点
在 elasticsearch.yml 中为不同角色的节点单独配置:
1 | # 主节点(只负责集群管理,不存储数据) |
1 | # 数据节点(负责数据存储和查询) |
使用副本分片分摊查询压力
Elasticsearch 默认开启自适应副本选择(adaptive replica selection),会智能选择响应最快的副本。若希望以轮询方式在所有副本间均匀分配请求(可能降低搜索速度),可关闭该功能:
1 | PUT /_cluster/settings |
通过 Allocation Awareness 指定副本分布
使用 allocation awareness 功能,可将副本分片分配到特定节点组(如不同机架)。首先在每个节点的 elasticsearch.yml 中设置自定义属性:
1 | node.attr.rack_id: rack_one |
也可以在启动时通过命令行参数指定:
1 | ./bin/elasticsearch -Enode.attr.rack_id=rack_one |
然后在每个 master eligible 节点的配置中启用 awareness:
1 | cluster.routing.allocation.awareness.attributes: rack_id |
这样 Elasticsearch 在分配分片时会考虑 rack_id 属性,确保主副分片不会落在同一机架上。
指定查询在特定分片上执行
使用 preference 参数可将查询请求路由到指定分片:
1 | GET /index/_search?preference=_shards:1 |
通过以上配置,可以实现类似 MySQL 主从的效果,并将查询请求引导到从节点或特定节点上执行。