LWLock:SubtransSLRU - Amazon Relational Database Service

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

LWLock:SubtransSLRU

LWLock:SubtransSLRULWLock:SubtransBuffer等待事件表示工作階段正在等待存取簡單的最近最少使用 (SLRU) 快取以取得子交易資訊。這會在判斷交易可見性和父子關係時發生。

  • LWLock:SubtransSLRU:程序正在等待為子交易存取簡單的最近最少使用 (SLRU) 快取。在 RDS for PostgreSQL 12.22 及更早版本中,此等待事件稱為 。 SubtransControlLock

  • LWLock:SubtransBuffer:程序正在等待簡單最近最少使用 (SLRU) 緩衝區上的輸入/輸出進行子交易。在 RDS for PostgreSQL 12.22 及更早版本中,此等待事件稱為 。 subtrans

支援的引擎版本

所有版本的 RDS for PostgreSQL 都支援此等待事件資訊。

Context

了解子交易 – 子交易是 PostgreSQL 中交易內的交易。它也稱為巢狀交易。

子交易通常會在您使用 時建立:

  • SAVEPOINT 命令

  • 例外狀況區塊 (BEGIN/EXCEPTION/END)

子交易可讓您復原部分交易,而不會影響整個交易。這可讓您精細控制交易管理。

實作詳細資訊 – PostgreSQL 在主要交易中實作子交易做為巢狀結構。每個子交易都會取得自己的交易 ID。

關鍵實作層面:

  • 交易 IDs會在 中追蹤 pg_xact

  • 父子關係存放在 下的pg_subtrans子目錄中 PGDATA

  • 每個資料庫工作階段最多可以維持 個64作用中的子交易

  • 超過此限制會導致子交易溢位,這需要存取簡單的最近最少使用 (SLRU) 快取以取得子交易資訊

等待時間增加的可能原因

子交易 SLRU 爭用的常見原因包括:

  • 過度使用 SAVEPOINT 和 EXCEPTION 處理 – PL/pgSQL 程序搭配EXCEPTION處理常式會自動建立隱含儲存點,無論是否發生例外狀況。每個 都會SAVEPOINT啟動新的子交易。當單一交易累積超過 64 個子交易時,會觸發子交易 SLRU 溢位。

  • 驅動程式和 ORM 組態SAVEPOINT 用量可以在應用程式程式碼中明確,或透過驅動程式組態隱含。許多常用的 ORM 工具和應用程式架構原生支援巢狀交易。以下是一些常見的範例:

    • 如果 JDBC 驅動程式參數 autosave設定為 alwaysconservative,則 會在每次查詢之前產生儲存點。

    • 設定為 時的 Spring Framework 交易定義propagation_nested

    • requires_new: true 已設定 時的 Rails。

    • 使用 session.begin_nested 時的 SQLAlchemy。

    • 使用巢狀atomic()區塊時的 Django。

    • 使用 Savepoint 時的 GORM。

    • psqlODBC 將回復層級設定設為陳述式層級回復時 (例如,PROTOCOL=7.4-2)。

  • 具有長時間執行交易和子交易的高並行工作負載 – 當子交易 SLRU 溢位發生在高並行工作負載和長時間執行的交易和子交易期間時,PostgreSQL 的爭用性會增加。這會顯示為 LWLock:SubtransBufferLWLock:SubtransSLRU鎖定的較高等待事件。

動作

根據等待事件的原因,我們會建議不同的動作。有些動作提供立即的緩解,有些則需要調查和長期更正。

監控子交易用量

對於 PostgreSQL 16.1 版和更新版本,請使用下列查詢來監控每個後端的子交易計數和溢位狀態。此查詢將後端統計資料與活動資訊聯結,以顯示哪些程序正在使用子交易:

SELECT a.pid, usename, query, state, wait_event_type, wait_event, subxact_count, subxact_overflowed FROM (SELECT id, pg_stat_get_backend_pid(id) pid, subxact_count, subxact_overflowed FROM pg_stat_get_backend_idset() id JOIN LATERAL pg_stat_get_backend_subxact(id) AS s ON true ) a JOIN pg_stat_activity b ON a.pid = b.pid;

對於 PostgreSQL 13.3 版和更新版本,請監控pg_stat_slru檢視是否有子交易快取壓力。下列 SQL 查詢會擷取 Subtrans 元件的 SLRU 快取統計資料:

SELECT * FROM pg_stat_slru WHERE name = 'Subtrans';

持續增加blks_read的值表示未快取子交易經常存取磁碟,發出潛在的 SLRU 快取壓力訊號。

設定記憶體參數

對於 PostgreSQL 17.1 和更新版本,您可以使用 subtransaction_buffers 參數設定子交易 SLRU 快取大小。下列組態範例示範如何設定子交易緩衝區參數:

subtransaction_buffers = 128

此參數指定用來快取子交易內容的共用記憶體數量 (pg_subtrans)。在沒有單位的情況下指定時,值代表BLCKSZ位元組區塊,通常每個區塊為 8KB。例如,將值設定為 128 會為子交易快取配置 1MB (128 * 8kB) 的記憶體。

