Lwlock:SubtransSLRU - Amazon Aurora

Lwlock:SubtransSLRU

LWLock:SubtransSLRU および LWLock:SubtransBuffer 待機イベントは、セッションがサブトランザクション情報の単純最小使用時間 (SLRU) キャッシュへのアクセスを待っていることを示します。これは、トランザクションの可視性と親子関係を決定するときに発生します。

  • LWLock:SubtransSLRU: プロセスは、サブトランザクションのシンプルな最も長い時間使われていない (SLRU) キャッシュへのアクセスを待っています。Aurora PostgreSQL 12.22 以前では、この待機イベントは SubtransControlLock と呼ばれます。

  • LWLock:SubtransBuffer: プロセスは、サブトランザクションのシンプルな最も長い時間使われていない (SLRU) バッファの I/O を待っています。Aurora PostgreSQL 12.22 以前では、この待機イベントは subtrans と呼ばれます。

サポート対象エンジンバージョン

この待機イベント情報は、Aurora PostgreSQL のすべてのバージョンでサポートされています。

Context

サブトランザクションを理解する – サブトランザクションは、PostgreSQL のトランザクション内のトランザクションです。ネストされたトランザクションとも呼ばれます。

サブトランザクションは通常、次の場合に作成されます。

  • SAVEPOINT コマンド

  • 例外ブロック (BEGIN/EXCEPTION/END)

サブトランザクションを使用すると、トランザクション全体に影響を与えることなく、トランザクションの一部をロールバックできます。これにより、トランザクション管理をきめ細かく制御できます。

実装の詳細 – PostgreSQL は、メイントランザクション内のネストされた構造としてサブトランザクションを実装します。各サブトランザクションは独自のトランザクション ID を取得します。

実装の主な側面。

  • トランザクション ID は pg_xact で追跡されます。

  • 親子関係は PGDATApg_subtrans サブディレクトリに保存されます。

  • 各データベースセッションは、最大 64 のアクティブなサブトランザクションを維持できます

  • この制限を超えると、サブトランザクションオーバーフローが発生します。サブトランザクション情報を取得するために、最も長い時間使われていない (SLRU) キャッシュにアクセスする必要があります

待機時間が増加する原因の可能性

サブトランザクション SLRU 競合の一般的な原因は次のとおりです。

  • SAVEPOINT および EXCEPTION 処理の過剰な使用EXCEPTION ハンドラーを使用した PL/pgSQL プロシージャは、例外が発生するかどうかにかかわらず、暗黙的なセーブポイントを自動的に作成します。各 SAVEPOINT は新しいサブトランザクションを開始します。1 つのトランザクションが 64 を超えるサブトランザクションを蓄積すると、サブトランザクション SLRU オーバーフローがトリガーされます。

  • ドライバーと ORM の設定SAVEPOINT の使用は、アプリケーションコードで明示的で行うことも、ドライバー設定を通じて暗黙的に行うこともできます。一般的に使用される ORM ツールやアプリケーションフレームワークの多くは、ネストされたトランザクションをネイティブにサポートしています。以下は一般的な例です。

    • JDBC ドライバーパラメータ autosavealways または conservative に設定すると、各クエリの前にセーブポイントが生成されます。

    • Spring Framework トランザクション定義を propagation_nested に設定した場合。

    • requires_new: true が設定されている場合の Rails。

    • session.begin_nested を使用する場合の SQLAlchemy。

    • ネストされた atomic() ブロックを使用する場合の Django。

    • Savepoint を使用する場合の GORM。

    • ロールバックレベル設定がステートメントレベルのロールバックに設定されている場合の psqlODBC (例: PROTOCOL=7.4-2)。

  • 長時間実行されるトランザクションとサブトランザクションを伴う高同時ワークロード – 同時ワークロードが高く、長時間実行されるトランザクションとサブトランザクション中にサブトランザクション SLRU オーバーフローが発生すると、PostgreSQL の競合が増加します。これは、LWLock:SubtransBuffer および LWLock: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 を使用した EXCEPTION 処理の問題を示しています。

      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 パラメータを always または conservative に設定すると、各クエリの前にセーブポイントが生成されます。never 設定がアプリケーションに受け入れられるかどうかを評価します。

    • PostgreSQL ODBC ドライバー (psqlODBC) — ロールバックレベル設定 (ステートメントレベルのロールバック用) は、ステートメントのロールバック機能を有効にするための暗黙的なセーブポイントを作成します。トランザクションレベルのロールバックがアプリケーションで許容されるかどうかを評価します。

    • ORM トランザクション設定を確認する

    • セーブポイントを必要としない代替エラー処理戦略を検討する

  • トランザクション設計の最適化 – 過剰なネストを回避し、サブトランザクションオーバーフロー条件の可能性を減らすために、トランザクションを再構築します。

  • 長時間実行されるトランザクションの削減 – 長時間実行されるトランザクションでは、サブトランザクション情報を長く保持することで、サブトランザクションの問題が悪化する可能性があります。Performance Insights メトリクスをモニタリングし、アイドル状態のトランザクションを自動的に終了するように idle_in_transaction_session_timeout パラメータを設定します。

  • Performance Insights メトリクスのモニタリング – idle_in_transaction_count (トランザクション状態でアイドル状態のセッション数) や idle_in_transaction_max_time (アイドル状態にある最長時間のトランザクションの継続時間) などのメトリクスを追跡して、長時間実行されるトランザクションを検出します。

  • idle_in_transaction_session_timeout の設定 – 指定した期間後にアイドル状態のトランザクションを自動的に終了するように、パラメータグループにこのパラメータを設定します。

  • プロアクティブモニタリング – LWLock:SubtransBuffer および LWLock:SubtransSLRU 待機イベントの発生頻度をモニタリングし、サブトランザクション関連の競合が重大になる前に検出します。