TL;DR
- 场景:从 2--4 节点业务搜索到 ELK/OLAP 大集群,做角色划分、容量推算与性能调优
- 结论:先定角色与容量边界,再定分片/副本与写入策略,最后用搜索侧与运维侧指标闭环
- 产出:一套可复用的集群规划模板 + 分片副本规则 + 写入/搜索调优抓手 + 常见故障速查

版本矩阵
| 版本 | 适用性说明 | 注意事项 |
|---|---|---|
| Elasticsearch 7.x | 角色规划、分片/副本与写入/搜索调优思路适用 | 节点角色推荐以node.roles表达(较新写法);mapping片段需按7.x语法调整 |
| Elasticsearch 8.x | 规划与调优方法论同样适用 | 安全与证书默认更"强约束",跨节点通信与客户端接入需同步校验;节点角色以node.roles为主 |

Elasticsearch 集群模式
Elasticsearch 是一个分布式搜索引擎,集群模式是指由多个节点(node)组成的一个集群(cluster),它们协同工作以提供更高的性能、扩展性和容错性。每个集群都有唯一的名称,所有属于同一集群的节点使用相同的集群名称相互识别。
在集群架构中,节点根据其功能职责被划分为三种主要类型,每种类型在集群中承担着不同的角色:
-
主节点(Master Node)
- 核心职责 :
- 管理集群级别的元数据操作,包括索引创建/删除、分片分配等
- 监控集群状态,跟踪节点的加入或离开
- 处理集群范围内的配置变更
- 特性 :
- 通常不参与实际的数据搜索和存储操作
- 为保证高可用性,建议配置3个主节点(奇数个)组成主节点集群
- 示例:当新建索引时,客户端请求首先由主节点处理,主节点决定新索引的分片分配方案
- 核心职责 :
-
数据节点(Data Node)
- 核心功能 :
- 存储索引数据的实际分片
- 处理与数据相关的CRUD操作(创建、读取、更新、删除)
- 执行搜索和聚合等计算密集型任务
- 重要特性 :
- 存储数据的多个副本,确保数据高可用性
- 需要较强的CPU、内存和存储资源
- 应用场景:电商网站的搜索服务通常需要部署多个数据节点来处理大量商品数据的存储和检索
- 核心功能 :
-
协调节点(Coordinating Node)
- 工作流程 :
- 接收客户端请求
- 将请求路由到相关数据节点
- 收集各节点的响应
- 合并结果返回给客户端
- 特点 :
- 不存储数据,也不参与主节点选举
- 默认情况下所有节点都具备协调功能
- 专用协调节点通常用于大型集群,减轻其他节点的请求处理负担
- 示例:在分布式日志分析系统中,协调节点负责将搜索查询分发到存储日志的数据节点
- 工作流程 :
在实际部署中,一个节点可以同时承担多种角色(如既是数据节点又是协调节点),但生产环境通常建议将主节点与数据节点分离,以确保集群稳定性。节点类型的合理配置对集群性能、可靠性和资源利用率有重大影响。
集群规划
规划的重要性
在部署 Elasticsearch 集群时,规划是至关重要的基础步骤,直接影响集群的性能表现、未来扩展能力以及日常运维的便捷性。合理的规划可以避免后期频繁的架构调整,确保集群能够稳定高效地运行。
核心规划要素
1. 主节点规划
主节点是集群的大脑,负责维护集群状态、索引元数据和执行分片分配等重要操作。规划时需特别注意:
- 数量配置:建议至少配置三个专用主节点(master-only nodes)以形成法定人数(quorum),确保集群高可用性。当其中一个节点故障时,剩余两个节点仍能正常选举新的主节点。
- 资源分配:由于主节点不处理数据存储和搜索请求,可以配置相对较小的资源(如2-4核CPU,4-8GB内存)。
- 部署位置:应将主节点分散在不同机架或可用区(AZ)以防范单点故障。例如在AWS环境中,可以将三个主节点分别部署在us-east-1a、us-east-1b和us-east-1c三个可用区。
2. 数据节点规划
数据节点是集群的主力,负责存储索引数据、执行搜索和分析操作。规划要点包括:
- 资源需求 :
- 内存:建议每个节点配置32GB以上内存,其中一半(16GB)分配给JVM堆,剩余用于文件系统缓存。
- 存储:根据数据量和增长预期确定,建议使用SSD存储以获得更好的IO性能。例如,预计年增长10TB数据的业务,可按3节点×2TB SSD配置。
- 分片策略:每个节点建议承载不超过20-25个分片,每个分片大小控制在30-50GB之间。例如10TB数据可分为200个50GB的分片,需要8-10个数据节点。
- 扩展性:采用水平扩展策略,初期可按最小需求配置,后续随数据增长逐步添加节点。例如电商平台在促销季前可临时增加数据节点应对流量高峰。
3. 协调节点规划
协调节点作为请求的入口和调度中心,在大规模集群中特别重要:
- 功能分离:将搜索请求的聚合、排序等计算密集型操作从数据节点卸载到协调节点,减轻数据节点负担。
- 资源配置:需要较强的CPU资源(8-16核)处理请求路由和结果聚合,内存需求中等(16-32GB)。
- 部署场景:特别适用于搜索请求量大(如每天百万级查询)或复杂聚合查询多的场景。例如新闻网站可部署3-5个协调节点处理用户搜索请求。
- 负载均衡:配合负载均衡器(如Nginx、HAProxy)使用,实现请求的均匀分发和故障转移。
规划考虑
我们在业务上需要考虑的是:
- 当前的数据量有多大?数据增长情况如何?
- 你的机器配置如何?CPU?内存?硬盘容量?
推算依据
- Elasticsearch JVM Heap 最大可以设置32G
- 30G heap大概能处理的数据量10T
- 内存很大的话,比如128G的内存,可以考虑一台机器上部署多个Elasticsearch
应用场景
- 用于构建业务搜索功能模块,且多是垂直领域的搜索。数据量级几千万到数十亿级别,一般2-4台机器的规模
- 用于大规模的实时OLAP(联机处理分析),经典的如ELK Stack,数据规模可以达到千亿或更多,几十到上百节点的规模
角色分配
节点角色:
- MasterNode: node.master设置为true,节点可以作为主节点
- DataNode:node.data设置为true,默认是数据节点
- CoordinateNode:协调节点,一个节点只作为接收请求、转发请求到其他的节点、汇总各个节点返回数据等功能的节点,就叫协调节点。(如果仅担任协调节点,需要将MasterNode和DataNode设置为false,一个节点可以充当一个角色,也可以充当多个角色)
节点角色如何分配:
- 小规模集群,不需要严格区分
- 中大规模集群(十个节点以上),应考虑单独的角色充当。特别并发查询量大,查询的合并量大,可以增加独立的协调节点。角色分开的好处是分工分开,互不影响。如不会因协调角色负载过高而影响数据节点的能力。
设置分片
- 说明:分片数指定后不可变,除非索引重建。
- 分片设置的可参考原则: Elasticsearch推荐的JVM最大的堆空间是:30-32G,所以把分片的最大容量限制在30G,然后对分片数量做合理估算。 在开始阶段,一个好的方案是根据节点的数量按照 1.5-3倍的原则来创建分片。例如:如果你有三个节点,则推荐你创建的分片数量不超过9个(3*3)个。 当性能开始下降时,增加节点,ES会平衡分片的放置。 对于基于日期的索引需求,并且对索引数据的搜索场景非常少,也许这些索引量会成百上千,但是每个索引的大小缺只有1GB甚至更小。对于这种场景,建议只需要为索引分配1个分片。 对于日志管理的需求,就是类似于日期索引需求,日期索引会很多,但是每个索引存放的数据量缺很少。
设置副本
分片应该设置几个副本呢?
- 为了保证高可用,副本数设置为2即可。但是要求集群至少有3个节点,来分开存放主分片、副本。
- 如果并发量大时,查询性能下降,则增加副本数,提高并发查询的能力。
- 注意:新增副本时主节点会自动协调,然后拷贝数据到新增的副本节点,副本数是随时都可以调整的。
json
PUT /wzk_temp_index/_settings
{
"number_of_replicas": 1
}
集群调优
Index调优
在业务场景中,很多时候数据都是从MySQL集群,再抽取到ES的Index中。 如果你的场景的数据是不断变化的,那就要求ES中的数据也要有一个快速变化的要求,这样才可以保证MySQL和Elasticsearch中的数据保持一致。
副本数0
如果集群是首次写入数据,那么可以先设置为0,后续写完再根据业务要求设置为2(比如高可用),节约集群生成索引的过程。
json
PUT /wzk_temp_index/_settings
{
"number_of_replicas": 0
}
自动生成ID
自动生成DocID,通过Elasticsearch写入流程可以看出,如果写入Doc时外部指定了id,那么Elasticsearch会先尝试读取原来的Doc的版本号,以判断是否需要更新数据,这个操作涉及到了磁盘,如果是自动生成DocID则可以避免这个问题。
mappings
合理设置mappings:
- 将不需要建立索引的字段index属性设置为not_analyzed或no。对字段不分词,或者不索引,可以减少很多CPU的计算。尤其是Binary类型,默认情况下CPU会很高,而且这种分词通过没有任何意义。
- 减少字段的内容长度,如果原始数据的大段内容不用全部建立索引,则可以尽量减少不必要的内容
- 使用不同的分析器(analyzer),不同的分词器在建立索引的过程中,运算的复杂度也有较大的差异。
source字段
调整 _source 字段,source字段用于存储原数的doc数据,对于部分不需要存储的数据,可以通过index excludes过滤,或者将source禁用,一般用于索引和数据分离,这样可以降低I/O的压力,不过业务场景中大多数都不会禁用Source。
analyzed禁用norms
norms用于在搜索中计算doc的评分,如果不需要评分,则可以将其禁用。
json
"title": {
"type": "string",
"norms": {
"enabled": false
}
}
刷新间隔
调整索引的刷新间隔,该参数缺省是1秒,强制ES每秒创建一个新的Segment,从而保证新写入的数据近实时可见,可以被搜索到。比如该参数被调整为30秒,降低了刷新的次数,把刷新操作消耗的资源给释放出来给index操作使用。
json
PUT /wzk_temp_index/_settings
{
"index" : {
"refresh_interval": "30s"
}
}
这种方式是牺牲可见性的方式,提高了index操作的性能。
批处理
批处理把多个index操作请求合并到一个batch中去处理,和MySQL的JDBC的Batch有类似之处。 如下图所示: 
比如每批10000个Document是一个性能比较好的大小,每批中多少Document条数合适,受到很多因素影响而不同。
Search调优
在存储的Document超过10亿条后,需要进行搜索调优。
数组分组
ES用来存储日志,日志的索引管理方式一般都是基于日期,基于天、周、月、年建立索引,如下图,基于天建立索引:
当搜索丹单天的数据,只要要查询一个索引的Shards就可以。当需要查询多天的数据时,需要查询多个索引的Shards。这种方案其实和数据库分表、分库、分区查询方案相比思路是类似的,小数据范围检索而不是大海捞针。
Filter
使用Filter替代Query 在搜索的过程中使用Query,需要对Document的相关度进行打分,使用Filter的话,就不会有过滤了,做的事情更少,而且Filter理论上更快一些。 如果搜索不需要打分,可以直接使用Filter查询,如果部分搜索需要打分,建议使用Bool查询,这种方式可以把打分和不打分的放到一起:
json
GET /_search
{
"query": {
"bool": {
"must": {
"term": {
"user": "kimchy"
}
},
"filter": {
"term": {
"tag": "tech"
}
}
}
}
}
ID字段
将ID字段定义为Keyword类型是一种常见的优化实践。这种定义方式特别适用于以下场景:
- 使用场景分析:
- 当ID主要用作精确匹配查询(如terms查询)时
- 当ID不会被用于范围查询(range query)或数值计算时
- 典型应用场景包括:用户ID、订单编号、产品SKU等标识性字段
- 性能优化原理:
- Keyword类型在Elasticsearch内部会被优化为倒排索引结构,特别适合精确匹配查询
- 相比数值类型(如Integer),Keyword类型避免了为范围查询优化的开销
- 在terms查询场景下,Keyword类型的查询效率比数值类型更高
- 实际案例数据:
- 某电商平台将商品ID从Integer改为Keyword类型后:
- 查询响应时间从平均120ms降低到85ms
- 系统吞吐量提升了约30%
- 索引大小减少了15%(因为不需要存储数值类型的额外元数据)
- 实现建议:
json
{
"mappings": {
"properties": {
"id": {
"type": "keyword"
}
}
}
}
- 注意事项:
- 该优化主要适用于字符串形式的ID或不需要数值运算的数字ID
- 如果确实需要范围查询功能,建议保留数值类型
- 对于既有精确匹配又有范围查询需求的字段,可以考虑使用multi-fields特性同时定义两种类型
错误速查
| 症状 | 根因 | 定位 | 修复 |
|---|---|---|---|
| 集群起不来 / 反复选主(master not discovered) | 选主节点不足、发现配置错误、网络/防火墙、时钟漂移 | master 日志、/_cluster/health、/_cat/nodes?v、发现配置与端口连通性 | 保证 ≥3 个专用主节点并跨故障域;校验 discovery/seed 配置与端口;修复网络与时间同步 |
| 分片长期 UNASSIGNED | 节点不足/磁盘水位、分配过滤、版本不兼容、恢复受限 | /_cat/shards?v、/_cluster/allocation/explain、磁盘水位与 routing 规则 | 扩容或释放磁盘;修正分配过滤与路由限制;调整水位阈值(在可控风险下)并触发重分配 |
| 写入吞吐低 / ingest 卡顿 | refresh 太频繁、merge 压力大、磁盘 IO 瓶颈、mapping 字段过多 | segment/merge 指标、节点 IO、写入延迟与线程池 | 写入期提高 refresh_interval;bulk 合并请求;减少不必要字段索引与分析;升级 SSD/提升 IO |
| CPU 飙高(尤其是写入期) | analyzer 复杂、字段爆炸、动态 mapping 失控 | hot threads、mapping 字段数、索引速率与 CPU | 收敛字段与动态模板;选择合适 analyzer;对无需检索字段 index:false |
| 内存告警 / circuit breaker | heap 压力、聚合/排序过重、请求过大 | breaker 日志、GC、慢查询与大聚合请求 | 拆分查询、限制聚合维度与 size;引入专用协调节点;控制并发与请求体 |
| 查询慢(多天日志/多索引) | 检索面过大、无过滤、分片过多导致 fan-out | query profile、慢日志、命中索引数量与分片数 | 按时间分索引并先过滤时间;用 filter 减少打分;控制分片数量与分片大小 |
| 搜索线程池 rejected / 429 | 并发过高、协调节点/数据节点压力不均 | 线程池指标、reject 计数、节点负载分布 | 加协调节点与 LB;降低并发/限流;优化查询与副本承载并发 |
| 集群不稳定(抖动/频繁重分片) | 主节点与数据负载混跑、角色未隔离、资源争用 | master 日志、节点角色与资源利用率 | 主节点专用化;大集群引入协调节点;隔离 JVM/CPU/磁盘资源 |
| "堆设得很大但更慢" | heap 超过压缩指针阈值带来性能回退 | JVM 参数与 GC、启动日志 | heap 控制在 30--32GB;其余内存留给 OS cache;必要时以多实例/多节点扩展 |
其他系列
🚀 AI篇持续更新中(长期更新)
AI炼丹日志-29 - 字节跳动 DeerFlow 深度研究框斜体样式架 私有部署 测试上手 架构研究 ,持续打造实用AI工具指南! AI研究-132 Java 生态前沿 2025:Spring、Quarkus、GraalVM、CRaC 与云原生落地 🔗 AI模块直达链接
💻 Java篇持续更新中(长期更新)
Java-207 RabbitMQ Direct 交换器路由:RoutingKey 精确匹配、队列多绑定与日志分流实战 MyBatis 已完结,Spring 已完结,Nginx已完结,Tomcat已完结,分布式服务已完结,Dubbo已完结,MySQL已完结,MongoDB已完结,Neo4j已完结,FastDFS 已完结,OSS已完结,GuavaCache已完结,EVCache已完结,RabbitMQ正在更新... 深入浅出助你打牢基础! 🔗 Java模块直达链接
📊 大数据板块已完成多项干货更新(300篇):
包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈! 大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT案例 详解 🔗 大数据模块直达链接