0. 先把术语摆正

  • Index(索引):逻辑数据集合,≈ MySQL 的库。
  • Document(文档):一条 JSON 数据,≈ MySQL 的行。
  • Field(字段):文档里的键值,≈ MySQL 的列。
  • Shard(分片):一个索引被水平拆成 N 份(primary主 + replica副本)。
  • Segment:Lucene 最小存储单元(文件不可变);很多机制围着它转。
  • 倒排索引:term → posting list(文档 ID 列表)。
  • Doc Values:列式存储,用于排序/聚合(不是倒排索引)。
  • File System Cache:OS 级缓存,并非落盘。

ES 搜索是近实时(NRT),不是强实时。写入到可被搜索看到,中间隔着一个 refresh


1. 单机写入:一条写请求到底发生了什么?

1.1 写入过程(Index/Insert/Update)

  1. Analyzer 分析:对 text 字段分词(如 IK),keyword/数值/日期 不分词;可能生成多字段(text+keyword)。

  2. 写入内存 buffer:用于构建倒排索引/列存结构;此时搜索不可见

  3. 追加 translog:同时把这次操作追加写入 translog 文件(磁盘上的操作日志文件,但默认先进 OS page cache,有个参数控制什么时候真正落盘,1.3会提到,其实默认就是直接刷盘)。

  4. refresh(默认 1s):把内存 buffer 的内容刷新为新的 segment

    • 新 segment 进入 file system cache,从此搜索可见
    • 这一步不是持久化,只是“可被搜索到”。
  5. flush(定期或阈值触发):强制把缓存中的 segment 落到磁盘,清空 translog,形成安全的持久化点(commit point)。

  6. merge(后台线程):自动把多个小 segment 合并成更大的 segment,清理删除标记,降低查询开销。

1.2 GET-by-id 与搜索的可见性不同

  • GET index/_doc/id:默认实时realtime=true),即使没 refresh,也能从 translog 读取最新版本。
  • _search 查询:需要 refresh 后的新 segment 才能看到(NRT)。

1.3 translog 的持久化策略

  • index.translog.durability=request(默认):每次写请求结束前执行 fsync,确保 translog 已真正落到物理盘

    • 安全但慢。
  • index.translog.durability=async:写入 translog 后不立刻 fsync,按 index.translog.sync_interval(默认 5s)定期批量 fsync。

    • 快,但节点崩溃时可能丢失最近一个 sync_interval 窗口的数据。

重点区分:“写入 translog 文件” ≠ “fsync 到磁盘盘片”。前者可能仅到 OS page cache;后者才是不可丢的落盘。

1.4 refresh / flush / merge 的触发与作用

  • refresh

    • 触发:周期(index.refresh_interval,默认 1s)/ 手动 / 写多时可临时关闭(设为 -1)再打开批量refresh以提速。
    • 作用:生成新 segment,使数据可被搜索
  • flush

    • 触发:定时(常见 30min 级别)、translog 过大、手动。
    • 作用:把 segment 真正落盘清空 translog,形成安全恢复点。注意,translog只是操作日志而不是实际数据segment的落盘。
  • merge

    • 触发:Lucene 的合并策略自动决定(如分层合并,逐级把小段并大)。
    • 作用:减少 segment 数/删除开销,提升搜索性能,但会吃 IO/CPU。

简要心智图:
写 → buffer + translog →(1s)refresh(可查但未持久化)→(周期/阈值)flush(持久化并清空 translog)→(后台)merge(优化查询)。


2. 从单机到集群:协调、路由与复制

2.1 写入复制流程(Primary-Replica)

  1. 客户端 → 任意节点(作为协调节点)。
  2. 协调节点计算目标 主分片,把请求转发过去。
  3. 主分片执行写入(buffer + translog),并把操作并行转发给所有副本分片。
  4. 副本分片执行同样的写入(buffer + translog)。
  5. 所有副本 ACK 后,主分片返回给协调节点 → 客户端。

注意:一条文档只会写入它所属的 一个主分片 + 其副本,不是所有分片。

2.2 协调节点(Coordinating Node)是怎么来的?

  • 不是选举出来的固定角色:谁接到客户端请求,谁临时扮演协调节点。

  • 为什么需要它

    1. 屏蔽路由细节(客户端不必知道分片在哪个节点),如果没有他,客户端就必须保存每个内容的主分片在哪个节点,这肯定不合理。。
    2. 适应集群动态(分片会迁移/升副为主)。
    3. 压力均衡(请求可打到任意节点,由它路由)。

2.3 路由规则与分片定位

  • 所有节点都知道这两个内容:

    • 路由算法shard = hash(_id) % number_of_primary_shards
    • 分片位置:通过 Cluster State(由 master 维护并分发)得知“某分片的主/副在谁那里”。

2.4 一致性与可用性参数

  • wait_for_active_shards:控制写入前需要有多少份分片处于 active 才返回;

    • 1(默认)仅等主分片;all 等主 + 所有副本。
  • 副本数 number_of_replicas:副本越多,读扩展强、容错高,写入成本也越高。

  • 失败与恢复:主分片宕机会由某个副本提升为新的主分片;通过序列号/主 term 等元数据保证顺序与幂等。


3. Segment 细节:为什么会有重复 term?查询怎么处理?

  • 每次 refresh 都会产出一个独立的小 segment;不同 segment 彼此独立,相同 term 会重复存在
  • 查询阶段:Lucene 会同时在多个 segment 里查同一 term 的 posting list,并把结果归并
  • merge 阶段:把多段合成大段,合并相同 term 的 posting,并物理清理删除标记(tombstones)。

这也是为什么 segment 过多会拖慢查询,merge 能提速但会消耗资源。


4. 字段与索引结构:不是所有字段都是倒排表

  • text:分词,建立倒排索引(term→posting)。
  • keyword:不分词,整个值作为一个 term 建倒排(适合精确匹配、聚合)。
  • 数值/日期/地理:不是倒排,使用 BKD 树/空间索引 支持范围/地理查询。
  • index: false:不建索引,只存储,无法被检索。
  • 多字段(multi-fields):一个字段既是 text 又是 keyword,兼顾全文与精确匹配。

5. 可观测与常用调优

5.1 可见性相关参数

  • index.refresh_interval:默认 1s;批量写入建议临时设为 -1,完毕后再改回。
  • index.translog.durabilityrequest(默认,安全) / async(快,可能丢最近一个窗口)。
  • index.translog.sync_intervalasync 模式下 fsync 周期,默认 5s

5.2 写入吞吐相关手段

  • Bulk 批量写:合并网络/解析开销;控制合理批大小(几 MB~几十 MB)。

  • 副本与刷新策略

    • 导入期可把副本数临时设为 0,导入完成再恢复。
    • 刷新间隔设为 -1,导入完成手动 _refresh
  • 映射与字段控制:禁用不需要的索引/存储/来源字段(如关闭 _all、合理控制 doc_values)。

  • Merge 影响:高写入期可以调节合并限速(避免打爆 IO),导入后允许合并充分进行以稳定查询性能。

5.3 故障与恢复

  • 宕机恢复:依赖 translog 回放 + 上次 flush 的 commit point。
  • 副本恢复:主分片把缺失的 segment/操作日志同步给副本,直到达到一致。

6. 协调节点到底值不值得?(设计权衡)

  • 好处:隐藏路由、承接集群动态、均衡负载、简化客户端。
  • 代价:多一跳转发(但通常可忽略),以及所有节点需要持有最新 Cluster State(大集群可能膨胀,需要控制索引/映射规模)。

7. 一些面试点

Q1:为什么 ES 写入快、搜索也快?
A:倒排索引/列存结构 + 分片并行 + OS cache + 针对数值/地理的 BKD/空间索引;查询时多段归并,merge 降段数。

Q2:写入成功是不是所有分片都写了?
A:不是。一条文档只落到一个主分片及其所有副本。

Q3:写入成功后为什么搜索不到?
A:还没 refresh(默认 1s)。可手动 _refresh,或等下一次 refresh。GET-by-id 默认可见(realtime)。

Q4:translog 是不是“写盘”了?还会丢?
A:写入 translog 后若没 fsync,只在 OS page cache,机器掉电可能丢。durability=request 会在返回前 fsync,安全;async 依赖 sync_interval,窗口内可能丢。

Q5:merge 什么时候发生?会影响性能吗?
A:后台自动按策略触发;会吃 IO/CPU,写入高峰要限速/合理配置,导入完成后让它合并以稳定查询时延。

Q6:为什么需要协调节点?
A:简化客户端、适应分片迁移/升主、均衡负载;谁接到请求谁协调。


8. 小结

单机:写 → buffer + translog → refresh(可搜) → flush(持久化) → merge(优化)。
集群:任一节点临时协调 → 定位主分片 → 写主并同步副本 → 返回。
可靠性durability=request 安全;async + sync_interval 快但可能丢最近窗口。
设计哲学:用不可变 segment + 异步合并,换取简单、稳定、可伸缩。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/919625.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/919625.shtml
英文地址,请注明出处:http://en.pswp.cn/news/919625.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java多线程编程——基础篇

目录 前言 一、进程与线程 1、进程 2、线程 二、并发与并行 1、并发 2、并行 三、线程调度 1、CPU时间片 2、调度方式 ①时间片轮转 ②抢占式调度 四、线程实现方式 1、继承 Thread 类 Thread的多种构造函数: 2、实现 Runnable 接口 五、线程的核心方法 1、start() …

阿里云的centos8 服务器安装MySQL 8.0

在 CentOS 8 上安装 MySQL 8.0 可以通过添加 MySQL 官方 YUM 仓库并使用 dnf 命令安装。以下是具体步骤: 步骤如下: 下载并添加 MySQL 官方 YUM 仓库 运行以下命令下载 MySQL 8.0 的 YUM 仓库配置文件: sudo dnf install https://dev.mysql.…

【运维进阶】Linux 正则表达式

Linux 正则表达式定义:正则表达式是一种pattern(模式),用于与待搜索字符串匹配,以查找一个或多个目标字符串。组成:自成体系,由两类字符构成普通字符:未被显式指定为元字符的所有可打…

STM32输入捕获相位差测量技术详解(基于TIM1复位模式)

本文将深入解析基于STM32定时器输入捕获功能的方波相位差测量技术,通过复位模式实现高精度相位检测。以下是完整的代码实现与详细原理分析。一、相位差测量原理相位差测量基于两个同频方波信号下降沿时间差计算。核心原理:​复位模式​:将TIM…

什么是股指期货可转移阿尔法策略?

阿尔法(Alpha)是投资领域的一个术语,用来衡量投资组合的超额收益。简单来说,阿尔法就是你在市场上赚的比平均水平多出来的那部分钱。比如,市场平均收益率是5%,但你的投资组合收益率是10%,那你的…

AXI GPIO S——ZYNQ学习笔记10

AXI GPIO 同意通道混合输入输出中断控制#KEY set_property IOSTANDARD LVCMOS18 [get_ports {AXI_GPIO_KEY_tri_io[0]}] set_property PACKAGE_PIN J13 [get_ports {AXI_GPIO_KEY_tri_io[0]}] set_property IOSTANDARD LVCMOS18 [get_ports {AXI_GPIO_KEY_tri_io[1]}] set_pro…

如何通过传感器选型优化,为设备寿命 “续航”?

在当今竞争激烈的工业领域,企业就像在一场没有硝烟的战争中角逐,设备便是企业的“秘密武器”。设备的使用寿命,如同武器的耐用程度,直接决定了企业在生产战场上的“战斗力”。延长设备寿命,已然成为众多企业降低生产成…

WebSocket连接的例子

// 初始化WebSocket连接 const initWebSocket () > {console.log("初始化链接中...")const websocketUrl ws://61.54.84.16:9090/;// WebSocket服务器地址websocket new WebSocket(websocketUrl)//使用真实的webscket// websocket new MockWebSocket(websocket…

c++之指针和引用

