ES101系列07 | 分布式系統和分頁

本篇文章主要講解 ElasticSearch 中分布式系統的概念,包括節點、分片和并發控制等,同時還會提到分頁遍歷和深度遍歷問題的解決方案。

節點

  • 節點是一個 ElasticSearch 示例
    • 其本質就是一個 Java 進程
    • 一個機器上可以運行多個示例但生產環境推薦只運行一個
  • 每一個節點都有名字,通過配置文件配置
  • 每一個節點啟動后都會分配一個 UID,保存在 data 目錄下
Coordinating Node
  • 處理請求的節點,叫 Coordinating Node
    • 路由請求到正確的節點,例如創建索引的請求,需要路由到 Master
  • 所有節點默認都是 Coordinating Node
  • 通過將其他類型設置成 False,使其成為 Dedicated Coordinating Node
Data Node
  • 可以保存數據的節點,叫做 Data Node
    • 節點啟動后,默認就是數據節點。可以設置 node.data:false 禁止
  • Data Node 的職責
    • 保存分片數據。在數據擴展上起到了至關重要的作用(由 Master Node 決定如何把分片分發到數據節點上)
  • 通過增加數據節點
    • 可以解決數據水平擴展和解決數據單點問題
Master Node
  • Master Node 的職責
    • 處理創建,刪除索引等請求/決定分片被分配到哪個節點 /負責索引的創建與刪除
    • 維護并且更新 Cluster State
  • Master Node 的最佳實踐
    • Master 節點非常重要,在部署上需要考慮解決單點的問題
    • 為一個集群設置多個 Master 節點/每個節點只承擔 Master 的單一角色
Master Eligible Nodes
  • 一個集群,支持配置多個 Master Eligible 節點。這些節點可以在必要時(如 Master 節點出現故障,網絡故障時)參與選主流程,成為 Master 節點
  • 每個節點啟動后,默認就是一個 Master Eligible 節點
    • 可以設置 node.master: false 禁止
  • 當集群內第一個 Master Eligible 節點啟動時候,它會將自己選舉成 Master 節點
選主過程
  • 互相 Ping 對方,Node ld 低的會成為被選舉的節點
  • 其他節點會加入集群,但是不承擔 Master 節點的角色。一旦發現被選中的主節點丟失,就會選舉出新的 Master 節點
腦裂問題
  • Split-Brain,分布式系統的經典網絡問題,當出現網絡問題,一個節點和其他節點無法連接
    • Node 2 和 Node 3 會重新選舉 Master
    • Node 1 自己還是作為 Master 組成一個集群,同時更新 Cluster State
    • 導致 2 個 Master 維護不同的 Cluster State,當網絡恢復時,無法選擇正確恢復

解決方法

  • 限定選舉條件,設置 quorum(仲裁),只有當 Master Eligible 節點數大于 quorum 時才能進行選舉
  • 7.0 后無需配置

分片

Primary Shard
  • 分片是 ElasticSearch 分布式存儲的基石(主分片 / 副本分片)
  • 通過主分片,將數據分布在所有節點上
    • Primary Shard 可以將一份索引的數據分散在多個 Data Node 上,實現存儲的水平擴展
    • 主分片數在索引創建時候指定,后續默認不能修改,如要修改需重建索引
Replica Shard
  • 數據可用性
    • 通過引入副本分片(Replica Shard)提高數據的可用性。一旦主分片丟失,副本分片可以 Promote 成主分片。副本分片數可以動態調整。每個節點上都有完備的數據。如果不設置副本分片,一旦出現節點硬件故障,就有可能造成數據丟失
  • 提升系統的讀取性能
    • 副本分片由主分片(Primary Shard)同步。通過支持增加 Replica 個數,一定程度可以提高讀取的吞吐量
分片數的設定
  • 如何規劃一個索引的主分片數和副本分片數
    • 主分片數過小:例如創建了 1 個 Primary Shard 的 Index。如果該索引增長很快,集群無法通過增加節點實現對這個索引的數據擴展
    • 主分片數設置過大:導致單個 Shard 容量很小,引發一個節點上有過多分片,影響性能
    • 副本分片數設置過多,會降低集群整體的寫入性能
集群健康狀態
GET /_cluster/health{"cluster_name" : "lanlance","status" : "green","timed_out" : false,"number_of_nodes" : 2,"number_of_data_nodes" : 2,"active_primary_shards" : 21,"active_shards" : 42,"relocating_shards" : 0,"initializing_shards" : 0,"unassigned_shards" : 0,"delayed_unassigned_shards" : 0,"number_of_pending_tasks" : 0,"number_of_in_flight_fetch" : 0,"task_max_waiting_in_queue_millis" : 0,"active_shards_percent_as_number" : 100.0
}
  • Green:健康狀態,所有的主分片和副本分片都可用
  • Yellow:亞健康,所有的主分片可用,部分副本分片不可用
  • Red:不健康狀態,部分主分片不可用
文檔到分片的路由算法
  • s h a r d = h a s h ( r o u t i n g ) / 主分片數 shard = hash(routing) / 主分片數 shard=hash(routing)/主分片數
    • Hash 算法確保文檔均勻分散到分片中
    • 默認 routing 值是文檔 id
    • 可以自行制定 routing 值,與業務邏輯綁定也可以
    • 是 Primary Shard 數不能修改的根本原因

刪除一個文檔的流程

分片的內部原理
倒排索引的不可變性

倒排索引采用 Immutable Design,一旦生成,不可更改

不可變性,帶來了的好處如下:

  • 無需考慮并發寫文件的問題,避免了鎖機制帶來的性能問題
  • 一旦讀入內核的文件系統緩存,便留在哪里。只要文件系統存有足夠的空間,大部分請求就會直接請求內存,不會命中磁盤,提升了很大的性能
  • 緩存容易生成和維護/數據可以被壓縮

但壞處是如果需要讓一個新的文檔可以被搜索,需要重建整個索引。

Lucene Index
  • 在 Lucene 中,單個倒排索引文件被稱為 Segment。Segment 是自包含的,不可變更的。多個 Segments 匯總在一起稱為 Lucene 的 Index,其對應的就是 ES 中的 Shard
  • 當有新文檔寫入時,會生成新 Segment,查詢時會同時查詢所有 Segments,并且對結果匯總。Lucene 中有一個文件用來記錄所有 Segments 信息,叫做 Commit Point

Refresh
  • 將 Index buffer 寫入 Segment 的過程叫 Refresh。Refresh 不執行 fsync 操作
  • Refresh 默認 1 秒發生一次,可通過 index.refresh_interval 配置。Refresh 后數據就可以被搜索到了。這也是為什么 ElasticSearch 被稱為近實時搜索
  • 如果系統有大量的數據寫入,那就會產生很多的 Segment
  • Index Buffer 被占滿時會觸發 Refresh,默認值是 JVM 的 10%
Transaction Log
  • Segment 寫入磁盤的過程相對耗時,借助文件系統緩存,Refresh 時先將 Segment 寫入緩存以開放查詢
  • 為了保證數據不會丟失,所以在 Index 文檔時同時寫 Transaction Log,高版本開始 Transaction Log 默認落盤。每個分片有一個 Transaction Log
  • 在 ES Refresh 時 Index Buffer 被清空,Transaction log 不會清空
Flush
  • 調用 Refresh,清空 Index Buffer
  • 調用 fsync,將緩存中的 Segments 寫入磁盤
  • 清空 Transaction Log

默認 30 分鐘調用一次,當 Transaction Log 滿時(默認 512 MB)也會調用

Merge
  • Segment 很多,需要被定期合并
    • 減少 Segments / 真正刪除已經刪除的文檔
  • ES 和 Lucene 會自動進行 Merge 操作
    • POST my_index / _forcemerge
分布式搜索的運行機制

ElasticSearch 的搜索會分為 Query 和 Fetch 兩階段進行。

Query
  • 用戶發出搜索請求到 ES 節點。節點收到請求后,會以 Coordinating 節點的身份,在 6 個主副分片中隨機選擇 3 個分片,發送查詢請求。
  • 被選中的分片執行查詢,進行排序。每個分片都會返回 From+Size 個排序后的文檔 Id 和排序值給 Coordinating 節點。
Fetch
  • Coordinating Node 會將 Query 階段從每個分片獲取的排序后的文檔 Id 列表重新進行排序。選取 From 到 From+Size 個文檔的 Id。
  • 以 multiget 請求的方式到相應的分片獲取詳細的文檔數據。

潛在有性能不好和相關性算分不準的問題。

解決算分不準的問題
  • 數據量不大的時候主分片數設置為 1,數據量大的時候保證文檔均勻分散在各個分片上。
  • 使用 DFS Query Then Fetch。會進行一次完整的相關性算法,耗費更多資源,性能不好。
排序
  • 排序是針對字段原始內容進行的,倒排索引無法發揮作用,需要正排索引。
  • ElasticSearch 中有兩種實現方法。
    • FieldData
    • Doc Values(列式存儲,對 Text 類型無效)

Doc Values 和 Field Data 比較:

特性Doc ValuesField Data
存儲位置磁盤 (內存映射訪問)堆內存 (JVM Heap)
加載時機按需加載 (惰性加載到 OS 緩存)按需構建 (首次用于聚合/排序時構建在內存中)
數據結構列式存儲 (按文檔 ID 組織值)列式存儲 (按段構建)
適用字段keyword, numeric, date, ip, booleantext (默認關閉),其他字段類型 (已廢棄)
默認啟用 (對于支持它的字段類型) (尤其對于 text 字段,7.0+ 默認關閉)
內存占用 (利用 OS 文件緩存,不直接占用 JVM 堆) (直接占用 JVM 堆內存)
垃圾回收無影響 (由 OS 管理緩存)顯著影響 (對象在堆上,易引發 GC 壓力)
適用操作聚合、排序、腳本 (高效)text 字段聚合 (分詞后的詞條)
安全性 (不易引發 OOM) (不當配置易導致節點 OOM)
版本趨勢推薦并默認僅限 text 字段聚合需求 (其他字段已棄用)

分頁和遍歷

分布式系統中深度分頁的問題
  • ES 天生就是分布式的。查詢信息同時數據保存在多個分片、多臺機器上,ES 天生就需要滿足排序的需要(按照相關性算分)。
  • 當一個查詢:From=990,Size =10。會在每個分片上先都獲取 1000 個文檔。通過 Coordinating Node 聚合所有結果。最后再通過排序選取前 1000 個文檔。
  • 頁數越深,占用內存越多。為了避免深度分頁帶來的內存開銷。ES 有一個設定,默認限定到 10000 個文檔。
使用 Search After 避免深度分頁問題
  • 避免深度分頁的性能問題,可以實時獲取下一頁文檔信息
    • 不支持指定頁數 (From)
    • 只能往下翻
  • 第一步搜索需要指定 sort,并且保證值是唯一的 (可以通過加入 id 保證唯一性)
  • 然后使用上一次最后一個文檔的 sort 值進行查詢。

示例

1、插入數據

POST users/_doc
{"name":"user1","age":10}
POST users/_doc
{"name":"user2","age":11}
POST users/_doc
{"name":"user2","age":12}
POST users/_doc
{"name":"user2","age":13}

2、執行查詢

POST users/_search
{"size": 1,"query": {"match_all": {}},"sort": [{"age": "desc"} ,{"_id": "asc"}    ]
}POST users/_search
{"size": 1,"query": {"match_all": {}},"search_after":[10,"ZQ0vYGsBrR8X3IP75QqX"],"sort": [{"age": "desc"} ,{"_id": "asc"}    ]
}
Scroll API

Scroll API 是 Elasticsearch 為大數據集深度遍歷設計的查詢機制,通過創建快照式上下文(Snapshot Context)保證分頁一致性,適用于離線導出、全量遷移等場景。

示例

DELETE users
POST users/_doc
{"name":"user1","age":10}
POST users/_doc
{"name":"user2","age":20}
POST users/_doc
{"name":"user3","age":30}
POST users/_doc
{"name":"user4","age":40}POST /users/_search?scroll=5m
{"size": 1,"query": {"match_all" : {}}
}// 這條數據無法查到
POST users/_doc
{"name":"user5","age":50}POST /_search/scroll
{"scroll" : "1m","scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAWAWbWdoQXR2d3ZUd2kzSThwVTh4bVE0QQ=="
}

Scroll API 與 Search After 的對比

特性Search AfterScroll API
設計目標實時深度分頁(用戶交互場景)大數據集離線遍歷(導出/遷移)
實時性基于當前索引狀態(實時可見變更)快照凍結(創建后索引變更不可見)
內存消耗低(無服務端狀態)高(服務端維護上下文,占用堆內存)
分頁一致性依賴 PIT 保障一致性天然一致性(快照隔離)
適用場景用戶界面逐頁瀏覽(如訂單列表翻頁)全量數據導出、ETL 遷移、離線分析
是否支持跳頁? 僅順序連續分頁? 僅順序連續遍歷
資源釋放無狀態(客戶端自主管理游標)需顯式刪除 Scroll ID(否則超時釋放)
性能開銷低(分片級游標定位)中(維護上下文,但比 from/size 高效)
最大深度僅受文檔總數限制同左
推薦排序方式業務字段 + _id(確保唯一性)["_doc"](最高效,避免排序計算)
版本演進主流實時分頁方案(結合 PIT 使用)逐漸被 Async Search 替代(大數據異步查詢)

