Elasticsearch 底层原理系列(一):架构概述
前言
Elasticsearch 是目前最流行的分布式搜索和分析引擎,广泛应用于日志分析、全文搜索、指标监控等场景。然而,很多开发者在使用 ES 时,往往只停留在 API 层面,对其底层实现原理缺乏深入了解。
本系列将从底层实现角度,深入剖析 Elasticsearch 的核心原理,帮助读者:
- 理解 ES 的分层架构设计
- 掌握倒排索引、Segment、Merge 等核心概念
- 了解写入和查询的完整流程
- 具备生产环境调优能力
技术亮点
| 技术点 | 难度 | 面试价值 | 本文覆盖 |
|---|---|---|---|
| ES 分层架构 | ⭐⭐⭐ | 高频考点 | ✅ |
| Lucene 与 ES 关系 | ⭐⭐⭐ | 高频考点 | ✅ |
| 核心概念(Index/Shard/Segment) | ⭐⭐⭐⭐ | 高频考点 | ✅ |
| 分布式搜索原理 | ⭐⭐⭐⭐ | 进阶考点 | ✅ |
面试考点
- Elasticsearch 的架构是怎样的?有哪些核心组件?
- Lucene 和 Elasticsearch 是什么关系?
- Index、Shard、Segment 分别是什么?它们之间有什么关系?
- Elasticsearch 为什么能做到近实时搜索?
Elasticsearch 是什么
Elasticsearch 是一个基于 Apache Lucene 构建的分布式、RESTful 风格的搜索和分析引擎。它能够解决不断涌现的各种用例:作为搜索系统存储和检索文档,作为日志分析系统处理海量日志数据,作为指标存储系统监控应用程序性能。
核心特性
┌─────────────────────────────────────────────────────────────────────────┐
│ Elasticsearch 核心特性 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 分布式 │ │ 近实时 │ │ 高可用 │ │ 可扩展 │ │
│ │ 架构 │ │ 搜索 │ │ 设计 │ │ 性 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ • 自动分片与路由 • 秒级数据可见 • 副本机制 • 水平扩展 │
│ • 集群自动发现 • 强大查询能力 • 故障自动转移 • 线性增长 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
分层架构
Elasticsearch 采用分层架构设计,从底层到上层依次为:
┌─────────────────────────────────────────────────────────────────────────┐
│ Elasticsearch 分层架构 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ API 层 │ │
│ │ REST API │ Java API │ HTTP/TCP 通信层 │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ 协调节点层 (Coordinating) │ │
│ │ 请求解析 │ 路由分发 │ 结果聚合 │ 响应构建 │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ 集群管理层 (Cluster) │ │
│ │ Master 选举 │ 状态同步 │ 分片分配 │ 故障检测 │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ 索引管理层 (Index) │ │
│ │ Mapping │ Analyzer │ Setting │ Alias │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ 分片层 (Shard) │ │
│ │ 主分片 │ 副本分片 │ 分片路由 │ 数据分布 │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ Lucene 层 │ │
│ │ Segment │ Inverted Index │ Doc Values │ Stored Fields │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
各层职责
| 层级 | 职责 | 关键组件 |
|---|---|---|
| API 层 | 对外暴露接口,处理协议 | REST Controller, Transport Service |
| 协调层 | 请求分发与结果聚合 | SearchService, AggregationService |
| 集群层 | 集群状态管理 | MasterService, ClusterService |
| 索引层 | 索引元数据管理 | IndexService, MappingService |
| 分片层 | 数据分布与复制 | IndexShard, ReplicationGroup |
| Lucene 层 | 底层存储与检索 | IndexWriter, IndexSearcher |
Lucene 与 Elasticsearch 的关系
理解 ES 底层原理的关键是理解 Lucene 与 ES 的关系。
Lucene 简介
Apache Lucene 是一个高性能、全功能的文本搜索引擎库,由 Doug Cutting 于 2000 年创建。它提供了:
- 完整的索引和搜索功能
- 强大的分析器(分词器)
- 多种查询类型
- 高效的存储格式
但 Lucene 只是一个库,不是完整的搜索服务,它有以下局限:
┌─────────────────────────────────────────────────────────────────────────┐
│ Lucene 的局限性 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ❌ 单机运行,无法水平扩展 │
│ ❌ 没有集群管理能力 │
│ ❌ 没有 REST API,需要编程方式调用 │
│ ❌ 没有内置的安全机制 │
│ ❌ 需要开发者处理并发、故障恢复等问题 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Elasticsearch 的角色
Elasticsearch 在 Lucene 之上构建了完整的分布式搜索服务:
┌─────────────────────────────────────────────────────────────────────────┐
│ ES 对 Lucene 的增强 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Lucene 能力 + ES 增强 │
│ ┌─────────────────────┐ ┌─────────────────────────────┐ │
│ │ • 倒排索引 │ │ • 分布式集群管理 │ │
│ │ • 搜索算法 │ + │ • REST API │ │
│ │ • 文本分析 │ ──► │ • 分片与副本机制 │ │
│ │ • 存储格式 │ │ • 故障检测与恢复 │ │
│ │ • 查询解析 │ │ • 认证与授权 │ │
│ └─────────────────────┘ └─────────────────────────────┘ │
│ │
│ = Elasticsearch │
│ │
└─────────────────────────────────────────────────────────────────────────┘
核心映射关系
| ES 概念 | Lucene 对应 | 说明 |
|---|---|---|
| Index(索引) | 多个 Lucene Index | ES Index 由多个 Shard 组成 |
| Shard(分片) | 一个 Lucene Index | 每个 Shard 是独立的 Lucene 索引 |
| Segment(段) | Lucene Segment | 不可变的索引段 |
ES Index (my_index)
│
├── Primary Shard 0 ──────► Lucene Index (shard-0)
│ ├── Segment_1
│ ├── Segment_2
│ └── Segment_N
│
├── Primary Shard 1 ──────► Lucene Index (shard-1)
│ ├── Segment_1
│ └── Segment_2
│
└── Replica Shard 0 ──────► Lucene Index (shard-0-replica)
└── ... (同主分片)
核心概念详解
Index(索引)
Index 是 ES 中最顶层的逻辑概念,类似于关系数据库中的"数据库"或"表"。
// 创建索引
PUT /my_index
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1
}
}
重要特性:
- 分片数量在创建时确定,后续不可更改
- 一个 Index 可以包含多个 Type(ES 7.x 后废弃 Type 概念)
- Index 名称必须小写,不能包含特殊字符
Document(文档)
Document 是 ES 中的最小数据单元,以 JSON 格式存储。
// 文档示例
{
"_id": "1",
"_source": {
"title": "Elasticsearch 入门",
"content": "ES 是一个分布式搜索引擎",
"timestamp": "2023-08-30T10:00:00Z",
"tags": ["search", "distributed"]
}
}
Shard(分片)
Shard 是 ES 分布式的基本单元,每个 Shard 是一个独立的 Lucene 索引。
┌─────────────────────────────────────────────────────────────────────────┐
│ 分片架构示意图 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────┐ │
│ │ ES Index │ │
│ │ (my_index) │ │
│ └──────────┬──────────┘ │
│ │ │
│ ┌────────────────────┼────────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ Shard 0 │ │ Shard 1 │ │ Shard 2 │ │
│ │ (Primary) │ │ (Primary) │ │ (Primary) │ │
│ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ Replica │ │ Replica │ │ Replica │ │
│ │ (R0) │ │ (R1) │ │ (R2) │ │
│ └────────────┘ └────────────┘ └────────────┘ │
│ │
│ 每个 Shard = 一个独立的 Lucene Index │
│ │
└─────────────────────────────────────────────────────────────────────────┘
分片类型:
| 类型 | 作用 | 特点 |
|---|---|---|
| Primary Shard | 主分片,负责写入 | 数量创建时确定,不可更改 |
| Replica Shard | 副本分片,负责读取和容灾 | 可动态调整数量 |
Segment(段)
Segment 是 Lucene 中最小的存储单元,具有不可变性。
┌─────────────────────────────────────────────────────────────────────────┐
│ Segment 特性 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ✅ 不可变(Immutable) │
│ • 一旦写入磁盘,就不会被修改 │
│ • 删除操作只是标记删除,不会真正删除数据 │
│ │
│ ✅ 写入后立即可搜索 │
│ • Refresh 操作将内存 Buffer 写入新的 Segment │
│ • 新 Segment 对搜索立即可见 │
│ │
│ ✅ 自动合并 │
│ • 小 Segment 会被合并成大 Segment │
│ • 合并时清理已删除的文档 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
分布式搜索原理
写入流程概览
┌─────────────────────────────────────────────────────────────────────────┐
│ 文档写入流程 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Client │
│ │ │
│ │ 1. 发送写入请求 │
│ ▼ │
│ ┌─────────────┐ │
│ │ Coordinating│ │
│ │ Node │ │
│ └──────┬──────┘ │
│ │ │
│ │ 2. 路由到目标分片 │
│ ▼ │
│ ┌─────────────┐ 3. 主分片写入 ┌─────────────┐ │
│ │ Primary │ ─────────────────────────► │ Replica │ │
│ │ Shard │ 4. 同步到副本分片 │ Shard │ │
│ └─────────────┘ ◄───────────────────────── └─────────────┘ │
│ │ │
│ │ 5. 返回确认 │
│ ▼ │
│ Client 收到写入成功响应 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
查询流程概览
┌─────────────────────────────────────────────────────────────────────────┐
│ 文档查询流程 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Client │
│ │ │
│ │ 1. 发送查询请求 │
│ ▼ │
│ ┌─────────────┐ │
│ │ Coordinating│ │
│ │ Node │ │
│ └──────┬──────┘ │
│ │ │
│ │ 2. 广播查询到所有相关分片 │
│ │ │
│ ├────────────────┬────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Shard 0 │ │ Shard 1 │ │ Shard 2 │ │
│ │ 本地搜索│ │ 本地搜索│ │ 本地搜索│ │
│ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │
│ │ 3. 返回 Top N 结果 │ │
│ ▼ ▼ ▼ │
│ └────────────────┴────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ 协调节点 │ │
│ │ 结果合并 │ │
│ │ 排序/分页 │ │
│ └──────┬──────┘ │
│ │ │
│ ▼ │
│ 返回给 Client │
│ │
└─────────────────────────────────────────────────────────────────────────┘
近实时搜索原理
ES 能够实现近实时搜索(Near Real-Time,约 1 秒延迟),核心机制是 Refresh:
┌─────────────────────────────────────────────────────────────────────────┐
│ 近实时搜索原理 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 时间线:T0 ──────────────► T1 (1秒后) ──────────► T2 │
│ │
│ T0: 文档写入 │
│ ┌──────────────────────────────────────────────┐ │
│ │ In-Memory Buffer │ Translog │ │
│ │ [doc1, doc2...] │ [操作日志...] │ │
│ └──────────────────────────────────────────────┘ │
│ │ │
│ │ Refresh (默认 1 秒) │
│ ▼ │
│ T1: 数据可搜索 │
│ ┌──────────────────────────────────────────────┐ │
│ │ New Segment (OS Cache) │ │
│ │ • 倒排索引已构建 │ │
│ │ • 数据在 OS Cache,可快速访问 │ │
│ │ • 对搜索可见 │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ 关键点: │
│ • Segment 写入 OS Cache,无需 fsync 到磁盘 │
│ • Refresh 操作轻量,每秒执行一次 │
│ • 这就是 ES 能实现 "近实时" 搜索的秘密 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
最佳实践
索引设计原则
# 推荐的索引设置
settings:
number_of_shards: 3 # 根据数据量和集群规模设置
number_of_replicas: 1 # 生产环境至少 1 个副本
refresh_interval: "1s" # 默认值,高写入场景可调大
分片规划建议
| 数据量 | 推荐分片数 | 单分片大小 |
|---|---|---|
| < 10GB | 1 | < 10GB |
| 10-100GB | 2-5 | 10-50GB |
| 100GB-1TB | 5-20 | 10-50GB |
| > 1TB | 20+ | 保持 10-50GB |
黄金法则: 单个分片大小保持在 10-50GB 之间。
避免的坑
┌─────────────────────────────────────────────────────────────────────────┐
│ 常见错误与避免方法 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ❌ 分片过多 │
│ • 每个分片会消耗内存和 CPU │
│ • 分片数不应超过节点数 × 20 │
│ │
│ ❌ 分片过少 │
│ • 无法利用分布式并行能力 │
│ • 单分片过大影响恢复速度 │
│ │
│ ❌ 动态映射滥用 │
│ • 自动映射可能导致类型错误 │
│ • 建议预先定义 mapping │
│ │
│ ❌ 深度分页 │
│ • from + size 过大会导致内存溢出 │
│ • 使用 scroll 或 search_after 替代 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
总结
本章介绍了 Elasticsearch 的整体架构,核心要点:
- 分层架构:从 API 层到 Lucene 层,各司其职
- ES 与 Lucene:ES 在 Lucene 之上构建分布式能力
- 核心概念:Index → Shard → Segment 的层级关系
- 分布式原理:写入路由、查询广播、结果聚合
- 近实时搜索:Refresh 机制实现秒级可见
参考资料
下一章预告
下一章将深入探讨 倒排索引原理,包括:
- Term Dictionary 与 Postings List 的实现
- FST(Finite State Transducer)数据结构
- 压缩技术与查询优化
💡 提示:理解 ES 架构的关键是理解 Lucene 与 ES 的关系——ES 本质上是 Lucene 的分布式封装,提供了集群管理、REST API、分片副本等企业级能力。
相关文章
Elasticsearch 底层原理系列(七):分片与路由机制
深入解析 Elasticsearch 分片路由机制,包括路由算法、自定义路由、分片数量规划、以及分片重平衡策略。
Elasticsearch 底层原理系列(六):集群架构与节点角色
深入解析 Elasticsearch 集群架构,包括 Master、Data、Coordinating 等节点角色的职责、集群状态管理、以及节点角色配置最佳实践。
Elasticsearch 底层原理系列(二):倒排索引原理
深入解析 Lucene 倒排索引的实现原理,包括 Term Dictionary、Postings List、FST 数据结构以及压缩技术。