ElasticSearch 知识

- ElasticSearch Database

1. Elasticsearch 概念与架构

2. 核心原理

1.1 倒排索引(Inverted Index)

1.2 分布式架构

1.3 近实时(NRT,Near Real-Time)

1.4 查询流程

  1. 客户端发起请求
    • 请求类型:根据需求,客户端可能发起 Get 请求(通过 ID 获取文档)或 Search 请求(复杂查询)
    • 目标节点:客户端将请求发送到集群中的任意节点,该节点默认担任协调节点(Coordinating Node)
  2. 请求路由与分片定位
    • Get by ID
      • 协调节点通过路由算法(如hash(_id) % number_of_shards )确定文档所在分片
      • 直接向该分片的主分片或副本分片发送请求(副本分片负载均衡)
    • Search 请求
      • 若查询未指定路由,协调节点将请求广播到索引的所有分片(主分片或副本分片)
      • 若指定路由参数,仅查询关联的分片
  3. 分片本地查询(Query Phase)
    • 分片处理
      • 每个分片在本地执行查询,使用倒排索引快速匹配词项
      • 对于搜索请求,分片返回匹配文档的 ID 和排序值(如相关性评分)
      • 分片可能使用缓存(如分片请求缓存)加速查询
    • 结果返回
      • 各分片返回本地排序后的 Top N 结果(N 有size 参数决定)
  4. 全局结果合并(Coordinating Node)
    • 排序与筛选
      • 协调节点收集所有分片的中间结果,按全局排序规则(如相关性评分)合并
      • 筛选最终** Top N 文档的 ID 列表 **(例如用户请求的 size=10 )
    • 分页处理
      • 深度分页优化:若使用from + size ,协调节点需要合并所有分片的from + size 条数据,内存开销大。推荐使用 Search AfterScroll API 替代
  5. 获取文档详情(Fetch Phase)
    • 二次请求
      • 协调节点根据筛选后的文档 ID,向对应分片发送 Multi-Get 请求获取完整文档内容
      • 分片返回文档的原始数据(如_source 字段)
    • 结果聚合
      • 协调节点将最终结果组装,返回给客户端
  6. 实时性处理
    • 新写入文档可见性
      • 搜索请求:依赖 Refresh 机制(默认1秒生成新 Segment),未刷新前不可被搜索
      • Get 请求:通过实施读取 Translog 可立即获取最新文档,无需等待 Refresh
  7. 容错与负载均衡
    • 副本分片利用
      • 读请求优先分发到副本分片,分担主分片压力,提升吞吐量
    • 故障恢复
      • 若某分片不可用,协调节点自动重试其它副本分片
  8. 缓存机制优化
    • 分片请求缓存
      • 缓存聚合结果或频繁查询的响应(仅对不含now 或动态参数的查询生效)
    • 字段数据缓存
      • 用于排序和聚合的字段数据缓存在内存,加速计算

1.5 写入流程

  1. 客户端发起写入请求
    • 请求类型:可以是单文档写入(PUT /index/_doc/1 )、批量写入(Bulk API )或更新/删除操作
    • 协调节点选择:客户端将请求发送到任意节点(默认作为协调节点)
  2. 路由计算与主分片定位
    • 路由规则
      • 若指定文档 ID,使用哈希算法:hash(_id) % number_of_shards 确定目标分片
      • 若未指定 ID(自动生成 ID),Elasticsearch 会随机选择主分片
    • 分片定位:协调节点根据路由结果,将请求转发到该主分片所在的** Data 节点**
  3. 主分片写入处理

3.1 写入内存缓冲去

3.2 写入 Translog (事务日志)

3.3 副本分片同步(Replication)

  1. 返回客户端响应
  1. 近实时搜索实现(Refresh)
  1. 数据持久化(Flush)
  1. Segment 合并(Merge)
  1. 容错与恢复机制

3. 倒排索引的底层实现

3.1 核心数据结构

原始ID:100, 200, 300 → 差值:100, 100, 100 → 压缩为单值100 + 重复次数。

3.2 倒排索引的局限性

4. 分布式设计的深度剖析

4.1 分片策略的权衡

PUT /logs/_doc/1?routing=node-1
{ "message": "error in node-1" }

4.2 分布式一致性模型

4.3 脑裂问题与防范

5. 查询流程深度优化

5.1 Query 与 Filter 的执行差异

5.2 聚合(Aggregation)的底层实现

5.3 查询性能优化

6. 高级调优参数

参数 作用 推荐值
indices.memory.index_buffer_size 控制索引缓冲区大小(堆内存百分比) 10%(默认)
index.refresh_interval 刷新间隔,影响搜索实时性 30s(写入优化场景)
index.translog.flush_threshold_size Translog刷盘阈值 1gb(高吞吐场景)
index.merge.scheduler.max_thread_count 合并线程数(需 SSD 支持) 4(默认)
search.max_buckets 聚合返回的最大桶数 100000(大数据聚合场景)