并發控制

ES 使用樂觀鎖進行并發控制。

ES 的樂觀并發控制

ES 中的文檔是不可變更的。如果你更新一個文檔,會將就文檔標記為刪除,同時增加一個全新的文檔。同時文檔的 version 字段加 1。

示例

DELETE products
PUT products
PUT products/_doc/1
{"title":"iphone","count":100
}// success
PUT products/_doc/1?if_seq_no=1&if_primary_term=1
{"title":"iphone","count":100
}// fail
PUT products/_doc/1?if_seq_no=1&if_primary_term=1
{"title":"iphone","count":102
}// success
PUT products/_doc/1?version=30000&version_type=external
{"title":"iphone","count":100
}

寫在最后

這是該系列的第七篇,主要講解 ElasticSearch 中分布式系統的概念,包括節點、分片和并發控制等,同時提到了分頁遍歷和深度遍歷問題的解決方案。可以自己去到 Kibana 的 Dev Tool 實戰操作,未來會持續更新該系列,歡迎關注👏🏻。

同時歡迎關注小紅書:LanLance。不定時分享職場思考、大廠方法論和后端經驗??

參考

  1. https://github.com/onebirdrocks/geektime-ELK/
  2. https://www.elastic.co/elasticsearch/

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/908203.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/908203.shtml
英文地址,請注明出處:http://en.pswp.cn/news/908203.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

CppCon 2015 學習:3D Face Tracking and Reconstruction using Modern C++

