

# LWLock:lock\_manager (LWLock:lockmanager)
<a name="wait-event.lw-lock-manager"></a>

このイベントは、RDS for PostgreSQL エンジンが、高速パスロックが不可能な場合に共有ロックのメモリ領域を維持し、ロックの割り当て、チェック、および解放を行うときに発生します。

**Topics**
+ [サポート対象エンジンバージョン](#wait-event.lw-lock-manager.context.supported)
+ [Context](#wait-event.lw-lock-manager.context)
+ [待機時間が増加する原因の可能性](#wait-event.lw-lock-manager.causes)
+ [アクション](#wait-event.lw-lock-manager.actions)

## サポート対象エンジンバージョン
<a name="wait-event.lw-lock-manager.context.supported"></a>

この待機イベント情報は、RDS for PostgreSQL バージョン 9.6 以降に関連します。RDS for PostgreSQL のバージョン 13 より前のリリースでは、この待機イベントの名前は `LWLock:lock_manager` になります。RDS for PostgreSQL のバージョン 13 以降のリリースでは、この待機イベントの名前は `LWLock:lockmanager` になります。

## Context
<a name="wait-event.lw-lock-manager.context"></a>

SQL ステートメントを発行すると、RDS for PostgreSQL は同時オペレーション中にデータベースの構造、データ、および整合性を保護するためにロックを記録します。エンジンは、高速パスロックまたは高速ではないパスロックを使用して、この目標を達成できます。高速ではないパスロックは、高速パスロックよりも高価で、オーバーヘッドも多く発生します。

### 高速パスロック
<a name="wait-event.lw-lock-manager.context.fast-path"></a>

バックエンドプロセスでは、頻繁にロックされロック解除されるがめったに競合しないロックのオーバーヘッドを減らすために、高速パスロックを使用できます。データベースでは、以下の基準を満たすロックにこのメカニズムを使用します。
+ DEFAULT ロック方式を使用します。
+ これらは、共有関係ではなく、データベースリレーションに対するロックを表します。
+ これらは競合する可能性が低い弱いロックです。
+ エンジンは、競合するロックが存在する可能性がないことをすばやく確認できます。

エンジンは、以下のいずれかの条件が true の場合、高速パスロックを使用できません。
+ ロックが上記の条件を満たしていません。
+ バックエンドプロセスに使用できるスロットはこれ以上ありません。

高速パスロック用にクエリを調整するには、次のクエリを使用できます。

```
SELECT count(*), pid, mode, fastpath
  FROM pg_locks
 WHERE fastpath IS NOT NULL
 GROUP BY 4,3,2
 ORDER BY pid, mode;
 count | pid  |      mode       | fastpath
-------+------+-----------------+----------
16 | 9185 | AccessShareLock | t
336 | 9185 | AccessShareLock | f
1 | 9185 | ExclusiveLock   | t
```

次のクエリでは、データベース全体の合計のみを表示します。

```
SELECT count(*), mode, fastpath
  FROM pg_locks
 WHERE fastpath IS NOT NULL
 GROUP BY 3,2
 ORDER BY mode,1;
count |      mode       | fastpath
-------+-----------------+----------
16 | AccessShareLock | t
337 | AccessShareLock | f
1 | ExclusiveLock   | t
(3 rows)
```

高速パスロックの詳細については、「PostgreSQL ロックマネージャ README」 の[fast path](https://github.com/postgres/postgres/blob/master/src/backend/storage/lmgr/README#L70-L76)および「PostgreSQL ドキュメント」の[pg-locks](https://www.postgresql.org/docs/9.3/view-pg-locks.html#AEN98195)を参照してください。

### ロックマネージャのスケーリング問題の例
<a name="wait-event.lw-lock-manager.context.lock-manager"></a>

この例では、`purchases`という名前のテーブルが 5 年分のデータを日ごとにパーティション化して保存しています。各パーティションには 2 つのインデックスがあります。次の一連のイベントが発生します。

1. 何日分ものデータをクエリすると、データベースは多くのパーティションを読み取る必要があります。

1. データベースは、各パーティションに対してロックエントリを作成します。パーティションインデックスがオプティマイザアクセスパスの一部である場合、データベースはそれらのロックエントリも作成します。

1. 同じバックエンドプロセスでリクエストされたロックエントリの数が`FP_LOCK_SLOTS_PER_BACKEND`の値である16より大きい場合、ロックマネージャは非高速パスロック方式を使用します。

最新のアプリケーションには何百ものセッションがあることがあります。同時セッションが適切なパーティションプルーニングを行わずに親を照会している場合、データベースは数百または数千の非高速パスロックを作成することがあります。通常、この同時実行が vCPUs の数よりも多いと、`LWLock:lock_manager`待機イベントが表示されます。

**注記**  
`LWLock:lock_manager`待機イベントは、データベーススキーマのパーティションまたはインデックスの数とは関係ありません。代わりに、データベースが制御する必要がある非高速パスロックの数と関係しています。

## 待機時間が増加する原因の可能性
<a name="wait-event.lw-lock-manager.causes"></a>

`LWLock:lock_manager`待機イベントが通常より頻繁に発生する場合は、おそらくパフォーマンスの問題を示しており、突然のスパイクが発生する原因として最も可能性が高いものは次のとおりです。
+ 同時アクティブセッションは、高速パスロックを使用しないクエリを実行しています。また、これらのセッション数が最大 vCPU を超えています。
+ 多数の同時アクティブセッションが、大きくパーティション化されたテーブルにアクセスしています。各パーティションには複数のインデックスがあります。
+ データベースで接続ストームが発生しています。デフォルトでは、一部のアプリケーションと接続プールソフトウェアは、データベースが遅い場合により多くの接続を作成します。これは問題を悪化させます。接続ストームが発生しないように接続プールソフトウェアをチューニングします。
+ 多数のセッションが、パーティションをプルーニングせずに親テーブルをクエリします。
+ データ定義言語 (DDL)、データ操作言語 (DML)、またはメンテナンスコマンドは、頻繁にアクセスまたは変更されるビジーリレーションあるいはタプルのいずれかを排他的にロックします。

## アクション
<a name="wait-event.lw-lock-manager.actions"></a>

`CPU`待機イベントが発生する場合、必ずしもパフォーマンスの問題を示しているとは限りません。パフォーマンスが低下し、この待機イベントが DB ロードを支配している場合にのみ、このイベントに応答します。

**Topics**
+ [パーティションプルーニングを使用する](#wait-event.lw-lock-manager.actions.pruning)
+ [不要なインデックスを削除する](#wait-event.lw-lock-manager.actions.indexes)
+ [高速パスロック用にクエリをチューニングする](#wait-event.lw-lock-manager.actions.tuning)
+ [他の待機イベントに合わせてチューニングする](#wait-event.lw-lock-manager.actions.other-waits)
+ [ハードウェアのボトルネックを減らす](#wait-event.lw-lock-manager.actions.hw-bottlenecks)
+ [接続プーラーを使用する](#wait-event.lw-lock-manager.actions.pooler)
+ [RDS for PostgreSQL バージョンのアップグレード](#wait-event.lw-lock-manager.actions.pg-version)

### パーティションプルーニングを使用する
<a name="wait-event.lw-lock-manager.actions.pruning"></a>

*パーティションプルーニング*とは、宣言によってパーティション分割されたテーブルに対するクエリ最適化戦略のことで、不要なパーティションをテーブルスキャンから除外し、パフォーマンスを向上させます。パーティションプルーニングは、デフォルトで有効になっています。オフになっている場合は、次のようにオンにします。

```
SET enable_partition_pruning = on;
```

クエリの`WHERE`節にパーティショニングに使用される列が含まれる場合は、パーティションのプルーニングを利用できます。詳細については、PostgreSQL のドキュメントの「[パーティションプルーニング](https://www.postgresql.org/docs/current/ddl-partitioning.html#DDL-PARTITION-PRUNING)」を参照してください。を参照してください。

### 不要なインデックスを削除する
<a name="wait-event.lw-lock-manager.actions.indexes"></a>

データベースには、未使用またはほとんど使用されないインデックスが含まれている可能性があります。その場合は、それらの削除を検討します。次のいずれかを実行します。
+ 不要なインデックスを見つける方法については、PostgreSQL wikiの「[未使用のインデックス](https://wiki.postgresql.org/wiki/Index_Maintenance#Unused_Indexes)」を参照してください。
+ PG コレクタを実行します。この SQL スクリプトは、データベース情報を収集し、統合 HTML レポートに表示します。「未使用のインデックス」セクションをチェックします。詳細については、AWSLabs GitHub リポジトリの「[PG コレクター](https://github.com/awslabs/pg-collector)」を参照してください。

### 高速パスロック用にクエリをチューニングする
<a name="wait-event.lw-lock-manager.actions.tuning"></a>

クエリで高速パスロックが使用されているかどうかを調べるには、`pg_locks`テーブルの`fastpath`列にクエリを実行します。クエリで高速パスロックを使用していない場合は、クエリあたりのリレーション数を 16 未満に減らしてください。

### 他の待機イベントに合わせてチューニングする
<a name="wait-event.lw-lock-manager.actions.other-waits"></a>

`LWLock:lock_manager`が上位待機のリストの第1位または 2 番目である場合、次の待機イベントもリストに表示されるかどうかを確認します。
+ `Lock:Relation`
+ `Lock:transactionid`
+ `Lock:tuple`

上記のイベントがリスト内で上位に表示される場合は、まずこれらの待機イベントのチューニングを検討してください。これらのイベントは、`LWLock:lock_manager`のドライバーになり得ます。

### ハードウェアのボトルネックを減らす
<a name="wait-event.lw-lock-manager.actions.hw-bottlenecks"></a>

CPU の枯渇や Amazon EBS 帯域幅の最大使用率など、ハードウェアのボトルネックが発生する可能性があります。このような場合は、ハードウェアのボトルネックを減らすことを検討してください。以下のアクションの場合を検討します。
+ インスタンスクラスをスケールアップします。
+ 大量の CPU とメモリを消費するクエリを最適化します。
+ アプリケーションロジックを変更します。
+ データをアーカイブします。

CPU、メモリ、および EBS ネットワーク帯域幅の詳細については、[Amazon RDS インスタンスタイプ](https://aws.amazon.com/rds/instance-types/)を参照してください。

### 接続プーラーを使用する
<a name="wait-event.lw-lock-manager.actions.pooler"></a>

アクティブな接続の総数が最大 vCPU を超えると、インスタンスタイプがサポートできるより多くの OS プロセスが CPU を必要とします。このような場合は、接続プールの使用またはチューニングを検討してください。インスタンスタイプの vCPUs の詳細については、「[Amazon RDS インスタンスタイプ](https://aws.amazon.com/rds/instance-types/)」を参照してください。

 接続プールの詳細については、次のリソースを参照してください。
+ [Amazon RDS Proxy ](rds-proxy.md)
+ [pgbouncer](http://www.pgbouncer.org/usage.html)
+ *PostgreSQL ドキュメント*の[接続プールとデータソース](https://www.postgresql.org/docs/7.4/jdbc-datasource.html)

### RDS for PostgreSQL バージョンのアップグレード
<a name="wait-event.lw-lock-manager.actions.pg-version"></a>

現在使用している RDS for PostgreSQL のバージョンが 12 より前のものであれば、バージョン 12 以降にアップグレードします。PostgreSQL バージョン 12 以降では、パーティションメカニズムが改良されています。バージョン12の詳細については、[PostgreSQL 12.0 リリースノート]( https://www.postgresql.org/docs/release/12.0/)を参照してください。RDS for PostgreSQL のアップグレードの詳細については、「[RDS for PostgreSQL DB エンジンのアップグレード](USER_UpgradeDBInstance.PostgreSQL.md)」を参照してください。