【PGCCC】在 Postgres 中構建復制安全的 LSM 樹

在這里插入圖片描述

在原生 Postgres 實現中,全文搜索由B 樹或GIN(廣義倒排索引)結構支持。這些索引針對相對快速的查找進行了優化,但受限于 B 樹的寫入吞吐量。

當我們構建pg_searchPostgres 搜索和分析擴展時,我們的優先級有所不同。為了成為 Elasticsearch 的有效替代方案,我們需要支持高效的實時掃描。我們選擇了一種更適合密集發布列表位圖和高數據采集工作負載的數據結構:日志結構化合并 ( LSM ) 樹。

然而,當我們在物理復制(允許 Postgres 將數據從主節點復制到一個或多個只讀副本的兩種機制之一)下測試 LSM 樹時,我們遇到了一些波折。最令人驚訝的是,我們發現 Postgres 基于預寫日志 (WAL) 傳輸機制構建的開箱即用的物理復制支持不足以讓LSM 樹這樣的高級數據結構實現復制安全。在本文中,我們將深入探討:

  1. LSM 樹的復制安全意味著什么
  2. Postgres 的 WAL 傳輸如何保證物理一致性
  3. 為什么原子日志對于邏輯一致性是必要的
  4. 我們如何利用鮮為人知但功能強大的 Postgres 設置hot_standby_feedback

什么是 LSM 樹?

圖片

日志結構合并樹 (LSM 樹) 是一種寫優化數據結構,常用于 RocksDB 和 Cassandra 等系統。

LSM 樹的核心思想是將隨機寫入轉換為順序寫入。傳入的寫入首先存儲在內存緩沖區(稱為 memtable)中,該緩沖區更新速度很快。一旦 memtable 寫滿,它將被刷新到磁盤,形成一個已排序的、不可變的段文件(通常稱為 SSTable)。

這些段文件按大小組織成層或級別。較新的數據寫入最頂層。隨著時間的推移,數據通過稱為“壓縮”的過程逐漸下推到較低的級別。在此過程中,較小段中的數據會被合并、去重,然后重寫到較大的段中。

復制安全是什么意思?

可靠的分布式數據存儲(保證“復制安全”)必須證明跨數據庫副本的物理和邏輯一致性。

  1. 物理一致性意味著副本包含結構有效的數據——磁盤上的每個頁面或塊都是格式良好的,并且對應于主節點上某個時刻存在的狀態。
  2. 邏輯一致性確保副本上的數據反映數據庫的一致且穩定的視圖,這是主數據庫上的事務可以看到的。

物理一致的狀態并不總是邏輯一致的狀態。具體來說,如果在復制正在進行的事務時拍攝物理一致的副本的快照,則它可能在邏輯上不一致。一個很好的比喻是想象復制一本書。物理一致性就像精確地復制每一頁,即使正在復制某一章的中間部分——保證有真實的頁面,但最終可能會缺少半句話或腳注。邏輯一致性就像等到章節完成后再復制,確保結果對讀者有意義。

WAL 傳輸:Postgres 如何保證物理一致性


在主備物理復制設置中,主服務器與備用服務器配對,備用服務器充當其主服務器的只讀副本。服務器通過使用預寫日志 (WAL) 來保持同步,在發生任何二進制更改之前,這些更改都會記錄在主服務器上的存儲塊上。然后,對此僅追加的 WAL 文件的更改將流式傳輸到備用服務器(此過程稱為“日志傳送”),并按接收的順序應用。此過程使兩臺服務器之間能夠實現近乎實時的數據同步,因此有“熱備”的說法。

為什么原子性是物理一致性的必要條件

原子性是物理一致性的必要條件,因為 Postgres 的鎖不會在副本服務器上重放。這是因為重放主服務器上獲取的每個鎖需要嚴格的時間同步,這會嚴重影響性能,并妨礙備用服務器提供讀取服務的能力。相反,WAL 使用每個緩沖區的鎖來按特定順序增量重放編輯:它獲取緩沖區(塊在內存中的表示形式)的獨占鎖,進行更改,然后釋放它。

當修改跨越多個 Postgres 緩沖區的數據結構時,就會出現問題。由于無法保證操作在整個結構上是原子的,這些修改可能會導致結構損壞。

例如:pg_search使用Postgres 緩沖區的展開鏈表,其中每個節點保存 LSM 樹中一批段的讀取有效性。為了確保主服務器永遠不會發現損壞的鏈表,我們使用了手動鎖定(也稱為鎖耦合)來保證該列表在主服務器上保持物理一致性。列表中的每個緩沖區被修改后,其 WAL 條目將在副本上以原子方式可見。

