← 返回文章列表

Elasticsearch 底层原理系列(一):架构概述

2020-10-06·5 分钟阅读

前言

Elasticsearch 是目前最流行的分布式搜索和分析引擎,广泛应用于日志分析、全文搜索、指标监控等场景。然而,很多开发者在使用 ES 时,往往只停留在 API 层面,对其底层实现原理缺乏深入了解。

本系列将从底层实现角度,深入剖析 Elasticsearch 的核心原理,帮助读者:

  • 理解 ES 的分层架构设计
  • 掌握倒排索引、Segment、Merge 等核心概念
  • 了解写入和查询的完整流程
  • 具备生产环境调优能力

技术亮点

技术点难度面试价值本文覆盖
ES 分层架构⭐⭐⭐高频考点
Lucene 与 ES 关系⭐⭐⭐高频考点
核心概念(Index/Shard/Segment)⭐⭐⭐⭐高频考点
分布式搜索原理⭐⭐⭐⭐进阶考点

面试考点

  1. Elasticsearch 的架构是怎样的?有哪些核心组件?
  2. Lucene 和 Elasticsearch 是什么关系?
  3. Index、Shard、Segment 分别是什么?它们之间有什么关系?
  4. 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 IndexES 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"       # 默认值,高写入场景可调大

分片规划建议

数据量推荐分片数单分片大小
< 10GB1< 10GB
10-100GB2-510-50GB
100GB-1TB5-2010-50GB
> 1TB20+保持 10-50GB

黄金法则: 单个分片大小保持在 10-50GB 之间。

避免的坑

┌─────────────────────────────────────────────────────────────────────────┐
│                        常见错误与避免方法                                │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  ❌ 分片过多                                                            │
│     • 每个分片会消耗内存和 CPU                                          │
│     • 分片数不应超过节点数 × 20                                         │
│                                                                         │
│  ❌ 分片过少                                                            │
│     • 无法利用分布式并行能力                                            │
│     • 单分片过大影响恢复速度                                            │
│                                                                         │
│  ❌ 动态映射滥用                                                        │
│     • 自动映射可能导致类型错误                                          │
│     • 建议预先定义 mapping                                              │
│                                                                         │
│  ❌ 深度分页                                                            │
│     • from + size 过大会导致内存溢出                                    │
│     • 使用 scroll 或 search_after 替代                                  │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

总结

本章介绍了 Elasticsearch 的整体架构,核心要点:

  1. 分层架构:从 API 层到 Lucene 层,各司其职
  2. ES 与 Lucene:ES 在 Lucene 之上构建分布式能力
  3. 核心概念:Index → Shard → Segment 的层级关系
  4. 分布式原理:写入路由、查询广播、结果聚合
  5. 近实时搜索:Refresh 机制实现秒级可见

参考资料

下一章预告

下一章将深入探讨 倒排索引原理,包括:

  • Term Dictionary 与 Postings List 的实现
  • FST(Finite State Transducer)数据结构
  • 压缩技术与查询优化

💡 提示:理解 ES 架构的关键是理解 Lucene 与 ES 的关系——ES 本质上是 Lucene 的分布式封装,提供了集群管理、REST API、分片副本等企业级能力。

分享: