Elasticsearch 寫入全鏈路:從單機到集群

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…