但是,當我們想要“一次性”(原子地)編輯列表中的多個條目時,例如當一個新壓縮的段替換多個舊段時,會發生什么情況?如果只有主服務器重要,那么我們可以通過在列表本身上應用全局鎖來保護多個列表節點的邏輯完整性,確保列表內容僅在有效狀態下可見。但是副本服務器無法訪問全局鎖,因此無法同時協調跨多個節點(和多個緩沖區)的編輯。

相反,對于多節點操作,pg_search使用列表的寫時復制 (CoW) 克隆,并在頭部進行原子交換。更一般地說,原子操作通過消除對粗粒度鎖的依賴,使免受危險。

問題:真空破壞邏輯一致性

在這里插入圖片描述

調整算法以在塊級別原子地工作是物理復制的賭注:如果不這樣做,您的數據結構就會被破壞,并且您將無法一致地使用它們。

但即使單個 WAL 操作和數據結構在原子上兼容,VACUUM也會干擾跨多個 WAL 條目的并發事務的執行,并損害邏輯一致性。

為了說明這個問題,假設主數據庫有一個包含一定數量行的表。為了確保并發寫入操作能夠安全地進行,而不會相互阻塞,Postgres 使用了一種稱為多版本并發控制 ( MVCC ) 的機制,該機制會為修改后的行(或元組)創建多個版本,而不是就地更新元組。當更新或刪除一行時,先前的元組不會被立即刪除,而是被標記為“已死”。

這些“死”的元組會一直保留在磁盤上,直到運行名為 VACUUM 的定期維護操作。與其他操作一樣,VACUUM 操作會記錄在 WAL 中,然后發送到備用數據庫,并在那里重放。

由于元組的“失效”發生在服務器本地,而 VACUUM 操作則會在全局范圍內重放,因此如果過早地從備庫中對某個元組執行 VACUUM 操作,則可能會出現錯誤。備庫可能正在讀取某個元組,并對其進行迭代(遍歷多個 WAL 條目),而主庫可能并發地決定執行 VACUUM 操作,將該元組從數據庫中移除。由于備庫缺乏任何鎖協調或對并發操作的感知,會在前一個事務仍在進行時重放 VACUUM 操作。如果一個長時間運行的查詢嘗試訪問已執行 VACUUM 操作的元組,則可能導致查詢失敗。

為什么 LSM 樹特別容易受到這個問題的影響

如果您的 Postgres 配置了只讀副本,并且寫入量很大,那么即使使用 B 樹索引,您可能也已經遇到過這個問題。如果在查詢命中只讀副本的同時,主服務器上正在運行 VACUUM,Postgres 可能會中止讀取操作。但是,在典型的 Postgres 設置中,這些錯誤可能很少發生,并且可以容忍,因為 VACUUM 每隔幾個小時運行一次。

但 LSM 樹的情況則不同,因為壓縮是系統的核心,并且是持續執行的部分。在高寫入吞吐量的系統中,壓縮每分鐘甚至每秒都可能發生多次。這增加了發生沖突的可能性。

與 VACUUM 類似,壓縮會重寫主服務器上的數據,并且需要知道正在進行的查詢何時不再需要該數據,以便能夠安全地刪除舊段。

合理的解決方案:熱備反饋

此時,Postgres 中一個可選的設置hot_standby_feedback就派上用場了。啟用后,hot_standby_feedback備用服務器可以告知主服務器從副本服務器的角度來看哪些數據是可以安全清理的。此信息顯著降低了元組被過早 VACUUM 的可能性,并允許pg_search確定何時可以安全刪除段。

要理解實際傳遞的信息hot_standby_feedback,我們必須首先了解 Postgres 中元組版本控制的工作原理。Postgres 中的每個元組都有兩個關鍵的元數據屬性: xmin 和 xmax。存儲創建 或 插入 該特定元組版本的xmin事務的事務 ID (XID) ,而 存儲更新 或 刪除該元組版本的事務的 XID ,從而有效地將其標記為已過時。當元組被刪除時,其 值將使用刪除事務的 XID 進行更新。由于 XID 是按順序分配的,因此后續事務的 XID 會被分配更大的編號,因此另一種思考方式是將其作為元組的“創建時間”和“上次更新或刪除時間”的代理。
在這里插入圖片描述
啟用后hot_standby_feedback,副本將定期傳達xmin其任何活動查詢當前固定的最小(最早的“創建時間”),這xmin標識了備用服務器上仍在使用的最舊元組。

有了這些信息,主服務器就可以更明智地決定何時允許執行清理操作(例如 VACUUM)。如果它發現備用查詢仍在對原本會被視為“死亡”的元組進行操作,則可以將清理操作推遲到該查詢完成。

