Elasticsearch第3章:架构原理

忘机山人

发布于184天前
博客图片修整中,看不了可以先搜索公众号“忘机山人”看。
#


https://appstore.lazycat.cloud/#/shop/detail/xu.deploy.elasticsearch


> 本章导读:本章将深入介绍 Elasticsearch 的架构设计,包括集群架构、节点类型、数据存储原理等,帮助读者理解 ES 的内部工作机制。

## 目录

- [前置知识](#前置知识)
- [集群架构概览](#集群架构概览)
- [节点类型详解](#节点类型详解)
- [数据存储原理](#数据存储原理)
- [分布式架构](#分布式架构)
- [本章小结](#本章小结)
- [参考资料](#参考资料)


## 集群架构概览

### 整体架构图

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                              客户端请求                                      │
│                    (REST API / Transport Protocol)                          │
└─────────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                           Elasticsearch 集群                                 │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                         协调层 (Coordinating)                        │   │
│  │              接收请求 → 路由到分片 → 聚合结果 → 返回响应               │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                    │                                        │
│         ┌──────────────────────────┼──────────────────────────┐            │
│         ▼                          ▼                          ▼            │
│  ┌─────────────┐           ┌─────────────┐           ┌─────────────┐       │
│  │   Master    │           │    Data     │           │   Ingest    │       │
│  │    Node     │           │    Node     │           │    Node     │       │
│  │             │           │             │           │             │       │
│  │ • 集群状态  │           │ • 数据存储  │           │ • 数据预处理│       │
│  │ • 索引管理  │           │ • 搜索执行  │           │ • Pipeline  │       │
│  │ • 分片分配  │           │ • 聚合计算  │           │             │       │
│  └─────────────┘           └─────────────┘           └─────────────┘       │
│                                    │                                        │
│                                    ▼                                        │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                         存储层 (Lucene)                              │   │
│  │                    倒排索引 / Doc Values / 段文件                     │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────────┘
```

### 架构组件说明

| 组件 | 职责 |
|------|------|
| 协调层 | 接收客户端请求,路由到正确的分片,聚合各分片结果 |
| Master 节点 | 管理集群元数据,处理索引创建/删除,分片分配决策 |
| Data 节点 | 存储数据,执行数据相关操作(CRUD、搜索、聚合) |
| Ingest 节点 | 执行 Ingest Pipeline,在索引前预处理文档 |
| 存储层 | 基于 Lucene 的底层存储,管理倒排索引和段文件 |

## 节点类型详解

### Master 节点

Master 节点负责集群级别的管理操作:

**职责**:
- 维护集群状态(Cluster State)
- 创建和删除索引
- 分片分配和重平衡决策
- 节点加入和离开处理

**配置**:
```yaml
# elasticsearch.yml
node.roles: [master]
```

**最佳实践**:
- 生产环境至少 3 个 Master-eligible 节点
- 专用 Master 节点不存储数据,资源需求较低
- 配置 `cluster.initial_master_nodes` 防止脑裂

```yaml
# 专用 Master 节点配置
node.roles: [master]
cluster.initial_master_nodes: ["master-1", "master-2", "master-3"]
```

### Data 节点

Data 节点负责数据存储和处理:

**职责**:
- 存储分片数据
- 执行 CRUD 操作
- 执行搜索和聚合

**配置**:
```yaml
# elasticsearch.yml
node.roles: [data]
```

**数据节点分层**(8.x 新特性):

| 角色 | 说明 | 适用数据 |
|------|------|----------|
| `data_hot` | 热数据节点 | 最新、频繁访问的数据 |
| `data_warm` | 温数据节点 | 较少访问的历史数据 |
| `data_cold` | 冷数据节点 | 很少访问的归档数据 |
| `data_frozen` | 冻结数据节点 | 极少访问,可搜索快照 |
| `data_content` | 内容数据节点 | 非时序数据 |

```yaml
# 热数据节点配置
node.roles: [data_hot]

# 温数据节点配置
node.roles: [data_warm]
```

### Coordinating 节点

协调节点(也称为客户端节点)专门处理请求路由:

**职责**:
- 接收客户端请求
- 将请求路由到相关分片
- 聚合各分片返回的结果
- 返回最终结果给客户端

**配置**:
```yaml
# 专用协调节点(不设置任何角色)
node.roles: []
```

**工作流程**:
```
客户端请求
    │
    ▼
┌─────────────────┐
│  Coordinating   │
│     Node        │
└────────┬────────┘
         │ 路由请求
    ┌────┴────┬────────┐
    ▼         ▼        ▼
┌───────┐ ┌───────┐ ┌───────┐
│Shard 0│ │Shard 1│ │Shard 2│
└───┬───┘ └───┬───┘ └───┬───┘
    │         │        │
    └────┬────┴────────┘
         │ 聚合结果
         ▼
┌─────────────────┐
│  Coordinating   │
│     Node        │
└────────┬────────┘
         │
         ▼
    客户端响应
```

### Ingest 节点

Ingest 节点在文档索引前执行预处理:

**职责**:
- 执行 Ingest Pipeline
- 数据转换和丰富
- 字段提取和格式化

**配置**:
```yaml
# elasticsearch.yml
node.roles: [ingest]
```

**Pipeline 示例**:
```json
PUT _ingest/pipeline/my-pipeline
{
  "description": "处理日志数据",
  "processors": [
    {
      "grok": {
        "field": "message",
        "patterns": ["%{IP:client_ip} - %{DATA:user} \\[%{HTTPDATE:timestamp}\\]"]
      }
    },
    {
      "date": {
        "field": "timestamp",
        "formats": ["dd/MMM/yyyy:HH:mm:ss Z"]
      }
    },
    {
      "geoip": {
        "field": "client_ip"
      }
    }
  ]
}
```

### ML 节点

机器学习节点执行 ML 任务:

**职责**:
- 异常检测作业
- 预测分析
- 数据帧分析

**配置**:
```yaml
# elasticsearch.yml
node.roles: [ml]
xpack.ml.enabled: true
```

### 节点角色组合建议

**小型集群(开发/测试)**:
```yaml
# 所有节点都是全角色
node.roles: [master, data, ingest]
```

**中型集群**:
```
┌─────────────────────────────────────────────────────────┐
│  3 x Master/Data 节点                                   │
│  node.roles: [master, data, ingest]                    │
└─────────────────────────────────────────────────────────┘
```

**大型集群**:
```
┌─────────────────────────────────────────────────────────┐
│  3 x 专用 Master 节点                                   │
│  node.roles: [master]                                  │
├─────────────────────────────────────────────────────────┤
│  N x 专用 Data 节点                                     │
│  node.roles: [data_hot] / [data_warm] / [data_cold]   │
├─────────────────────────────────────────────────────────┤
│  2+ x 协调节点                                          │
│  node.roles: []                                        │
├─────────────────────────────────────────────────────────┤
│  2+ x Ingest 节点                                       │
│  node.roles: [ingest]                                  │
└─────────────────────────────────────────────────────────┘
```

## 数据存储原理

### Lucene 基础

Elasticsearch 底层使用 Apache Lucene 作为搜索引擎库。每个分片本质上是一个 Lucene 索引。

```
┌─────────────────────────────────────────────────────────┐
│                    Elasticsearch 分片                    │
│  ┌─────────────────────────────────────────────────┐   │
│  │                  Lucene Index                    │   │
│  │  ┌─────────┐ ┌─────────┐ ┌─────────┐           │   │
│  │  │Segment 0│ │Segment 1│ │Segment 2│  ...      │   │
│  │  └─────────┘ └─────────┘ └─────────┘           │   │
│  └─────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────┘
```

### 倒排索引(Inverted Index)

倒排索引是全文搜索的核心数据结构:

**正向索引 vs 倒排索引**:

```
正向索引(文档 → 词项):
┌─────────┬────────────────────────────┐
│ Doc ID  │ Content                    │
├─────────┼────────────────────────────┤
│ 1       │ "Elasticsearch is fast"    │
│ 2       │ "Elasticsearch is scalable"│
│ 3       │ "Lucene is fast"           │
└─────────┴────────────────────────────┘

倒排索引(词项 → 文档):
┌───────────────┬─────────────────────────┐
│ Term          │ Posting List            │
├───────────────┼─────────────────────────┤
│ elasticsearch │ [1, 2]                  │
│ fast          │ [1, 3]                  │
│ is            │ [1, 2, 3]               │
│ lucene        │ [3]                     │
│ scalable      │ [2]                     │
└───────────────┴─────────────────────────┘
```

**倒排索引结构**:

```
┌─────────────────────────────────────────────────────────┐
│                      倒排索引                            │
├─────────────────────────────────────────────────────────┤
│  Term Dictionary (词项字典)                              │
│  ┌─────────────────────────────────────────────────┐   │
│  │ elasticsearch → offset: 0                        │   │
│  │ fast → offset: 100                               │   │
│  │ scalable → offset: 200                           │   │
│  └─────────────────────────────────────────────────┘   │
│                          │                              │
│                          ▼                              │
│  Posting List (倒排列表)                                │
│  ┌─────────────────────────────────────────────────┐   │
│  │ Doc IDs: [1, 2]                                  │   │
│  │ Term Frequency: [1, 1]                           │   │
│  │ Positions: [[0], [0]]                            │   │
│  │ Offsets: [[0-13], [0-13]]                        │   │
│  └─────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────┘
```

### Doc Values

Doc Values 是列式存储,用于排序、聚合和脚本访问:

```
倒排索引(搜索用):        Doc Values(聚合/排序用):
Term → Doc IDs              Doc ID → Field Value

"apple"  → [1, 3]           1 → "apple"
"banana" → [2]              2 → "banana"
"cherry" → [4]              3 → "apple"
                            4 → "cherry"
```

**Doc Values vs Fielddata**:

| 特性 | Doc Values | Fielddata |
|------|------------|-----------|
| 存储位置 | 磁盘 | 内存 |
| 构建时机 | 索引时 | 查询时 |
| 适用类型 | keyword, numeric, date, ip, geo | text |
| 内存占用 | 低 | 高 |
| 默认状态 | 启用 | 禁用 |

```json
// 禁用 Doc Values(节省磁盘,但无法排序/聚合)
PUT /my-index
{
  "mappings": {
    "properties": {
      "description": {
        "type": "keyword",
        "doc_values": false
      }
    }
  }
}
```

### 段(Segment)

段是 Lucene 索引的基本单位,是不可变的:

**段的生命周期**:

```
1. 文档写入内存缓冲区
   ┌─────────────────┐
   │  Memory Buffer  │ ← 新文档
   └─────────────────┘

2. Refresh:内存缓冲区 → 新段(可搜索)
   ┌─────────────────┐
   │   Segment 0     │ ← 可搜索
   └─────────────────┘

3. 更多文档写入,创建更多段
   ┌─────────┐ ┌─────────┐ ┌─────────┐
   │Segment 0│ │Segment 1│ │Segment 2│
   └─────────┘ └─────────┘ └─────────┘

4. Merge:多个小段合并为大段
   ┌─────────────────────────────────┐
   │         Merged Segment          │
   └─────────────────────────────────┘
```

**段合并(Merge)**:

```json
// 强制合并(谨慎使用,资源消耗大)
POST /my-index/_forcemerge?max_num_segments=1
```

### _source 字段

`_source` 存储文档的原始 JSON:

```json
// 禁用 _source(节省存储,但无法更新/reindex)
PUT /my-index
{
  "mappings": {
    "_source": {
      "enabled": false
    }
  }
}

// 部分存储
PUT /my-index
{
  "mappings": {
    "_source": {
      "includes": ["title", "date"],
      "excludes": ["content"]
    }
  }
}
```

### 存储结构总结

```
┌─────────────────────────────────────────────────────────────────┐
│                        Lucene Segment                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐ │
│  │ Inverted Index  │  │   Doc Values    │  │    _source      │ │
│  │                 │  │                 │  │                 │ │
│  │ • Term Dict     │  │ • 列式存储      │  │ • 原始 JSON     │ │
│  │ • Posting List  │  │ • 排序/聚合用   │  │ • 更新/高亮用   │ │
│  │ • 全文搜索用    │  │                 │  │                 │ │
│  └─────────────────┘  └─────────────────┘  └─────────────────┘ │
│                                                                 │
│  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐ │
│  │  Stored Fields  │  │   Term Vectors  │  │     Norms       │ │
│  │                 │  │                 │  │                 │ │
│  │ • 存储的字段值  │  │ • 词项位置信息  │  │ • 字段长度归一化│ │
│  │                 │  │ • 高亮/MLT 用   │  │ • 评分用        │ │
│  └─────────────────┘  └─────────────────┘  └─────────────────┘ │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

## 分布式架构

### 文档路由

文档通过路由算法分配到特定分片:

```
shard_num = hash(routing) % number_of_primary_shards
```

默认 `routing` 值为文档 `_id`。

```json
// 自定义路由
PUT /products/_doc/1?routing=user123
{
  "name": "Product A",
  "user_id": "user123"
}

// 查询时指定路由(提高效率)
GET /products/_search?routing=user123
{
  "query": {
    "match": { "user_id": "user123" }
  }
}
```

### 写入流程

```
1. 客户端发送写入请求到协调节点
2. 协调节点根据路由计算目标主分片
3. 请求转发到主分片所在节点
4. 主分片执行写入
5. 主分片并行复制到所有副本分片
6. 所有副本确认后,返回成功响应

┌────────┐     ┌─────────────┐     ┌─────────────┐
│ Client │────>│ Coordinating│────>│   Primary   │
└────────┘     │    Node     │     │   Shard     │
               └─────────────┘     └──────┬──────┘
                                          │
                              ┌───────────┼───────────┐
                              ▼           ▼           ▼
                         ┌────────┐  ┌────────┐  ┌────────┐
                         │Replica │  │Replica │  │Replica │
                         │   1    │  │   2    │  │   3    │
                         └────────┘  └────────┘  └────────┘
```

### 搜索流程

搜索分为两个阶段:Query Phase 和 Fetch Phase。

**Query Phase**:
```
1. 协调节点将请求发送到所有相关分片
2. 每个分片执行本地搜索,返回匹配文档的 ID 和排序值
3. 协调节点合并结果,确定最终的 Top N 文档

┌────────┐     ┌─────────────┐
│ Client │────>│ Coordinating│
└────────┘     │    Node     │
               └──────┬──────┘
                      │ Query
         ┌────────────┼────────────┐
         ▼            ▼            ▼
    ┌─────────┐  ┌─────────┐  ┌─────────┐
    │ Shard 0 │  │ Shard 1 │  │ Shard 2 │
    └────┬────┘  └────┬────┘  └────┬────┘
         │            │            │
         └────────────┼────────────┘
                      │ Doc IDs + Scores
                      ▼
               ┌─────────────┐
               │ Coordinating│
               │    Node     │
               └─────────────┘
```

**Fetch Phase**:
```
1. 协调节点向包含目标文档的分片发送 Fetch 请求
2. 分片返回完整文档内容
3. 协调节点组装最终结果返回客户端

               ┌─────────────┐
               │ Coordinating│
               │    Node     │
               └──────┬──────┘
                      │ Fetch (Doc IDs)
         ┌────────────┼────────────┐
         ▼            ▼            ▼
    ┌─────────┐  ┌─────────┐  ┌─────────┐
    │ Shard 0 │  │ Shard 1 │  │ Shard 2 │
    └────┬────┘  └────┬────┘  └────┬────┘
         │            │            │
         └────────────┼────────────┘
                      │ Full Documents
                      ▼
               ┌─────────────┐
               │ Coordinating│──────> Client
               │    Node     │
               └─────────────┘
```

### 集群状态管理

集群状态(Cluster State)包含:
- 节点信息
- 索引元数据
- 分片分配信息
- 映射定义
- 集群设置

```json
// 查看集群状态
GET /_cluster/state

// 查看集群状态大小
GET /_cluster/state?filter_path=metadata.indices.*.state
```

### 主节点选举

Elasticsearch 使用基于 Raft 的选举算法(7.0+):

```
┌─────────────────────────────────────────────────────────┐
│                    主节点选举流程                        │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  1. 节点启动,进入候选状态                               │
│  2. 候选节点向其他节点请求投票                           │
│  3. 获得多数票的节点成为主节点                           │
│  4. 主节点定期发送心跳                                   │
│  5. 主节点失联,重新选举                                 │
│                                                         │
│  ┌─────────┐    ┌─────────┐    ┌─────────┐             │
│  │ Node 1  │    │ Node 2  │    │ Node 3  │             │
│  │(Master) │◄───│         │    │         │             │
│  └─────────┘    └─────────┘    └─────────┘             │
│       │              ▲              ▲                   │
│       │   心跳       │              │                   │
│       └──────────────┴──────────────┘                   │
│                                                         │
└─────────────────────────────────────────────────────────┘
```

**防止脑裂**:
```yaml
# 配置初始主节点(仅首次启动时需要)
cluster.initial_master_nodes: ["node-1", "node-2", "node-3"]
```

## 本章小结

本章深入介绍了 Elasticsearch 的架构原理:

1. **集群架构**:由协调层、Master 节点、Data 节点、Ingest 节点等组成
2. **节点类型**:
   - Master:管理集群状态和元数据
   - Data:存储数据,执行搜索和聚合
   - Coordinating:路由请求,聚合结果
   - Ingest:数据预处理
   - ML:机器学习任务
3. **数据存储**:
   - 倒排索引:全文搜索的核心
   - Doc Values:排序和聚合的列式存储
   - 段:不可变的 Lucene 索引单元
4. **分布式机制**:
   - 文档路由:hash(routing) % shards
   - 写入流程:主分片写入 → 副本复制
   - 搜索流程:Query Phase → Fetch Phase

理解这些架构原理有助于更好地设计和优化 Elasticsearch 应用。

## 参考资料

- [Elasticsearch 集群架构](https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-cluster.html)
- [节点角色](https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-node.html)
- [Lucene 倒排索引](https://lucene.apache.org/core/)
- [分布式搜索执行](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-shard-routing.html)



![image.png](https://dl.playground.lazycat.cloud/guidelines/459/fa251e50-a0fe-40bf-8a4d-33211d43e0c1.png "image.png")

评论

0

暂无评论

说点什么呢~
收藏
0
0
0