6. 架构运行相关流程图

drawio

快速问答

  1. Translog 如何保证数据安全?
    • Translog 使用追加写入(Append-Only)模式,避免随机写磁盘的性能问题
    • 通过 fsync 系统调度强制刷盘(依赖index.translog.durability 配置)
    • 崩溃恢复:节点重启时,通过 Translog 重放未持久化到 Lucene Segment 的操作
    • 源码关联:org.elasticsearch.index.translog.Translog 类处理日志的写入与恢复
    • 与 Lucene Commit 的关系:Flush 操作会将内存数据生成 Segment 并刷盘,同时清除已提交的 Translog
  2. 使用 Bulk API、调大 Refresh 间隔
    • 实战案例:在日志系统中,将refresh_interval 设为30s ,写入吞吐量提升 3 倍,但需接受搜索延迟
    • 参数调优:调整indices.memory.index_buffer_size (默认 10% 堆内存)增加索引缓冲区
    • 硬件影响:使用 SSD 减少 Flush 耗时,避免写入瓶颈
    • 监控工具:通过 Kibana Monitoring 观察indexing_ratemerge_time ,针对性优化
  3. Elasticsearch 和关系型数据库的写入区别
    • 数据模型:ES 时 Schema-less 的文档模型,支持动态字段;关系数据库需预定义 Schema
    • 事务性:ES 不支持 ACID 事务,依赖版本号(_version )实现乐观锁
    • 写入延迟:ES 的 NRT(近实时)vs 数据库的实时可见
  4. Refresh 机制对写入性能的影响
    • Refresh 操作将内存缓冲区中的数据生成新的 Lucene Segment,写入文件系统缓存(非磁盘),使数据可被搜索)
    • 频繁 Refresh 会导致产生大量小 Segment,增加 Merge 开销(I/O 和 CPU 竞争)
    • 日志数据:设置refresh_interval: 30s 甚至-1 (关闭自动 Refresh),通过手动 Refresh 控制搜索可见性
    • 高查询压力:避免长时间不 Refresh,否则新数据无法被搜索
    • 监控指标:通过_nodes/states/indices/ API 观察refresh_tatolrefresh_time_in_millis ,评估 Refresh 开销
  5. 主分片与副本分片的写入同步
    • 主分片写入成功后,会并行向所有副本分片发送写入请求
    • 副本分片写入成功后,主分片才向客户端返回确认
    • wait_for_active_shards: quorm (默认):多数分片(主 + 副本)可用时写入成功
    • wati_for_active_shards: 1 :仅主分片成功即可(风险:副本可能落后)
    • 若副本分片写入失败,主分片会向 Master 节点报告,触发分片重分配
    • 集群状态变为Yellow ,直到副本恢复
  6. 设计一个支持亿级日志写入的系统,你会如何规划 ES 集群?
    • 分片设计:按时间滚动索引(如logs-2023-10 ),单个分片大小控制在 50GB 以内
    • 写入优化:使用 Bulk API,客户端侧实现批量压缩与重试机制
    • 硬件规划:独立 Ingest 节点处理数据预处理,Data 节点使用 NVMe SSD
    • 可靠性:设置index.translog.durability: async ,副本数设为 1
    • 监控:通过 ILM(索引生命周期管理)自动归档旧索引到冷存储
  7. 为什么 Elasticsearch 查询比数据库快?
    • 倒排序索引:快速定位文档,避免全表扫描。
    • 分布式并行:查询拆分到多个分片并行执行。
    • 文件系统缓存:Segment 文件缓存在 OS Cache,减少磁盘 IO。
    • 列式存储(doc_values ):优化排序与聚合。
  8. 如何处理数据一致性问题?
    • 写入一致性:通过wait_for_active_shards 控制最小成功分片数。
    • 版本控制:
      • 使用_version 实现乐观锁,避免并发覆盖。
      • 外部版本号(version_type=external )兼容数据库同步。
    • 读一致性:
      • preference=_primary :强制读主分片(强一致性,性能低)。
      • replication=async :异步副本更新(最终一致性,性能高)。
  9. 如何设计一个高可用 ES 集群?
    • 节点角色分离:
      • 专用 Master 节点(3台,避免脑裂)。
      • 独立 Data 节点、Ingest 节点、Coordination 节点。
    • 分片策略:
      • 副本数≥1,跨机架分布(awareness 参数)。
      • 使用ILM(索引生命周期管理)自动滚动索引。
    • 容灾备份:
      • 快照(Snapshot)到 S3/NFS,支持跨集群恢复。
      • 多集群同步(CCR,跨集群复制)。