最后的想法

即使借助hot_standby_feedback,備用服務器也基本上要依賴 WAL 來提供按接收順序和時間安全執行的指令。本地激勵與全局需求之間的矛盾,只是在分布式 Postgres 系統中實現完全復制安全性的挑戰性維度之一。

為了實現物理和邏輯一致性,pg_search我們實現了原子記錄的 LSM 樹,而為了實現邏輯一致性,我們依賴于hot_standby_feedback。

這項挑戰值得挑戰,因為它能夠在不犧牲一致性的情況下實現最快的搜索性能。要查看實際效果。

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

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

相關文章

架構如鐘擺:在變與不變之間優雅平衡

在當今數字轉型浪潮中,企業在“快速創新”與“長期穩定”之間反復拉扯。是否應該重建所有架構以適應AI?又是否該死守傳統系統確保安全與合規?在The Open Group阿姆斯特丹峰會上,凱捷全球 CTO Ron Tolido 借用了一個極具畫面感的比…

LLM中的位置嵌入矩陣(Position Embedding Matrix)是什么

LLM中的位置嵌入矩陣(Position Embedding Matrix)是什么 在大語言模型(LLM)中,位置嵌入矩陣(Position Embedding Matrix) 是用來表示輸入序列中每個詞的位置信息的矩陣。它的核心作用是:讓模型能夠區分“相同詞在不同位置的語義差異”(比如“貓喜歡魚”中的“貓”和“…

國產DevOps平臺Gitee:如何重塑中國企業研發效能新格局

國產DevOps平臺Gitee:如何重塑中國企業研發效能新格局 在全球數字化轉型浪潮中,軟件研發效率已成為企業競爭力的核心指標。作為中國最大的代碼托管平臺,Gitee正通過其全棧式DevOps解決方案,助力中國企業突破研發效能瓶頸&#xff…

告別混亂!【Java Web】項目分層架構全指南:核心三層 + 關鍵輔助包詳解

目錄 1.前言 2.正文 2.1為什么要分層 2.2核心三層詳解 2.2.1Controller層(表現層/API層) 2.2.2Service層(業務邏輯層) 2.2.3DAO層(持久層) 2.3. 核心關系與數據流轉:分層架構的交互邏輯…

解決Docker Compose報錯

解決Docker Compose報錯:exec ./entrypoint.sh: no such file or directory在使用Docker Compose部署應用時,你是否遇到過exec ./entrypoint.sh: no such file or directory這個令人頭疼的錯誤?本文將深入分析錯誤原因并提供多種解決方案&…

【element plus】el-select,allow-create不需要點回車鍵

<el-selectv-model"row.expertName"filterableremoteallow-createdefault-first-optionreserve-keywordplaceholder"請輸入姓名":remote-method"remoteMethod":loading"loadingName"change"(val) > handleNameChange(row, …

RK3588 HDMI-RX 驅動、RGA 加速與 OpenCV GStreamer 支持完整指南

一、環境檢測與前置依賴 確認內核與 HDMI-RX 節點&#xff1a; uname -a # 輸出&#xff1a;6.1.0-1025-rockchip ...dmesg | grep -i hdmirx # 應能看到 hdmirx-controller 節點&#xff1a; # fdee0000.hdmirx-controller driver probe ok!如果僅出現&#xff1a; rockchi…

AS32A601芯片QSPI 調試技術解析與與實戰經驗分享

一、概述&#xff08;一&#xff09;QSPI 簡介QSPI&#xff08;Quad Serial Peripheral Interface&#xff09;是一種高速串行通信接口&#xff0c;在標準 SPI&#xff08;Serial Peripheral Interface&#xff09;的基礎上擴展至 4 條數據線&#xff08;Quad Mode&#xff09;…

TDengine 轉化函數 TO_TIMESTAMP 用戶手冊

TDengine TO_TIMESTAMP 函數用戶使用手冊 函數概述 TO_TIMESTAMP 是 TDengine 中的標量函數&#xff0c;用于將字符串按照指定格式轉換為時間戳。該函數在數據導入、時間格式轉換、以及處理各種時間字符串格式時非常有用。 語法 TO_TIMESTAMP(ts_str_literal, format_str_liter…

關于我司即將對商業間諜行為進行法律訴訟的通知

最后警告我司所屬社交媒體中所有友商間諜&#xff1a;請于2025年7月26日上午十點前&#xff0c;自行刪除我方好友&#xff0c;并停止通過欺詐行為&#xff08;包括但不限于冒充客戶等&#xff09;盜取我司商業秘密的行為。十點后&#xff0c;我司將開始進行逐一排查&#xff0c…

【打怪升級 - 03】YOLO11/YOLO12/YOLOv10/YOLOv8 完全指南:從理論到代碼實戰,新手入門必看教程

引言&#xff1a;為什么選擇 YOLO&#xff1f; 在目標檢測領域&#xff0c;YOLO&#xff08;You Only Look Once&#xff09;系列模型一直以其高效性和準確性備受關注。作為新版本&#xff0c;YOLO系列的新版本總能在前輩的基礎上進行了多項改進&#xff0c;包括更高的檢測精度…

JMeter每次壓測前清除全部以確保異常率準確(以黑馬點評為例、詳細圖解)

目錄 一、前言 二、未清除全部會出現的情況(以樂觀鎖解決超賣問題為例) 三、清除全部就能得到準確的結果 一、前言 在學習黑馬點評之前我并沒有接觸過JMeter這個壓測軟件&#xff0c;然后在黑馬點評視頻中老師也是直接拿起JMeter就開始使用&#xff0c;所以我一直在不斷搜索…

關于新學C++編程Visual Studio 2022開始,使用Cmake工具構建Opencv和SDK在VS里編譯項目開發簡介筆記

1. C 項目build文件夾 2. VS解決方案管理器Solution——.sln文件 3. CMake 自動化構建工具 4. SDK軟件開發工具包作為初學者&#xff0c;從工程項目開始接觸完整一套流程工具和編譯&#xff0c;有助于快速上手。 一、C 項目build文件夾在 VS2022 中打開 C 項目后&#xff0c;在…

測試ppyoloe的小樣本few-shot能力,10張圖片精度達到69.8%

近期公司有個項目&#xff0c;需要解決長尾樣本的問題&#xff0c;所以測試了一下paddlepaddle小樣本的能力。 環境&#xff1a;&#xff1a;T4 、ubuntu 、cuda-11.6 、py3.9、 paddlepaddle-gpu2.6.0、pip install opencv-python4.5.5.64 -i https://pypi.tuna.tsinghua.…

結構化布線系統詳解

1. 結構化布線系統概述 結構化布線系統(Structured Cabling System, SCS)是一種標準化、模塊化的建筑物或建筑群內信息傳輸基礎設施&#xff0c;它為語音、數據、圖像等多媒體業務提供了統一的物理傳輸介質。與傳統的點對點布線方式不同&#xff0c;結構化布線采用層次化、標準…

【Java學習】匿名內部類的向外訪問機制

目錄 一、方法局部變量的訪問 1.生命周期 1.1方法生命周期 1.2匿名實例生命周期 1.3生命超時性 2.變量捕獲 2.1按值捕獲 2.1.1值捕獲優勢 2.1.1.1生命及時訪問 2.1.1.2線程安全 2.1.2常量值捕獲優勢 2.2按引用捕獲 引用捕獲風險 (1)生命超時訪問 (2)線程不安全 …

LinkedList的模擬實現+LinkedList和ArrayList的區別

目錄 LinkedList的模擬實現 什么是雙向鏈表 增加數據 頭插法&#xff1a; 尾插法&#xff1a; 指定的下標插入&#xff1a; 刪除數據 刪除雙向鏈表中出現的第一個key 置空所有數據 LinkedList和ArrayList的區別 順序表對應的集合類是ArrayList&#xff1b;鏈表對應的集…

Vue + WebSocket 實時數據可視化實戰:多源融合與模擬數據雙模式設計

在現代交通大屏項目中&#xff0c;實時數據的采集和可視化尤為重要。本文結合 Vue3 和 ECharts&#xff0c;分享一個支持多 WebSocket 數據源實時合并、模擬數據調試、自動重連的完整設計方案&#xff0c;幫助你快速搭建健壯的數據可視化組件。一、項目背景與核心需求實時接收多…

C#索引器、接口、泛型

以下是對提供的 C# 代碼中涉及的核心知識點的梳理和總結&#xff0c;涵蓋索引器、接口、泛型三大核心內容&#xff0c;以及相關實踐要點&#xff1a;一、索引器&#xff08;Indexer&#xff09;索引器是一種允許類或結構體像數組一樣通過[]語法訪問成員的特殊成員&#xff0c;本…

界面組件DevExpress WPF中文教程:Grid - 如何過濾節點?

DevExpress WPF擁有120個控件和庫&#xff0c;將幫助您交付滿足甚至超出企業需求的高性能業務應用程序。通過DevExpress WPF能創建有著強大互動功能的XAML基礎應用程序&#xff0c;這些應用程序專注于當代客戶的需求和構建未來新一代支持觸摸的解決方案。 無論是Office辦公軟件…