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のロックを、ANALYSESHARE 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 秒をはるかに下回っています。ロックは問題になる前にタイムアウトします。

ライターセッション リーダーセッション
export WRITER=aurorapg1.12345678910.us-west-1.rds.amazonaws.com psql -h $WRITER psql (15devel, server 10.14) Type "help" for help.
export READER=aurorapg2.12345678910.us-west-1.rds.amazonaws.com psql -h $READER psql (15devel, server 10.14) Type "help" for help.
ライターセッションはt1ライターインスタンスにテーブルを作成します。ACCESS EXCLUSIVE ロックは、ライターで競合するクエリがないことを前提に、ライターで即座に取得されます。
postgres=> CREATE TABLE t1(b integer); CREATE TABLE
リーダーセッションは 100 ミリ秒のロックタイムアウトインターバルを設定します。
postgres=> SET lock_timeout=100; SET
リーダーセッションはt1リーダーインスタンスでテーブルからデータを読み込もうとします。
postgres=> SELECT * FROM t1; b --- (0 rows)
ライターセッションがt1をドロップします。
postgres=> BEGIN; BEGIN postgres=> DROP TABLE t1; DROP TABLE postgres=>
クエリがタイムアウトし、リーダーでキャンセルされます。
postgres=> SELECT * FROM t1; ERROR: canceling statement due to lock timeout LINE 1: SELECT * FROM t1; ^
リーダーセッションがpg_locksおよびpg_stat_activityへのクエリを実行し、エラーの原因を特定します。その結果、aurora wal replayプロセスがテーブルt1ACCESS EXCLUSIVEをホールドしていることを示します。
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; locktype | relation | mode | backend_type ----------+----------+---------------------+------------------- relation | 68628525 | AccessExclusiveLock | aurora wal replay (1 row)