Elasticsearch 核心概念详解
Elasticsearch(简称 ES)是一款基于 Apache Lucene 构建的分布式搜索与分析引擎,广泛应用于日志分析、全文检索、实时监控等场景。理解其核心概念,是用好 ES 的第一步。
一、节点(Node)
节点是 Elasticsearch 集群中的一个运行实例,本质上就是一个 JVM 进程。每个节点都有唯一的名称和 ID,负责存储数据、参与集群的索引和搜索操作。
一个集群可以包含一个或多个节点。节点启动时,会自动尝试加入同一网络中名称相同的集群。在生产环境中,通常会将不同职责的节点分开部署,以提升系统的稳定性和性能。
重要:节点是进程概念,不是机器概念。一台物理服务器上完全可以同时启动多个 ES 进程,每个进程就是一个独立的节点,拥有各自的数据目录、端口和配置。这意味着在资源充裕的情况下,单台机器也能模拟出一个多节点集群。不过在生产环境中,为避免单点故障影响多个节点,通常还是建议将节点分散部署在不同的物理机或虚拟机上。
二、角色(Role)
每个节点可以承担一种或多种角色,角色在 elasticsearch.yml 中通过 node.roles 字段配置,它决定了节点在集群中的职责分工。
在 ES 9.x 中,节点角色体系相比早期版本已大幅细化,以下是完整的角色分类:
1. Master 节点(master)
负责集群层面的管理工作,是集群的"大脑":
- 维护集群状态(Cluster State),包括节点信息、索引 Mapping、分片分配情况等
- 处理索引的创建与删除请求
- 监控节点的加入和退出,并相应更新集群状态
- 负责分片的分配与再平衡
一个集群同时只有一个活跃 Master 节点,其余具备 master 角色的节点称为 Master 候选节点(Master-eligible),在主节点故障时参与重新选举。
生产建议:部署3 个专用 Master 候选节点,既能保证选举的奇数仲裁(防止脑裂),又避免 Master 节点因数据压力影响集群稳定性。
node.roles: [ master ]
2. Data 节点(data 及数据分层角色)
Data 节点负责存储分片数据,并处理与数据相关的读写、搜索、聚合操作,是集群中资源消耗最重的角色。
在 ES 9.x 的数据分层(Data Tier)架构中,Data 节点进一步细分为以下几种子角色,对应冷热分层的生命周期管理:
| 角色 | 配置值 | 适用场景 |
|---|---|---|
| 通用数据节点 | data_content | 非时序类数据,常规业务数据 |
| 热层节点 | data_hot | 最新、最频繁读写的时序数据,需 SSD |
| 温层节点 | data_warm | 访问频率下降的近期数据,可用 HDD |
| 冷层节点 | data_cold | 较少访问的历史数据,低成本存储 |
| 冻结层节点 | data_frozen | 极少访问的归档数据,从快照按需加载 |
数据会随时间推移,由 ILM(Index Lifecycle Management)自动从 Hot → Warm → Cold → Frozen 流转,从而在性能与成本之间取得平衡。
# 热层节点配置示例
node.roles: [ data_hot, data_content ]
3. Ingest 节点(ingest)
在文档写入索引之前,对数据进行预处理。通过配置 Ingest Pipeline,可以实现:
- 字段提取与格式转换(如解析日志格式)
- 数据清洗与过滤
- 字段重命名、添加默认值
- GeoIP 解析、用户代理解析等
node.roles: [ ingest ]
当 Pipeline 逻辑复杂、CPU 消耗较高时,建议配置专用 Ingest 节点,避免与数据节点争抢资源。
4. 协调节点(Coordinating Only)
协调节点不存储数据,也不参与 Master 选举,专职负责:
- 接收客户端请求
- 将请求路由、分发到相关的数据节点
- 汇总各节点的返回结果,完成"Scatter-Gather"流程后响应客户端
所有节点默认都具备协调能力。若将 node.roles 设置为空数组,则该节点成为纯协调节点:
node.roles: []
在高并发、大聚合的场景下,专用协调节点可以有效减轻数据节点的压力,是大型集群常见的优化手段。
5. Machine Learning 节点(ml)
专门用于运行 ES 内置的机器学习任务,包括异常检测、数据预测等。ML 任务计算量大,将其隔离到专用节点可避免影响正常的搜索和写入性能。
node.roles: [ ml, remote_cluster_client ]
6. Transform 节点(transform)
负责运行 Transform 任务——将索引中的数据按聚合规则转换,并持续写入目标索引,常用于生成汇总报表、构建用户画像等场景。
node.roles: [ transform ]
7. Remote Cluster Client(remote_cluster_client)
使节点具备连接远程集群的能力,是使用**跨集群搜索(CCS)和跨集群复制(CCR)**功能的必要角色。
8. 缺省情况(不配置 node.roles)
如果在 elasticsearch.yml 中不设置 node.roles,ES 会自动为该节点赋予所有默认角色,相当于一个"全能节点",包括:
master、data、data_content、data_hot、data_warm、data_cold、data_frozen、ingest、ml、remote_cluster_client、transform
这种模式在本地开发、单节点测试时非常方便,启动即用,无需任何额外配置。但在生产环境中,全能节点意味着所有压力集中在一个进程上,Master 职责可能因数据节点的高负载而受影响,存在稳定性隐患,因此不建议在生产集群中使用缺省配置。
角色配置总结
# 小型开发集群(所有角色合一,不配置则默认全部角色)
node.roles: [ master, data, data_content, data_hot, ingest, ml, transform, remote_cluster_client ]
# 生产集群——专用 Master 节点
node.roles: [ master ]
# 生产集群——专用热层数据节点
node.roles: [ data_hot, data_content ]
# 生产集群——专用协调节点
node.roles: []
小结:在小型集群或开发环境中,一个节点可以同时承担所有角色;在生产环境中,强烈建议按角色拆分部署,职责单一,既便于资源调优,也提升了集群的整体稳定性。
三、索引(Index)
索引是 ES 中存储相关文档的逻辑命名空间,类似于关系型数据库中的"表"的概念。每个索引由三个核心部分组成:Alias(别名)、Setting(设置)、Mapping(映射)。
3.1 Alias(别名)
Alias 是索引的"昵称",一个别名可以指向一个或多个索引,客户端通过别名访问数据,而无需关心背后实际的索引名称。
Alias 的主要用途:
- 零停机切换:新索引构建完成后,将别名从旧索引切换到新索引,业务无感知
- 逻辑分组:一个别名同时指向多个索引,实现跨索引统一查询
- 写入路由:通过
is_write_index指定别名中唯一的写入目标索引
POST /_aliases
{
"actions": [
{ "add": { "index": "articles_v2", "alias": "articles", "is_write_index": true } },
{ "remove": { "index": "articles_v1", "alias": "articles" } }
]
}
3.2 Setting(设置)
Setting 定义了索引的物理结构和行为参数,分为静态配置和动态配置两类。
静态配置(创建后不可修改)
number_of_shards:主分片数量。索引数据被水平切分为多个分片,每个分片是一个独立的 Lucene 实例。分片数决定了索引的并行能力和水平扩展上限,一旦创建不可更改(需重建索引才能调整)。
动态配置(可随时修改)
number_of_replicas:每个主分片的副本数量。副本分布在不同节点上,提供数据冗余和读请求的负载均衡,可以随时动态调整。
PUT /articles
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1
}
}
分片与副本的关系:假设
number_of_shards: 3,number_of_replicas: 1,则集群共有 3 个主分片 + 3 个副本分片 = 6 个分片,分散在各个 Data 节点上。
3.3 Mapping(映射)
Mapping 定义了索引中文档的字段结构与数据类型,类似于关系数据库的 Schema,但更加灵活。
常见字段类型:
| 类型 | 说明 |
|---|---|
text | 全文检索字段,会经过分词器处理 |
keyword | 精确匹配字段,不分词,适合过滤、排序、聚合 |
date | 日期时间类型 |
integer / long | 整数类型 |
boolean | 布尔类型 |
object / nested | 对象与嵌套结构 |
Mapping 支持两种模式:
- 显式 Mapping:由开发者手动定义字段类型,推荐在生产环境使用,可精确控制字段行为
- 动态 Mapping:ES 根据写入的文档内容自动推断字段类型,适合快速原型开发,但可能产生不符合预期的类型推断
PUT /articles
{
"mappings": {
"properties": {
"title": { "type": "text" },
"author": { "type": "keyword" },
"content": { "type": "text" },
"created_at": { "type": "date" },
"view_count": { "type": "integer" }
}
}
}
四、类型(Type)
在早期版本的 ES 中,一个索引下可以定义多个类型(Type),类似于关系数据库中同一个数据库下的不同表,用于对同一索引中的不同结构文档进行区分。
然而,这一设计在实践中引发了诸多问题——不同类型中同名字段必须共享相同的 Mapping 定义,容易造成混淆和冲突。
因此,ES 逐步废弃了 Type 的概念:
- ES 6.x:每个索引只允许一个 Type,建议统一命名为
_doc - ES 7.x:Type 正式废弃,API 中不再需要指定 Type
- ES 8.x:完全移除 Type 相关 API
在现代 ES 开发中,不同业务实体应使用不同的索引来隔离,而不是依赖 Type 进行区分。
五、文档(Document)
文档是 ES 中数据存储的基本单元,以 JSON 格式表示,存储于某个索引之中。类比关系数据库,文档相当于表中的一行记录。
5.1 文档结构
一个完整的文档由两部分组成:Metadata(元数据) 和 Source Data(业务数据)。
{
"_index": "articles",
"_id": "1",
"_version": 3,
"_seq_no": 10,
"_score": 1.8745,
"_source": {
"title": "Elasticsearch 入门指南",
"author": "张三",
"tags": ["搜索", "大数据"],
"created_at": "2024-06-01"
}
}
Metadata(元数据)
元数据是 ES 自动维护的系统字段,以下划线开头,描述文档自身的身份和状态信息:
| 字段 | 说明 |
|---|---|
_index | 文档所属的索引名称 |
_id | 文档的唯一标识符,可在写入时手动指定,不指定则由 ES 自动生成一个 UUID |
_version | 文档的版本号,每次写入或更新后自动加 1,可用于乐观锁并发控制 |
_seq_no | 严格递增的序列号,比 _version 更精确,是实现并发控制的推荐方式(ES 7.x 起) |
_score | 相关性评分,仅在搜索结果中出现,反映文档与查询的匹配程度,不参与存储 |
Source Data(业务数据)
_source 字段存储的是文档写入时的原始 JSON 内容,即开发者实际定义的业务字段。ES 默认会完整保存 _source,查询时可直接返回原文内容。
_source 有几点值得注意:
_source中的字段类型由 Mapping 决定,写入的数据会按照 Mapping 进行解析和索引- 可以通过
_source: false关闭原始内容存储以节省磁盘空间,但关闭后将无法直接返回原始文档,也无法使用 reindex、update 等操作,需权衡利弊 - 查询时可通过
_source_includes/_source_excludes过滤返回的字段,减少网络传输开销
5.2 文档操作
ES 对文档的操作遵循 RESTful 风格,支持创建(PUT/POST)、读取(GET)、更新(POST /_update)、删除(DELETE)等标准操作。
文档写入时,ES 会根据 _id 对文档进行路由,将其分配到特定的主分片上,计算公式如下:
shard = hash(_id) % number_of_primary_shards
这也是为什么主分片数量一旦确定就不能修改的根本原因。
小结
| 概念 | 类比(关系型数据库) | 核心职责 |
|---|---|---|
| 节点(Node) | 数据库服务器实例 | 集群的基本计算单元 |
| 角色(Role) | 主从角色 | 定义节点在集群中的职责 |
| 索引(Index) | 数据库 / 表 | 文档的逻辑存储容器 |
| 类型(Type) | 表(已废弃) | 已被独立索引方案替代 |
| 文档(Document) | 行(Row) | 数据存储的最小单元 |
掌握这五个核心概念,是深入学习 ES 分片策略、查询 DSL、聚合分析等进阶内容的重要基础。