1. 3D面部追蹤和重建是什么? 3D面部追蹤(3D Face Tracking): 實時檢測并追蹤人臉在三維空間中的位置和姿態(如轉頭、點頭、表情變化等),通常基于攝像頭捕獲的視頻幀。3D面部重建(3D…

代碼中的問題及解決方法

目錄 YOLOX1. AttributeError: VOCDetection object has no attribute cache2. ValueError: operands could not be broadcast together with shapes (8,5) (0,)3. windows遠程查看服務器的tensorboard4. AttributeError: int object has no attribute numel YOLOX 1. Attribu…

【JVM】Java類加載機制

【JVM】Java類加載機制 什么是類加載? 在 Java 的世界里,每一個類或接口在經過編譯后,都會生成對應的 .class 字節碼文件。 所謂類加載機制,就是 JVM 將這些 .class 文件中的二進制數據加載到內存中,并對其進行校驗…

vue的監聽屬性watch的詳解

文章目錄 1. 監聽屬性 watch2. 常規用法3. 監聽對象和route變化4. 使用場景 1. 監聽屬性 watch watch 是一個對象,鍵是需要觀察的表達式,用于觀察 Vue 實例上的一個表達式或者一個函數計算結果的變化。回調函數的參數是新值和舊值。值也可以是方法名&am…

如何在 Ubuntu 24.04 服務器上安裝 Apache Solr

Apache Solr 是一個免費、開源的搜索平臺,廣泛應用于實時索引。其強大的可擴展性和容錯能力使其在高流量互聯網場景下表現優異。 Solr 基于 Java 開發,提供了分布式索引、復制、負載均衡及自動故障轉移和恢復等功能。 本教程將指導您如何在 Ubuntu 24.…

Linux內核中TCP三次握手的實現機制詳解

TCP三次握手是建立可靠網絡連接的核心過程,其在內核中的實現涉及復雜的協議棧協作。本文將深入分析Linux內核中三次握手的實現機制,涵蓋客戶端與服務端的分工、關鍵函數調用、協議號驗證及數據包處理流程。 一、三次握手的整體流程 三次握手分為三個階段,客戶端與服務端通過…

服務器--寶塔命令

一、寶塔面板安裝命令 ?? 必須使用 root 用戶 或 sudo 權限執行! sudo su - 1. CentOS 系統: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系統…

優化 Spring Boot API 性能:利用 GZIP 壓縮處理大型有效載荷

引言 在構建需要處理和傳輸大量數據的API服務時,響應時間是一個關鍵的性能指標。一個常見的場景是,即使后端邏輯和數據庫查詢已得到充分優化,當API端點返回大型數據集(例如,數千條記錄的列表)時&#xff0…

【WPF】WPF 項目實戰:構建一個可增刪、排序的光源類型管理界面(含源碼)

💡WPF 項目實戰:構建一個可增刪、排序的光源類型管理界面(含源碼) 在實際的圖像處理項目中,我們經常需要對“光源類型”進行篩選或管理。今天我們來一步步構建一個實用的 WPF 界面,實現以下功能&#xff1…

C++23 已棄用特性

文章目錄 1. std::aligned_storage 與 std::aligned_union1.1 特性介紹1.2 被棄用的原因1.3 替代方案 2. std::numeric_limits::has_denorm2.1 特性介紹2.2 被棄用的原因 3. 總結 C23 已棄用特性包括:std::aligned_storage、std::aligned_union 與 std::numeric_lim…

十三、【核心功能篇】測試計劃管理:組織和編排測試用例

【核心功能篇】測試計劃管理:組織和編排測試用例 前言準備工作第一部分:后端實現 (Django)1. 定義 `TestPlan` 模型2. 生成并應用數據庫遷移3. 創建 `TestPlanSerializer`4. 創建 `TestPlanViewSet`5. 注冊路由6. 注冊到 Django Admin第二部分:前端實現 (Vue3)1. 創建 `Test…

STM32最小CLion開發環境

文章目錄 1 必須文件2 工具鏈3 CLion 全局配置4 CLion 新項目配置ST-Link 調試 5 點亮 LED6 分析 elf 文件7 項目模板 1 必須文件 ST 提供的頭文件支持 MDK-ARM, GCC, IAR 3種編譯器, 下面采用 GCC 編譯器 Arm GNU Toolchain Downloads – Arm Developer 或 安裝包版 調試器服…

核函數:解鎖支持向量機的強大能力

在機器學習的世界中,支持向量機(SVM)是一種強大的分類算法,而核函數則是其背后的“魔法”,讓 SVM 能夠處理復雜的非線性問題。今天,我們就來深入探討核函數的奧秘,看看它們是如何幫助 SVM 在高維…

【Go-6】數據結構與集合

6. 數據結構與集合 數據結構是編程中用于組織和存儲數據的方式,直接影響程序的效率和性能。Go語言提供了多種內置的數據結構,如數組、切片、Map和結構體,支持不同類型的數據管理和操作。本章將詳細介紹Go語言中的主要數據結構與集合&#xf…

3. 簡述node.js特性與底層原理

😺😺😺 一、Node.js 底層原理(簡化版) Node.js 是一個 基于 Chrome V8 引擎構建的 JavaScript 運行時,底層核心由幾部分組成: 組成部分簡要說明 1.V8 引擎 將 JS 編譯成機器碼執行&#xff0…

Web開發主流前后端框架總結

🖥 一、前端主流框架 前端框架的核心是提升用戶界面開發效率,實現高交互性應用。當前三大主流框架各有側重: React (Meta/Facebook) 核心特點:采用組件化架構與虛擬DOM技術(減少真實DOM操作,優化渲染性能&…

大語言模型備案與深度合成算法備案的區別與聯系

“什么情況下做算法備案?” “什么情況下做大模型備案呢?” 進行大模型備案的企業必然要進行算法備案,而進行算法備案的企業則需根據其提供的服務性質判斷是否需要進行大模型備案。 算法備案與大模型備案已經是個老生常談的話題了&#xf…

微軟PowerBI考試 PL300-Power BI 入門

Power BI 入門 上篇更新了微軟PowerBI考試 PL-300學習指南,今天分享PowerBI入門學習內容。 簡介 Microsoft Power BI 是一個完整的報表解決方案,通過開發工具和聯機平臺提供數據準備、數據可視化、分發和管理。 Power BI 可以從使用單個數據源的簡單…

【Hive入門】

之前實習寫的筆記,上傳留個備份。 1. 使用docker-compose快速搭建Hive集群 使用docker快速配置Hive環境 拉取鏡像 2. Hive數據類型 隱式轉換:窄的可以向寬的轉換顯式轉換:cast 3. Hive讀寫文件 SerDe:序列化(對象轉為字節碼…

設計模式——簡單工廠模式(創建型)

摘要 本文主要介紹了簡單工廠模式,包括其定義、結構、實現方式、適用場景、實戰示例以及思考。簡單工廠模式是一種創建型設計模式,通過工廠類根據參數決定創建哪一種產品類的實例,封裝了對象創建的細節,使客戶端無需關心具體類的…