Lock:Relation - Amazon Aurora

Lock:Relation

Lock:Relationイベントは、別のトランザクションによって現在ロックされているテーブルまたはビュー (リレーション) のロックを取得するためにクエリが待っているときに発生します。

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

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

Context

ほとんどの PostgreSQL コマンドは、テーブル内のデータへの同時アクセスを制御するために、暗黙のうちにロックを使用します。また、これらのロックは、アプリケーションコード内でLOCKコマンドによって明示的に使用することもできます。多くのロックモードは互いに互換性がないため、同じオブジェクトにアクセスしようとしているときにトランザクションをブロックすることがあります。これが起こると、Aurora PostgreSQL はLock:Relationイベントを生成します。一般的な例をいくつか以下に示します。

  • ACCESS EXCLUSIVEのような排他的なロックは、すべての同時アクセスをブロックできます。DROP TABLETRUNCATEVACUUM FULLCLUSTERなどのデータ定義言語 (DDL) オペレーションは、暗黙のうちにACCESS EXCLUSIVEロックを取得します。ACCESS EXCLUSIVE は、明示的にモードを指定しない LOCK TABLE ステートメントのデフォルトのロックモードでもあります。

  • テーブル上でCREATE INDEX (without CONCURRENT)を使用すると、ROW EXCLUSIVEロックを取得するデータ操作言語 (DML) ステートメントUPDATEDELETEINSERTと競合します。

テーブルレベルのロックと競合するロックモードの詳細については、PostgreSQL ドキュメントの「明示的なロック」を参照してください。

ブロックされたクエリとトランザクションは、通常、次のいずれかの方法でブロックを解除します。

  • クエリのブロック: アプリケーションがクエリをキャンセルするか、ユーザーがプロセスを終了できます。また、セッションのステートメントタイムアウトやデッドロック検出メカニズムによって、エンジンがクエリを強制終了させることもできます。

  • トランザクションのブロック: トランザクションが ROLLBACK または COMMIT を実行すると、トランザクションはブロックを停止します。ロールバックは、クライアントまたはネットワークの問題によってセッションが切断されたり、終了したときにも自動的に行われます。セッションは、データベースエンジンがシャットダウンされたり、システムがメモリ不足になったりしたときに終了できます。

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

Lock:Relation イベントが通常よりも頻繁に発生する場合、パフォーマンスの問題を示している可能性があります。代表的な原因としては、以下が挙げられます。

テーブルロックの競合による同時セッションの増加

競合するロックモードで同じテーブルをロックするクエリによる同時セッションの数が増加する可能性があります。

メンテナンスオペレーション

VACUUMANALYZEのようなヘルスメンテナンスオペレーションは、競合するロックの数を大幅に増加させる可能性があります。VACUUM FULLACCESS EXCLUSIVEのロックを、ANALYZESHARE UPDATE EXCLUSIVEのロックを取得します。どちらのタイプのロックも、Lock:Relation待機イベントを引き起こすことがあります。また、マテリアライズドビューのリフレッシュなどのアプリケーションデータのメンテナンスオペレーションも、ブロックされたクエリとトランザクションを増加することもあります。

リーダーインスタンスをロックする

ライターとリーダーが保持しているリレーションロックの間に矛盾がある可能性があります。現在は、ACCESS EXCLUSIVE リレーションロックのみが、リーダーインスタンスにレプリケートされます。ただし、ACCESS EXCLUSIVE リレーションロックは、リーダーが保持する ACCESS SHARE リレーションロックと競合します。これにより、リーダーのロックリレーション待機イベントが増加する可能性があります。

アクション

待機イベントの原因に応じたさまざまなアクションをお勧めします。

SQL ステートメントのブロックによる影響を軽減

SQL ステートメントのブロックによる影響を軽減するには、可能なところではアプリケーションコードを修正します。ブロックを減らすための 2 つの一般的な方法は以下のとおりです。

  • NOWAIT オプションを使用する: SELECTLOCK ステートメントなど、一部の SQL コマンドはこのオプションをサポートしています。NOWAIT指示文は、ロックをすぐに取得できない場合、ロックへのクエリをキャンセルします。この方法は、ブロックされたセッションが、その後ろにあるブロックされたセッションが積み重なるのを防ぐのに役立ちます。

    例えば、トランザクション A がトランザクション B に保持されているロックを待っているとします。ここで、B がトランザクション C によってロックされているテーブルのロックをリクエストすると、トランザクション C が完了するまでトランザクション A がブロックされる可能性があります。ただし、トランザクション B が C のロックを要求するときにNOWAITを使用する場合、トランザクションBは迅速に失敗し、トランザクション A が無期限に待機する必要がないことを保証できます。

  • SET lock_timeout を使用する: lock_timeout 値を設定して、SQL ステートメントがリレーションでロックを取得するのを待機する時間を制限します。指定したタイムアウト時間内にロックが取得されなかった場合、ロックを要求したトランザクションはキャンセルされます。この値はセッションレベルで設定します。