注意

您可以在叢集層級設定此參數,讓所有執行個體保持一致。測試並調整 值,以符合您的特定工作負載需求和執行個體類別。您必須重新啟動寫入器執行個體,參數變更才會生效。

長期動作

  • 檢查應用程式碼和組態 – 檢閱應用程式碼和資料庫驅動程式組態,了解一般的明確和隱含SAVEPOINT用量和子交易用量。識別可能產生超過 64 個子交易的交易。

  • 減少儲存點用量 – 將交易中的儲存點用量降至最低:

    • 使用 EXCEPTION 區塊檢閱 PL/pgSQL 程序與函數。EXCEPTION 區塊會自動建立隱含儲存點,這可能會導致子交易溢位。無論執行期間是否實際發生例外狀況,每個 EXCEPTION 子句都會建立子交易。

      範例 1:有問題的 EXCEPTION 區塊用量

      下列程式碼範例顯示建立多個子交易的有問題的 EXCEPTION 區塊用量:

      CREATE OR REPLACE FUNCTION process_user_data() RETURNS void AS $$ DECLARE user_record RECORD; BEGIN FOR user_record IN SELECT * FROM users LOOP BEGIN -- This creates a subtransaction for each iteration INSERT INTO user_audit (user_id, action, timestamp) VALUES (user_record.id, 'processed', NOW()); UPDATE users SET last_processed = NOW() WHERE id = user_record.id; EXCEPTION WHEN unique_violation THEN -- Handle duplicate audit entries UPDATE user_audit SET timestamp = NOW() WHERE user_id = user_record.id AND action = 'processed'; END; END LOOP; END; $$ LANGUAGE plpgsql;

      下列改進的程式碼範例使用 UPSERT 而非例外狀況處理來減少子交易用量:

      CREATE OR REPLACE FUNCTION process_user_data() RETURNS void AS $$ DECLARE user_record RECORD; BEGIN FOR user_record IN SELECT * FROM users LOOP -- Use UPSERT to avoid exception handling INSERT INTO user_audit (user_id, action, timestamp) VALUES (user_record.id, 'processed', NOW()) ON CONFLICT (user_id, action) DO UPDATE SET timestamp = NOW(); UPDATE users SET last_processed = NOW() WHERE id = user_record.id; END LOOP; END; $$ LANGUAGE plpgsql;

      範例 2:STRICT 例外狀況處理常式

      下列程式碼範例顯示使用 NO_DATA_FOUND 處理的問題:

      CREATE OR REPLACE FUNCTION get_user_email(p_user_id INTEGER) RETURNS TEXT AS $$ DECLARE user_email TEXT; BEGIN BEGIN -- STRICT causes an exception if no rows or multiple rows found SELECT email INTO STRICT user_email FROM users WHERE id = p_user_id; RETURN user_email; EXCEPTION WHEN NO_DATA_FOUND THEN RETURN 'Email not found'; END; END; $$ LANGUAGE plpgsql;

      下列改進的程式碼範例使用 IF NOT FOUND 而非例外狀況處理來避免子交易:

      CREATE OR REPLACE FUNCTION get_user_email(p_user_id INTEGER) RETURNS TEXT AS $$ DECLARE user_email TEXT; BEGIN SELECT email INTO user_email FROM users WHERE id = p_user_id; IF NOT FOUND THEN RETURN 'Email not found'; ELSE RETURN user_email; END IF; END; $$ LANGUAGE plpgsql;
    • JDBC 驅動程式 – autosave 如果 參數設定為 alwaysconservative,則 會在每次查詢之前產生儲存點。評估您的應用程式是否可以接受never設定。

    • PostgreSQL ODBC 驅動程式 (psqlODBC) — 回復層級設定 (用於陳述式層級回復) 會建立隱含儲存點,以啟用陳述式回復功能。評估您的應用程式是否可以接受交易層級或無轉返。

    • 檢查 ORM 交易組態

    • 考慮不需要儲存點的替代錯誤處理策略

  • 最佳化交易設計 – 重組交易,以避免過度巢狀化,並減少子交易溢位情況的可能性。

  • 減少長時間執行的交易 – 長時間執行的交易可以透過保留更長的子交易資訊來加劇子交易問題。監控績效詳情指標並設定 idle_in_transaction_session_timeout 參數以自動終止閒置交易。

  • 監控績效詳情指標 – 追蹤指標,包括 idle_in_transaction_count(處於交易狀態的閒置工作階段數) 和 idle_in_transaction_max_time(最長執行閒置交易的持續時間),以偵測長時間執行的交易。

  • 設定 idle_in_transaction_session_timeout – 在參數群組中設定此參數,以在指定的持續時間後自動終止閒置交易。

  • 主動監控 - 監控 的頻繁出現,LWLock:SubtransBufferLWLock:SubtransSLRU等待事件以偵測與交易相關的爭用,然後再變得至關重要。