一 使用场景 C++ 什么时候使用指针?什么时候使用引用?什么时候应该按值传递?_引用什么时候用比较好-CSDN博客 只使用传递过来的值,而不对值进行修改 需要修改传递过来的值 内置数据类型 按值传递(小型结构) 指针传递 数组 指针传递 指针传递 结构 指针或引用(较大的结构…

pytorch学习笔记-模型训练、利用GPU加速训练(两种方法)、使用模型完成任务

应该算是完结啦~再次感谢土堆老师! 模型训练 模型训练基本可以分为以下几个步骤按序执行: 引入数据集-使用dataloader加载数据集-建立模型-设置损失函数-设置优化器-进行训练-训练中计算损失,并使用优化器更新参数-模型测试-模型存储 习惯上会…

深度卷积神经网络AlexNet

在提出LeNet后卷积神经网络在计算机视觉和机器学习领域中报有名气,但是卷积神经网络并没有主导这些领域,因为LeNet在小数据集上取得了很好的效果,在更大,更真实的数据集上训练卷积神经网络的性能 和可行性有待研究,20世…

数据结构-HashSet

在 Java 编程的世界里,集合框架是极为重要的一部分,而 HashSet 作为 Set 接口的典型实现类,在处理不允许重复元素的场景中频繁亮相。今天,我们就一同深入探究 HashSet,梳理它的特点、常用方法,以及和其他相…

心意行药号 · 慈心方的八种用法

心意行药号 慈心方的八种用法慈心方是心意行药号589个珍贵秘方中的一个养生茶方,配伍比例科学严谨,君臣佐使堪称经典,自古就有“小小慈心方,转动大乾坤”之说。自清代光绪年间传承至今,慈心方受益者逾百万计&#xff…

Spring面试宝典:Spring IOC的执行流程解析

在准备Spring框架的面试时,“Spring IOC的工作流程是什么?” 是一个非常经典的问题。虽然网上有很多详细的教程,但它们往往过于复杂,对于没有深入研究过源码的人来说理解起来确实有些困难。今天我们就来简化这个概念,从…

学习日志39 python

1 fromkeys()函数是什么在 Python 中,fromkeys() 是字典(dict)的一个类方法,用于创建一个新字典。它的作用是:根据指定的可迭代对象(如列表、元组等)中的元素作为键(key)…

SpringBoot + MyBatis-Plus 使用 listObjs 报 ClassCastException 的原因与解决办法

在项目中我们经常会遇到这种需求: 根据一组 ID 查询数据库,并返回指定字段列表。 我在写代码的时候,遇到了一个典型的坑,分享出来给大家。一、问题背景我的代码是这样写的(查询项目表的负责人信息)&#xf…

WT2606B 驱屏语音芯片新增蓝牙功能:功能集成一体化,产品升级自动化,语音交互无线化,场景应用普适化!

小伙伴们,欢迎来到我们的 #唯创芯片小讲堂!今天我们要为大家介绍一位多才多艺的"芯片全能手"——WT2606B驱屏语音芯片。这颗芯片将在今年8月的I0TE物联网展及ELEXCON 2025深圳国际电子展上大放异彩。在智能设备满天飞的今天&#x…

ORA-16331: container is not open ORA-06512: at “SYS.DBMS_LOGMNR“

使用Flink CDC、Debezium等CDC工具对Oracle进行基于log的实时数据同步时遇到异常ORA-16331: container is not open的解决方案。 1. 异常信息 异常信息通常如下: at oracle.jdbc.driver.OracleStatement.executeInternal(OracleStatement.java:1823) at oracle.jdbc…

「三维共振」:重构实体零售的破局模式

在电商冲击与消费升级的双重浪潮下,传统零售模式正面临前所未有的挑战。wo店首创的 “三维共振” 运营模式,以场景体验为根基、数据驱动为引擎、社群共生为纽带,构建起线上线下深度融合的新型零售生态,至今已实现连续 18 个月客流…

将集合拆分成若干个batch,并将batch存于新的集合

在使用saveAll()等方法时,为了防止集合元素过大,使用splitList将原集合,分割成若干个小集合 import java.util.ArrayList; import java.util.List;public class ListUtils {/*** 将集合拆分成若干个batch,并将batch存于新的集合** param list…