メンテナンスオペレーションの影響を最小限に抑える

VACUUMANALYZEのようなメンテナンスオペレーションは重要です。これらのメンテナンス作業に関連するLock:Relation待機イベントを見つけても、それらをオフにしないことをお勧めします。次のようなアプローチにより、これらの操作の影響を最小限に抑えることができます。

  • オフピーク時にメンテナンス操作をマニュアルで実行します。

  • オートバキュームタスクによるLock:Relation待機をへらすには、必要なオートバキュームチューニングを実行します。オートバキュームのチューニングについては、Amazon RDS ユーザーガイドの「Amazon RDS での PostgreSQL オートバキュームの使用」を参照してください。

リーダーロックをチェックする

ライターとリーダーの同時セッションが、お互いをブロックするロックを保持しているかどうかを確認できます。これを行う 1 つの方法は、ロックのタイプとリレーションを返すクエリを実行することです。この表では、ライターセッションとリーダーセッションという 2 つの同時セッションに対する一連のクエリを見つけることができます。

再生プロセスは、リーダークエリをキャンセルする前に max_standby_streaming_delay の期間待機します。例に示すように、100 ms のロックタイムアウトは、デフォルトの max_standby_streaming_delay である30 秒をはるかに下回っています。ロックは問題になる前にタイムアウトします。

一連のイベント セッション コマンドまたは出力

指定された値で READER という環境変数を設定し、このエンドポイントで DB インスタンスに接続しようとします。

リーダーセッション

CLI コマンド:

export READER=aurorapg2.12345678910.us-west-1.rds.amazonaws.com psql -h $READER

出力:

psql (15devel, server 10.14)
Type "help" for help.

WRITER という環境変数を設定し、このエンドポイントを使用して DB インスタンスに接続しようとします。

ライターセッション

CLI コマンド:

export WRITER=aurorapg1.12345678910.us-west-1.rds.amazonaws.com psql -h $WRITER

出力:

psql (15devel, server 10.14) 
Type "help" for help. 

ライターセッションはライターインスタンスにテーブル t1 を作成します。

ライターセッション

PostgreSQL クエリ:

postgres=> CREATE TABLE t1(b integer); CREATE TABLE

ライターに競合するクエリがない場合、ACCESS EXCLUSIVE ロックはライターですぐに取得されます。

ライターセッション

ACCESS EXCLUSIVE ロックの有効化

リーダーセッションは 100 ミリ秒のロックタイムアウトインターバルを設定します。

リーダーセッション

PostgreSQL クエリ:

postgres=> SET lock_timeout=100; SET

リーダーセッションはリーダーインスタンスでテーブル t1 からデータを読み込もうとします。

リーダーセッション

PostgreSQL クエリ:

postgres=> SELECT * FROM t1;

サンプル出力:

b
---
(0 rows)

ライターセッションが t1 をドロップします。

ライターセッション

PostgreSQL クエリ:

postgres=> BEGIN; BEGIN postgres=> DROP TABLE t1; DROP TABLE postgres=>

クエリがタイムアウトし、リーダーでキャンセルされます。

リーダーセッション

PostgreSQL クエリ:

postgres=> SELECT * FROM t1;

サンプル出力:

ERROR:  canceling statement due to lock timeout
LINE 1: SELECT * FROM t1;
                      ^

リーダーセッションが pg_locks および pg_stat_activity へのクエリを実行し、エラーの原因を特定します。

リーダーセッション

PostgreSQL クエリ:

postgres=> SELECT locktype, relation, mode, backend_type postgres=> FROM pg_locks l, pg_stat_activity t1 postgres=> WHERE l.pid=t1.pid AND relation = 't1'::regclass::oid;

結果は、aurora wal replay プロセスがテーブル t1 で ACCESS EXCLUSIVE ロックをホールドしていることを示します。

リーダーセッション

クエリ結果:

locktype | relation | mode | backend_type ----------+----------+---------------------+------------------- relation | 68628525 | AccessExclusiveLock | aurora wal replay (1 row)