

# pgactive を使用したアクティブ/アクティブレプリケーションのサポート
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive"></a>

`pgactive` 拡張は、アクティブ/アクティブレプリケーションを使用して、複数の RDS for PostgreSQL データベースに対する書き込み操作をサポートおよび調整します。Amazon RDS for PostgreSQL は、次のバージョンの `pgactive` 拡張機能をサポートしています。
+ RDS for PostgreSQL バージョン 17.0 以降のバージョン
+ RDS for PostgreSQL 16.1 またはそれ以降の 16 バージョン
+ RDS for PostgreSQL 15.4-R2 以降のバージョン 15
+ RDS for PostgreSQL 14.10 以降のバージョン 14
+ RDS for PostgreSQL 13.13 以降のバージョン 13
+ RDS for PostgreSQL 12.17 以降のバージョン 12
+ RDS for PostgreSQL 11.22

**注記**  
レプリケーション設定に複数のデータベースに対する書き込み操作があると、競合が発生する可能性があります。詳細については、[アクティブ/アクティブレプリケーションの競合の処理](Appendix.PostgreSQL.CommonDBATasks.pgactive.handle-conflicts.md)を参照してください。

**Topics**
+ [pgactive 拡張の制限事項](#Appendix.PostgreSQL.CommonDBATasks.pgactive.requirements-limitations)
+ [pgactive 拡張機能の初期化](Appendix.PostgreSQL.CommonDBATasks.pgactive.basic-setup.md)
+ [RDS for PostgreSQL DB インスタンスのアクティブ/アクティブレプリケーションの設定](Appendix.PostgreSQL.CommonDBATasks.pgactive.setup-replication.md)
+ [pgactive メンバー間のレプリケーションラグの測定](Appendix.PostgreSQL.CommonDBATasks.pgactive.replicationlag.md)
+ [pgactive 拡張機能のパラメータ設定](Appendix.PostgreSQL.CommonDBATasks.pgactive.parameters.md)
+ [アクティブ/アクティブ競合について](Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.replication.md)
+ [pgactive スキーマについて](Appendix.PostgreSQL.CommonDBATasks.pgactive.schema.md)
+ [pgactive 関数リファレンス](pgactive-functions-reference.md)
+ [アクティブ/アクティブレプリケーションの競合の処理](Appendix.PostgreSQL.CommonDBATasks.pgactive.handle-conflicts.md)
+ [アクティブ/アクティブレプリケーションでのシーケンスの処理](Appendix.PostgreSQL.CommonDBATasks.pgactive.handle-sequences.md)

## pgactive 拡張の制限事項
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.requirements-limitations"></a>
+ すべてのテーブルには主キーが必要です。主キーがないと、更新や削除は許可されません。主キー列の値は更新しないでください。
+ シーケンスにはギャップがある場合があり、順序に従わないこともあります。シーケンスはレプリケートされません。詳細については、「[アクティブ/アクティブレプリケーションでのシーケンスの処理](Appendix.PostgreSQL.CommonDBATasks.pgactive.handle-sequences.md)」を参照してください。
+ DDL とラージオブジェクトはレプリケートされません。
+ セカンダリの一意のインデックスはデータの相違を引き起こす可能性があります。
+ 照合順序はグループ内のすべてのノードで同一である必要があります。
+ ノード間の負荷分散はアンチパターンです。
+ トランザクションが大きいと、レプリケーションの遅延が発生する可能性があります。

# pgactive 拡張機能の初期化
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.basic-setup"></a>

RDS for PostgreSQL DB インスタンスの `pgactive` 拡張機能を初期化するには、`rds.enable_pgactive` パラメータの値を `1` に設定し、データベースに拡張を作成します。これを行うと、`rds.logical_replication` パラメータと `track_commit_timestamp` パラメータが自動的に有効になり、`wal_level` の値が `logical` に設定されます。

これらのタスクを実行するには、`rds_superuser` ロールとしてアクセス許可が必要です。

AWS マネジメントコンソール または AWS CLI を使用して、必要な RDS for PostgreSQL DB インスタンスを作成できます。以下のステップでは、RDS for PostgreSQL DB インスタンスがカスタム DB パラメータグループに関連付けられていることを前提としています。カスタム DB パラメータグループの作成については、「[Amazon RDS のパラメータグループ](USER_WorkingWithParamGroups.md)」を参照してください。

## コンソール
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.basic-setup.CON"></a>

**pgactive 拡張機能を初期化するには**

1. AWS マネジメントコンソール にサインインし、Amazon RDS コンソール ([https://console.aws.amazon.com/rds/](https://console.aws.amazon.com/rds/)) を開きます。

1. ナビゲーションペインで、RDS for PostgreSQL DB インスタンスを選択します。

1. RDS for PostgreSQL DB インスタンスの **[設定]** タブを開きます。インスタンスの詳細で、**[DB インスタンスパラメータグループ]** リンクを見つけます。

1. リンクを選択して、RDS for PostgreSQL DB インスタンスに関連付けられたカスタムパラメータを開きます。

1. `rds.enable_pgactive` パラメータを見つけて `1` に設定し、`pgactive` 機能を初期化します。

1. **[Save changes]** (変更の保存) をクリックします。

1. Amazon RDS コンソールのナビゲーションペインで、**[データベース]** を選択します。

1. RDS for PostgreSQL DB インスタンスを選択し、**[アクション]** メニューから **[再起動]** を選択します。

1. DB インスタンスの再起動を確定して、変更を有効にします。

1. DB インスタンスが使用可能になったら、`psql` または他の任意の PostgreSQL インスタンスを使用して RDS for PostgreSQL DB インスタンスに接続します。

   次の例では、RDS for PostgreSQL DB インスタンスに *postgres* という名前のデフォルトデータベースがあることを前提としています。

   ```
   psql --host=mydb.111122223333.aws-region.rds.amazonaws.com --port=5432 --username=postgres --password=PASSWORD --dbname=postgres
   ```

1. pgactive が初期化されていることを確認するには、次のコマンドを実行します。

   ```
   postgres=>SELECT setting ~ 'pgactive' 
   FROM pg_catalog.pg_settings
   WHERE name = 'shared_preload_libraries';
   ```

   `pgactive` が `shared_preload_libraries` にある場合、前述のコマンドは以下を返します。

   ```
   ?column? 
   ----------
    t
   ```

## AWS CLI
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.basic-setup.CLI"></a>

**pgactive 拡張機能を初期化するには**

AWS CLI を使用して `pgactive` を設定するには、次の手順に示すように、[modify-db-parameter-group](https://docs.aws.amazon.com/cli/latest/reference/rds/modify-db-parameter-group.html) オペレーションを呼び出してカスタムパラメータグループ内の特定のパラメータを変更します。

1. AWS CLI コマンドを使用して `rds.enable_pgactive` を `1` に設定し、RDS for PostgreSQL DB インスタンスの `pgactive` 機能を初期化します。

   ```
   postgres=>aws rds modify-db-parameter-group \
      --db-parameter-group-name custom-param-group-name \
      --parameters "ParameterName=rds.enable_pgactive,ParameterValue=1,ApplyMethod=pending-reboot" \
      --region aws-region
   ```

1. 次の AWS CLI コマンドを使用して RDS for PostgreSQL DB インスタンスを再起動し、`pgactive` ライブラリを初期化します。

   ```
   aws rds reboot-db-instance \
       --db-instance-identifier your-instance \
       --region aws-region
   ```

1. インスタンスが使用可能になったら、`psql` を使用して RDS for PostgreSQL DB インスタンスに接続します。

   ```
   psql --host=mydb.111122223333.aws-region.rds.amazonaws.com --port=5432 --username=master user --password=PASSWORD --dbname=postgres
   ```

1. pgactive が初期化されていることを確認するには、次のコマンドを実行します。

   ```
   postgres=>SELECT setting ~ 'pgactive' 
   FROM pg_catalog.pg_settings
   WHERE name = 'shared_preload_libraries';
   ```

   `pgactive` が `shared_preload_libraries` にある場合、前述のコマンドは以下を返します。

   ```
   ?column? 
   ----------
    t
   ```

# RDS for PostgreSQL DB インスタンスのアクティブ/アクティブレプリケーションの設定
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.setup-replication"></a>

以下の手順は、`pgactive` が利用可能な場合に 2 つの RDS for PostgreSQL DB インスタンス間でアクティブ/アクティブレプリケーションを開始する方法を示しています。マルチリージョンの高可用性の例を実行するには、2 つの異なるリージョンに Amazon RDS for PostgreSQL インスタンスをデプロイし、VPC ピアリングを設定する必要があります。詳細については、「[VPC ピアリング接続](https://docs.aws.amazon.com/vpc/latest/peering/what-is-vpc-peering.html)」を参照してください。

**注記**  
複数のリージョン間でトラフィックを送信すると、追加コストが発生する可能性があります。

次の手順では、RDS for PostgreSQL DB インスタンスが `pgactive` 拡張を使用して有効化されていることを前提としています。詳細については、「[pgactive 拡張機能の初期化](Appendix.PostgreSQL.CommonDBATasks.pgactive.basic-setup.md)」を参照してください。

**`pgactive` 拡張を使用して最初の RDS for PostgreSQL DB インスタンスを設定するには**

次の例は、`pgactive` グループの作成方法と、RDS for PostgreSQL DB インスタンスで `pgactive` 拡張を作成するために必要なその他の手順を示しています。

1. `psql` または別のクライアントツールを使用して、最初の RDS for PostgreSQL DB インスタンスに接続します。

   ```
   psql --host=firstinstance.111122223333.aws-region.rds.amazonaws.com --port=5432 --username=postgres --password=PASSWORD --dbname=postgres
   ```

1. 次のコマンドを使用して RDS for PostgreSQL インスタンスにデータベースを作成します。

   ```
   postgres=> CREATE DATABASE app;
   ```

1. 次のコマンドを使用して、接続先を新しいデータベースに切り替えます。

   ```
   \c app
   ```

1. 次の SQL ステートメントを使用して、サンプルのテーブルを作成および設定します。

   1. 次の SQL ステートメントを使用してサンプルテーブルを作成します。

      ```
      app=> CREATE SCHEMA inventory;
      CREATE TABLE inventory.products (
      id int PRIMARY KEY, product_name text NOT NULL,
      created_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP);
      ```

   1. 次の SQL ステートメントを使用して、サンプルデータをテーブルに入力します。

      ```
      app=> INSERT INTO inventory.products (id, product_name)
      VALUES (1, 'soap'), (2, 'shampoo'), (3, 'conditioner');
      ```

   1. 次の SQL ステートメントを使用して、テーブルにデータが存在することを確認します。

      ```
       app=>SELECT count(*) FROM inventory.products;
      
       count
      -------
       3
      ```

1. 既存のデータベースで `pgactive` 拡張を作成します。

   ```
   app=> CREATE EXTENSION pgactive;
   ```

1. pgactive グループを安全に作成して初期化するには、以下のコマンドを使用します。

   ```
   app=>
   -- connection info for endpoint1
   CREATE SERVER pgactive_server_endpoint1
       FOREIGN DATA WRAPPER pgactive_fdw
       OPTIONS (host '<endpoint1>', dbname 'app');
   CREATE USER MAPPING FOR postgres
       SERVER pgactive_server_endpoint1
       OPTIONS (user 'postgres', password '<password>');
         -- connection info for endpoint2
   CREATE SERVER pgactive_server_endpoint2
       FOREIGN DATA WRAPPER pgactive_fdw
       OPTIONS (host '<endpoint2>', dbname 'app');
   CREATE USER MAPPING FOR postgres
       SERVER pgactive_server_endpoint2
       OPTIONS (user 'postgres', password '<password>');
   ```

   これで、レプリケーショングループを初期化し、この最初のインスタンスを追加できます。

   ```
   SELECT pgactive.pgactive_create_group(
       node_name := 'endpoint1-app',
       node_dsn := 'user_mapping=postgres pgactive_foreign_server=pgactive_server_endpoint1'
   
   );
   ```

   代替手段として、以下のコマンドを使用して pgactive グループを作成および初期化します。ただし、安全性は低くなります。

   ```
   app=> SELECT pgactive.pgactive_create_group(
       node_name := 'node1-app',
       node_dsn := 'dbname=app host=firstinstance.111122223333.aws-region.rds.amazonaws.com user=postgres password=PASSWORD');
   ```

   node1-app は、`pgactive` グループ内のノードを一意に識別するために割り当てる名前です。
**注記**  
パブリックにアクセス可能な DB インスタンスで、このステップを正常に実行するには、`rds.custom_dns_resolution` パラメータを `1` に設定して有効にする必要があります。

1. DB インスタンスの準備が整っているかどうかを確認するには、次のコマンドを使用します。

   ```
   app=> SELECT pgactive.pgactive_wait_for_node_ready();
   ```

   コマンドが正常に完了した場合は、次の出力が表示されます。

   ```
   pgactive_wait_for_node_ready 
   ------------------------------ 
   (1 row)
   ```

**2 番目の RDS for PostgreSQL インスタンスを設定して `pgactive` グループに参加させるには**

次の例は、RDS for PostgreSQL DB インスタンスを `pgactive` グループに参加させる方法と、DB インスタンスに `pgactive` 拡張を作成するために必要なその他のステップを示しています。

次の手順では、RDS for PostgreSQL DB インスタンスが `pgactive` 拡張を使用して設定されていることを前提としています。詳細については、「[pgactive 拡張機能の初期化](Appendix.PostgreSQL.CommonDBATasks.pgactive.basic-setup.md)」を参照してください。

1. `psql` を使用して、パブリッシャーから更新を受け取るインスタンスに接続します。

   ```
   psql --host=secondinstance.111122223333.aws-region.rds.amazonaws.com --port=5432 --username=postgres --password=PASSWORD --dbname=postgres
   ```

1. 次のコマンドを使用して、2 番目の RDS for PostgreSQL DB インスタンスにデータベースを作成します。

   ```
   postgres=> CREATE DATABASE app;
   ```

1. 次のコマンドを使用して、接続先を新しいデータベースに切り替えます。

   ```
   \c app
   ```

1. 既存のデータベースに `pgactive` 拡張を作成します。

   ```
   app=> CREATE EXTENSION pgactive;
   ```

1. 次に示すように、以下のコマンドを使用して、より安全な方法で RDS for PostgreSQL の 2 番目の DB インスタンスを `pgactive` グループに参加させます。

   ```
   -- connection info for endpoint1
   CREATE SERVER pgactive_server_endpoint1
       FOREIGN DATA WRAPPER pgactive_fdw
       OPTIONS (host '<endpoint1>', dbname 'app');
   CREATE USER MAPPING FOR postgres
       SERVER pgactive_server_endpoint1
       OPTIONS (user 'postgres', password '<password>');
   
   -- connection info for endpoint2
   CREATE SERVER pgactive_server_endpoint2
       FOREIGN DATA WRAPPER pgactive_fdw
       OPTIONS (host '<endpoint2>', dbname 'app');
   CREATE USER MAPPING FOR postgres
       SERVER pgactive_server_endpoint2
       OPTIONS (user 'postgres', password '<password>');
   ```

   ```
   SELECT pgactive.pgactive_join_group(
       node_name := 'endpoint2-app',
       node_dsn := 'user_mapping=postgres pgactive_foreign_server=pgactive_server_endpoint2',
       join_using_dsn := 'user_mapping=postgres pgactive_foreign_server=pgactive_server_endpoint1'
   );
   ```

   代替手段として、以下のコマンドを使用して RDS for PostgreSQL の 2 番目の DB インスタンスを `pgactive` グループに参加させます。ただし、安全性は低くなります。

   ```
   app=> SELECT pgactive.pgactive_join_group(
   node_name := 'node2-app',
   node_dsn := 'dbname=app host=secondinstance.111122223333.aws-region.rds.amazonaws.com user=postgres password=PASSWORD',
   join_using_dsn := 'dbname=app host=firstinstance.111122223333.aws-region.rds.amazonaws.com user=postgres password=PASSWORD');
   ```

   node2-app は、`pgactive` グループ内のノードを一意に識別するために割り当てる名前です。

1. DB インスタンスの準備が整っているかどうかを確認するには、次のコマンドを使用します。

   ```
   app=> SELECT pgactive.pgactive_wait_for_node_ready(); 
   ```

   コマンドが正常に完了すると、次の出力が表示されます。

   ```
   pgactive_wait_for_node_ready 
   ------------------------------ 
   (1 row)
   ```

   最初の RDS for PostgreSQL データベースが比較的大きい場合は、`pgactive.pgactive_wait_for_node_ready()` から復元操作の進行状況レポートを出力されることを確認できます。出力は次の例のようになります:

   ```
   NOTICE:  restoring database 'app', 6% of 7483 MB complete
   NOTICE:  restoring database 'app', 42% of 7483 MB complete
   NOTICE:  restoring database 'app', 77% of 7483 MB complete
   NOTICE:  restoring database 'app', 98% of 7483 MB complete
   NOTICE:  successfully restored database 'app' from node node1-app in 00:04:12.274956
    pgactive_wait_for_node_ready 
   ------------------------------ 
   (1 row)
   ```

   この時点から、`pgactive` は 2 つの DB インスタンス間でデータを同期します。

1. 次のコマンドを使用して、2 番目の DB インスタンスのデータベースにデータがあるかどうかを確認できます。

   ```
   app=> SELECT count(*) FROM inventory.products;
   ```

   データが正常に同期されると、次の出力が表示されます。

   ```
    count
   -------
    3
   ```

1. 次のコマンドを実行して新しい値を挿入します。

   ```
   app=> INSERT INTO inventory.products (id, product_name) VALUES (4, 'lotion');
   ```

1. 最初の DB インスタンスのデータベースに接続し、次のクエリを実行します。

   ```
   app=> SELECT count(*) FROM inventory.products;
   ```

   アクティブ/アクティブレプリケーションが初期化されると、出力は次のようになります。

   ```
   count
   -------
    4
   ```

**`pgactive` グループから DB インスタンスをデタッチして削除するには**

`pgactive` グループから DB インスタンスをデタッチして削除するには、次の手順に従います。

1. 次のコマンドを使用して、最初のインスタンスから 2 番目の DB インスタンスをデタッチできます。

   ```
   app=> SELECT * FROM pgactive.pgactive_detach_nodes(ARRAY[‘node2-app']);
   ```

1. 次のコマンドを使用して、2 番目の DB インスタンスから `pgactive` 拡張を削除します。

   ```
   app=> SELECT * FROM pgactive.pgactive_remove();
   ```

   拡張を強制的に削除するには

   ```
   app=> SELECT * FROM pgactive.pgactive_remove(true);
   ```

1. 次のコマンドを使用して拡張をドロップします。

   ```
   app=> DROP EXTENSION pgactive;
   ```

# pgactive メンバー間のレプリケーションラグの測定
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.replicationlag"></a>

次のクエリを使用して、`pgactive` メンバー間のレプリケーションラグを表示できます。全体像を把握するには、すべての `pgactive` ノードでこのクエリを実行します。

```
    
app=> SELECT * FROM pgactive.pgactive_get_replication_lag_info();
│-[ RECORD 1 ]--------+---------------------------------------------
│node_name            | node2-app
│node_sysid           | 7481018224801653637
│application_name     | pgactive:7481018224801653637:send
│slot_name            | pgactive_16385_7481018224801653637_0_16385__
│active               | t
│active_pid           | 783486
│pending_wal_decoding | 0
│pending_wal_to_apply | 0
│restart_lsn          | 0/2108150
│confirmed_flush_lsn  | 0/2154690
│sent_lsn             | 0/2154690
│write_lsn            | 0/2154690
│flush_lsn            | 0/2154690
│replay_lsn           | 0/2154690
│-[ RECORD 2 ]--------+---------------------------------------------
│node_name            | node1-app
│node_sysid           | 7481018033434600853
│application_name     | pgactive:7481018033434600853:send
│slot_name            | pgactive_16385_7481018033434600853_0_16385__
│active               | t
│active_pid           | 783488
│pending_wal_decoding | 0
│pending_wal_to_apply | 0
│restart_lsn          | 0/20F5AD0
│confirmed_flush_lsn  | 0/214EF68
│sent_lsn             | 0/214EF68
│write_lsn            | 0/214EF68
│flush_lsn            | 0/214EF68
│replay_lsn           | 0/214EF68
```

少なくとも次の診断をモニタリングします。

アクティブ  
アクティブが false の場合にアラートを設定します。これは、スロットが現在使用されていない (サブスクライバーインスタンスがパブリッシャーから切断された) ことを示します。

Pending\$1wal\$1decoding  
PostgreSQL の論理レプリケーションでは、WAL ファイルはバイナリ形式で保存されます。パブリッシャーは、これらの WAL の変更をデコードし、論理的な変更 (挿入、更新、削除オペレーションなど) に変換する必要があります。  
pending\$1wal\$1decoding メトリクスは、パブリッシャー側でデコードを待っている WAL ファイルの数を示します。  
この数は、次の要因により増加する可能性があります。  
+ サブスクライバーが接続されていない場合、アクティブステータスは false になり、pending\$1wal\$1decoding は増加する
+ スロットはアクティブだが、パブリッシャーは WAL の変更の量に対応できない

pending\$1wal\$1to\$1apply  
pending\$1wal\$1apply メトリクスは、サブスクライバー側で適用を待っている WAL ファイルの数を示します。  
いくつかの要因により、サブスクライバーが変更を適用できなくなり、ディスクがいっぱいになるシナリオが発生する可能性があります。  
+ スキーマの違い - サンプルという名前のテーブルの WAL ストリームに変更があっても、そのテーブルがサブスクライバー側に存在しない場合など
+ プライマリキー列の値が更新された場合
+ セカンダリの一意のインデックスはデータの相違を引き起こす可能性がある

# pgactive 拡張機能のパラメータ設定
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.parameters"></a>

次のクエリを使用すると、`pgactive` 拡張に関連するすべてのパラメータを表示できます。

```
app=> SELECT * FROM pg_settings WHERE name LIKE 'pgactive.%';
```

`pgactive` 拡張機能は、さまざまなパラメータを使用して設定できます。これらのパラメータは、AWS マネジメントコンソール または CLI AWS インターフェイスから設定できます。

## 主な pgactive 拡張機能パラメータ
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.mainparams"></a>

次の表は、`pgactive` 拡張機能の主なパラメータのリファレンスです。


| パラメータ | 単位 | デフォルト | 説明  | 
| --- | --- | --- | --- | 
| pgactive.conflict\$1logging\$1include\$1tuples | `boolean` | –  | `pgactive` 拡張機能の完全なタプル情報をログに記録します。  変更を有効にするには、サーバーの再起動が必要です。  | 
| pgactive.log\$1conflicts\$1to\$1table | `boolean` | –  | `pgactive` 拡張機能が検出された競合を `pgactive.pgactive_conflict_history` テーブルにログ記録するかどうかを決定します。詳細については、「競合のログ記録」を参照してください。  変更を有効にするには、サーバーの再起動が必要です。  | 
| pgactive.log\$1conflicts\$1to\$1logfile | `boolean` | –  | `pgactive` 拡張機能が検出された競合を PostgreSQL ログファイルに記録するかどうかを決定します。詳細については、「競合のログ記録」を参照してください。  変更を有効にするには、サーバーの再起動が必要です。  | 
| pgactive.synchronous\$1commit | `boolean` | 化 | pgactive 適用ワーカーのコミット動作を決定します。無効 (オフ) にすると、適用ワーカーは非同期コミットを実行します。これにより、適用オペレーション中の PostgreSQL のスループットが向上しますが、アップストリームへのリプレイ確認が遅延します。`off` に設定しても常に安全であり、トランザクションの損失やスキップは発生しません。この設定は、ダウンストリームノードでのディスクフラッシュのタイミングと、確認がアップストリームに送信されるタイミングにのみ影響します。システムは、チェックポイントや定期的な作業などの関連しないオペレーションを通じてコミットがディスクにフラッシュされるまで、リプレイフラッシュ確認の送信を遅らせます。ただし、アップストリームノードの `synchronous_standby_names` にダウンストリームがリストされている場合、`off` に設定すると、アップストリームノードでの同期コミットがクライアントに成功を報告するまでの時間が長くなります。この場合、パラメータは `on` に設定してください。  このパラメータが `on` に設定されていても、`synchronous_standby_names` にノードがリストされている場合は、アクティブ/アクティブ設定ではレプリケーションの競合が発生する可能性があります。これは、システムにはノード間ロックとグローバルスナップショット管理がないため、異なるノード上の同時トランザクションが同じタプルを変更できるためです。さらに、トランザクションはアップストリームノードでコミットした後にのみレプリケーションを開始します。同期コミットを有効にしても、pgactive 拡張機能が常時一貫性のあるシステムになるわけではありません。  | 
| pgactive.temp\$1dump\$1directory | `string` | – | 初期設定時のデータベースクローン作成オペレーションに必要な一時ストレージパスを定義します。このディレクトリは postgres ユーザーによって書き込み可能で、完全なデータベースダンプを格納するのに十分なストレージ容量を持っている必要があります。システムは、論理コピーオペレーションによるデータベースの初期セットアップ中にのみ、この場所を使用します。このパラメータは、`pgactive_init_copy command` では使用されません。 | 
| pgactive.max\$1ddl\$1lock\$1delay | `milliseconds` | `-1` | 同時書き込みトランザクションを強制的に中止するまでの DDL ロックの最大待機時間を指定します。デフォルト値は `-1` で、`max_standby_streaming_delay` で設定された値が使用されます。このパラメータには時間単位を指定できます。例えば、10 秒の場合は 10s と設定できます。この待機期間中、システムは進行中の書き込みトランザクションがコミットまたはロールバックされるのを待つ間に DDL ロックの取得を試みます。詳細については、「DDL ロック」を参照してください。 | 
| pgactive.ddl\$1lock\$1timeout | `milliseconds` | `-1` | DDL ロック試行がロックの取得を待機する時間を指定します。デフォルト値は `-1` で、lock\$1timeout で指定された値を使用します。このパラメータは、10 秒の場合は 10s などの時間単位で設定できます。このタイマーは、DDL ロックを取得するための待機期間のみを制御します。システムがロックを取得し、DDL オペレーションを開始すると、タイマーは停止します。このパラメータは、DDL ロックを保持できる合計期間や全体的な DDL オペレーション時間を制限するものではありません。オペレーションの合計期間を制御するには、代わりに `statement_timeout` を使用します。詳細については、「DDL ロック」を参照してください。 | 
| pgactive.debug\$1trace\$1ddl\$1locks\$1level | `boolean` | –  | `pgactive` 拡張機能の DDL ロックオペレーションのデフォルトのデバッグログレベルを上書きします。この設定を行うと、DDL ロック関連のメッセージがデフォルトレベルではなく LOG デバッグレベルで出力されます。このパラメータを使用して、サーバー全体で詳細な `DEBUG1` または `DEBUG2` ログレベルを有効にせずに、DDL ロックアクティビティをモニタリングできます。 詳細度の高い順序で使用可能なログレベル。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.pgactive.parameters.html) モニタリングオプションの詳細については、「グローバル DDL ロックのモニタリング」を参照してください。  この設定の変更は、設定を再読み込みすると有効になります。サーバーを再起動する必要はありません。   | 

## 追加の pgactive 拡張機能パラメータ
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.addparams"></a>

次の表は、`pgactive` 拡張機能で利用可能な、あまり使用されない内部設定オプションを示しています。


| パラメータ | 単位 | デフォルト | 説明  | 
| --- | --- | --- | --- | 
| pgactive.debug\$1apply\$1delay | `integer` | – |  `pgactive.pgactive_connections` エントリに明示的に適用遅延が指定されていない設定済み接続の適用遅延 (ミリ秒単位) を設定します。この遅延はノード作成時または参加時に設定され、pgactive はコミットされてから指定されたミリ秒数が経過するまで、ピアノードでトランザクションをリプレイしません。 主に、テスト環境で高レイテンシーのネットワークをシミュレートして、競合を簡単に作成するために使用します。例えば、ノード A とノード B に 500 ミリ秒の遅延が設定されている場合、ノード A に値を挿入した後、ノード B で競合する挿入を実行するために少なくとも 500 ミリ秒の猶予があります。  適用ワーカーを有効にするには、サーバーの再ロードまたは再起動が必要です。  | 
| pgactive.connectability\$1check\$1duration | `integer` | –  | データベースワーカーが接続の確立に失敗した場合に、接続を確立しようとする時間 (秒単位) を指定します。ワーカーは、成功するかこのタイムアウト値に達するまで、1 秒ごとに接続を試行します。この設定は、ワーカーが接続を確立する準備ができる前にデータベースエンジンが起動する場合に便利です。 | 
| pgactive.skip\$1ddl\$1replication | `boolean` | `on` | `pgactive` が有効になっている Amazon RDS で DDL の変更をレプリケートまたは処理する方法を制御します。`on` に設定すると、ノードは非 pgcctive ノードと同様に DDL 変更を処理します。このパラメータを使用する場合、以下の要件が適用されます。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.pgactive.parameters.html) このパラメータは、スーパーユーザー権限を使用してグローバル、ローカル (セッションレベル) の 2 つの方法で変更できます。  このパラメータを誤って変更すると、レプリケーションのセットアップが中断される可能性があります。  | 
| pgactive.do\$1not\$1replicate | `boolean` | – | このパラメータは内部使用のみを目的としています。トランザクションでこのパラメータを設定すると、変更は DB クラスター内の他のノードにレプリケートされません。  このパラメータを誤って変更すると、レプリケーションのセットアップが中断される可能性があります。  | 
| pgactive.discard\$1mismatched\$1row\$1attributes | `boolean` | –  | このパラメータは専門家による使用のみを目的としています。このパラメータは、特定のレプリケーションの問題をトラブルシューティングする場合にのみ使用することをお勧めします。このパラメータは、次の場合に使用します。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.pgactive.parameters.html) この設定により、以下のエラーメッセージがオーバーライドされ、データの不一致が発生してもレプリケーションは続行されます。「`cannot right-pad mismatched attributes; attno %u is missing in local table and remote row has non-null, non-dropped value for this attribute`」  このパラメータを誤って変更すると、レプリケーションのセットアップが中断される可能性があります。   | 
| pgactive.debug\$1trace\$1replay | `boolean` | – | `on` に設定すると、ダウンストリームの適用ワーカーが処理するリモートアクションごとにログメッセージが出力されます。ログには以下が含まれます。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.pgactive.parameters.html) ログには、キューに登録された DDL コマンドとテーブルの DROP も記録されます。para> デフォルトでは、ログには行フィールドの内容は含まれません。ログに行の値を含めるには、次のフラグを有効にして再コンパイルする必要があります。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.pgactive.parameters.html)  このログ記録設定を有効にすると、パフォーマンスに影響する可能性があります。トラブルシューティングに必要な場合にのみ有効にすることをお勧めします。この設定の変更は、設定を再読み込みすると有効になります。サーバーを再起動する必要はありません。   | 
| pgactive.extra\$1apply\$1connection\$1options |  | – | pgactive ノードとのすべてのピアノード接続の接続パラメータを設定できます。これらのパラメータは、keepalives や SSL モードなどの設定を制御します。デフォルトでは、pgactive は次の接続パラメータを使用します。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.pgactive.parameters.html) デフォルトのパラメータを上書きするには、以下の同様のコマンドを使用します。 pgactive.extra\$1apply\$1connection\$1options = 'keepalives=0' 個々のノード接続文字列は、これらの設定と pgactive の組み込み接続オプションの両方よりも優先されます。接続文字列形式の詳細については、「[libpq connection strings](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING)」を参照してください。 デフォルトの keepalives 設定は有効のままにすることをお勧めします。信頼性の低いネットワーク経由で大規模なトランザクションが完了する際に問題が発生する場合にのみ、keepalives を無効にしてください。  デフォルトのkeepalives 設定は有効のままにすることをお勧めします。信頼性の低いネットワーク経由で大規模なトランザクションが完了する際に問題が発生する場合にのみ、keepalives を無効にしてください。この設定の変更は、設定を再読み込みすると有効になります。サーバーを再起動する必要はありません。  | 
| pgactive.init\$1node\$1parallel\$1jobs (int) |  | – | `pgactive.pgactive_join_group` 関数を使用して、論理ノードの結合時に `pg_dump` と `pg_restore` が使用できる並列ジョブの数を指定します。 この設定の変更は、設定を再読み込みすると有効になります。サーバーを再起動する必要はありません。 | 
| pgactive.max\$1nodes | `int` | 4 |  pgactive 拡張グループで許可されるノードの最大数を指定します。デフォルト値は 4 ノードです。このパラメータの値を設定するときは、次の点を考慮する必要があります。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.pgactive.parameters.html) このパラメータは、設定ファイルで設定する方法と、`ALTER SYSTEM SET` コマンドを使用する方法の 2 つの方法で設定できます。 このパラメータのデフォルト値は `4` です。つまり、`pgactive` 拡張グループには、いつでも最大 4 ノードまでしか参加できません。  この変更は、サーバーを再起動した後に有効になります。  | 
| pgactive.permit\$1node\$1identifier\$1getter\$1function\$1creation | `boolean` | – | このパラメータは、内部使用のみを目的としています。有効にすると、`pgactive` 拡張機能により、pgactive ノード識別子 getter 関数の作成が可能になります。 | 

# アクティブ/アクティブ競合について
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.replication"></a>

pgactive をアクティブ/アクティブモードで使用する場合、複数のノードから同じテーブルに書き込むと、データの競合が発生する可能性があります。一部のクラスタリングシステムでは、同時アクセスを防ぐために分散ロックを使用していますが、pgactive は地理的に分散されたアプリケーションに適した楽観的なアプローチを採用しています。

一部のデータベースクラスタリングシステムは、分散ロックを使用して同時データアクセスを防止します。このアプローチはサーバーが近接している場合に機能しますが、優れたパフォーマンスのためには非常に低いレイテンシーが必要となるため、地理的に分散したアプリケーションはサポートしていません。pgactive 拡張機能は、分散ロック (悲観的アプローチ) を使用する代わりに、楽観的アプローチを使用します。つまり、次のことを意味します。
+ 可能な場合には競合を回避できます。
+ 特定のタイプの競合の発生を許可します。
+ 競合が発生した場合に競合を解決します。

このアプローチにより、分散アプリケーションを構築する際の柔軟性が向上します。

## 競合の発生方法
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.howconflicts"></a>

ノード間の競合は、関連するすべてのトランザクションが同じノードで同時に発生した場合には発生しない一連のイベントから発生します。ノード間の変更はトランザクションのコミット後にのみ行われるため、各トランザクションはコミットされたノードで個別に有効ですが、その間に他の作業を行った別のノードで実行された場合は有効になりません。pgactive 適用は基本的に他のノードでトランザクションを再実行するため、適用されているトランザクションと受信側ノードでコミットされたトランザクションの間に競合がある場合、再実行オペレーションが失敗する可能性があります。

 すべてのトランザクションが単一のノードで実行されている場合にほとんどの競合が発生しないのは、PostgreSQL にそれを防ぐためのトランザクション間通信メカニズムがあるからです。これには、以下が含まれます。
+ UNIQUE インデックス
+ SEQUENCE
+ 行とリレーションのロック
+ SERIALIZABLE 依存関係の追跡

これらのメカニズムはすべて、望ましくない同時実行の問題を防ぐためにトランザクション間で通信する方法です。

pgactive は、分散トランザクションマネージャーやロックマネージャーを使用しないため、低レイテンシーを実現し、ネットワークパーティションを適切に処理します。ただし、これは、異なるノード上のトランザクションが相互に完全に分離して実行されることを意味します。通常、分離はデータベースの一貫性を向上させますが、この場合は、競合を防ぐために分離を減らす必要があります。

## 競合のタイプ
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflicttypes"></a>

発生する可能性のある競合には、以下が含まれます。

**Topics**
+ [PRIMARY KEY または UNIQUE の競合](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict1)
+ [INSERT/INSERT の競合](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict2)
+ [複数の UNIQUE 制約に違反する INSERT](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict3)
+ [UPDATE/UPDATE の競合](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict4)
+ [PRIMARY KEY の UPDATE 競合](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict5)
+ [複数の UNIQUE 制約に違反するUPDATE](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict6)
+ [UPDATE/DELETE の競合](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict7)
+ [INSERT/UPDATE の競合](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict8)
+ [DELETE/DELETE の競合](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict9)
+ [外部キー制約の競合](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict10)
+ [排他制約の競合](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict11)
+ [グローバルデータの競合](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict12)
+ [ロックの競合とデッドロックの中止](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict13)
+ [相違による競合](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict14)

### PRIMARY KEY または UNIQUE の競合
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict1"></a>

行の競合は、複数のオペレーションが単一のノードで同じ行キーを変更しようとしたときに発生します。これらの競合は、最も一般的なタイプのデータ競合です。

pgactive は検出された競合を、最終更新を優先する処理またはカスタム競合ハンドラーで解決します。

行の競合には以下が含まれます。
+ INSERT と INSERT
+ INSERT と UPDATE
+ UPDATE と DELETE
+ INSERT と DELETE
+ DELETE と DELETE
+ INSERT と DELETE

### INSERT/INSERT の競合
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict2"></a>

この最も一般的な競合は、2 つの異なるノードの INSERT が同じ PRIMARY KEY 値 (または PRIMARY KEY が存在しない場合は同じ UNIQUE 制約値) を持つタプルを作成するときに発生します。

pgactivelink は、発信元ホストのタイムスタンプを使用して最新のタプルを保持することで、INSERT の競合を解決します。このデフォルトの動作は、カスタム競合ハンドラーで上書きできます。このプロセスでは特別な管理者アクションは必要ありませんが、pgactivelink はノード全体で 1 つの INSERT オペレーションを破棄することに注意してください。カスタムハンドラーが実装しない限り、自動データマージは発生しません。

pgactivelink は、単一の制約違反に関連する競合のみを解決できます。INSERT が複数の UNIQUE 制約に違反している場合は、追加の競合解決戦略を実装する必要があります。

### 複数の UNIQUE 制約に違反する INSERT
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict3"></a>

INSERT/INSERT 競合は、PRIMARY KEY を含む複数の UNIQUE 制約に違反する可能性があります。pgactivelink は、単一の UNIQUE 制約を含む競合のみを処理できます。競合が複数の UNIQUE 制約に違反すると、適用ワーカーは失敗し、次のエラーを返します。

`multiple unique constraints violated by remotely INSERTed tuple.`

古いバージョンでは、この状況では代わりに「一意性の相違による競合」エラーが発生しました。

これらの競合を解決するには、手動でアクションを実行する必要があります。競合するローカルタプルを DELETE するか、UPDATE して新しいリモートタプルとの競合を削除します。複数の競合するタプルに対処する必要がある場合があることに注意してください。現在、pgactivelink には、複数の一意の制約に違反するタプルを無視、破棄、またはマージする組み込み機能はありません。

**注記**  
詳細については、「複数の UNIQUE 制約に違反する UPDATE」を参照してください。

### UPDATE/UPDATE の競合
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict4"></a>

この競合は、2 つのノードが PRIMARY KEY を変更せずに同じタプルを同時に変更した場合に発生します。pgactivelink は、定義されている場合には、最終更新を優先するロジックまたはカスタム競合ハンドラーを使用してこれらの競合を解決します。PRIMARY KEY は、タプルマッチングと競合の解決に不可欠です。PRIMARY KEY のないテーブルの場合、pgactivelink は次のエラーで UPDATE オペレーションを拒否します。

`Cannot run UPDATE or DELETE on table (tablename) because it does not have a primary key.`

### PRIMARY KEY の UPDATE 競合
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict5"></a>

pgactive は、PRIMARY KEY 更新を処理する際に制限があります。PRIMARY KEY で UPDATE オペレーションを実行することはできますが、pgactive はこれらのオペレーションに最終更新を優先するロジックを使用して競合を自動的に解決することはできません。PRIMARY KEY の更新が既存の値と競合しないようにする必要があります。PRIMARY KEY の更新中に競合が発生した場合、相違による競合が発生し、手動による介入が必要になります。これらの状況の処理の詳細については、「[相違による競合](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict14)」を参照してください。

### 複数の UNIQUE 制約に違反するUPDATE
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict6"></a>

pgactivelink は、受信する UPDATE が複数の UNIQUE 制約または PRIMARY KEY 値に違反している場合、最終更新を優先する競合解決を適用できません。この動作は、複数の制約違反がある INSERT オペレーションに似ています。このような状況では、手動による介入を必要とする相違による競合が発生します。詳細については、「[相違による競合](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict14)」を参照してください。

### UPDATE/DELETE の競合
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict7"></a>

この競合は、あるノードが行を UPDATE し、別のノードが同時にその行を DELETE した場合に発生します。この場合、再実行時に UPDATE/DELETE 競合が発生します。解決策は、カスタム競合ハンドラーが特に指定しない限り、DELETE の後に送信される UPDATE をすべて破棄することです。

pgactivelink は、タプルを照合して競合を解決するために PRIMARY KEY を必要とします。PRIMARY KEY のないテーブルの場合、次のエラーで DELETE オペレーションが拒否されます。

`Cannot run UPDATE or DELETE on table (tablename) because it does not have a primary key.`

**注記**  
pgactivelink は、UPDATE/DELETE と INSERT/UPDATE の競合を区別できません。どちらの場合も、UPDATE は存在しない行に影響します。非同期レプリケーションおよびノード間に再実行順序がないことにより、pgactivelink は UPDATE が新しい行 (INSERT をまだ受信していない) に対するものか、削除された行に対するものかを判断できません。どちらのシナリオでも、pgactivelink は UPDATE を破棄します。

### INSERT/UPDATE の競合
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict8"></a>

この競合は、マルチノード環境で発生する可能性があります。これは、あるノードが行を INSERT し、2 番目のノードが行を UPDATE し、3 番目のノードが元の INSERT の前に UPDATE を受信したときに発生します。デフォルトでは、カスタム競合トリガーで特に指定されていない限り、pgactivelink は UPDATE を破棄することで、これらの競合を解決します。この解決方法により、ノード間でデータの不整合が発生する可能性があることに注意してください。同様のシナリオとその処理の詳細については、「[UPDATE/DELETE の競合](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict7)」を参照してください。

### DELETE/DELETE の競合
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict9"></a>

この競合は、2 つの異なるノードが同じタプルを同時に削除した場合に発生します。pgactivelink は、両方の DELETE オペレーションの結果が同じであるため、これらの競合を無害と見なします。このシナリオでは、pgactivelink はデータ整合性に影響を与えることなく、一方の DELETE オペレーションを安全に無視します。

### 外部キー制約の競合
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict10"></a>

FOREIGN KEY の制約により、既存のローカルデータにリモートトランザクションを適用するときに競合が発生する可能性があります。これらの競合は通常、トランザクションが発信元ノードの論理順序とは異なる順序で適用された場合に発生します。

デフォルトでは、pgactive は session\$1replication\$1role を `replica` として変更を適用し、レプリケーション中に外部キーチェックをバイパスします。アクティブ/アクティブ設定では、これが外部キー違反につながる可能性があります。ほとんどの違反は一時的なものであり、レプリケーションが追いつくと解決されます。ただし、pgactive はクロスノードの行ロックをサポートしていないため、外部キーのダングリングが発生する可能性があります。

この動作は、分断耐性のある非同期アクティブ/アクティブシステムに固有のものです。例えば、ノード A が新しい子行を挿入すると同時に、ノード B がその親行を削除する場合があります。システムは、ノード間でのこのタイプの同時変更を防ぐことはできません。

外部キーの競合を最小限に抑えるには、以下のことをお勧めします。
+ 外部キー関係を密接に関連するエンティティに制限します。
+ 可能な場合は、単一のノードから関連エンティティを変更します。
+ ほとんど変更を必要としないエンティティを選択します。
+ 変更に対してアプリケーションレベルの同時実行制御を実装します。

### 排他制約の競合
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict11"></a>

 pgactivelink は排他制約をサポートしておらず、作成を制限します。

**注記**  
既存のスタンドアロンデータベースを pgactivelink データベースに変換する場合は、すべての排他制約を手動で削除します。

分散非同期システムでは、制約に違反する行のセットが存在しないことは保証できません。これは、異なるノード上のすべてのトランザクションが完全に分離されているためです。排他制約は、排他制約違反のためにどのノードからも別のノードに再実行できなくなる、再実行デッドロックにつながる可能性があります。

pgactivelink に排他制約の作成を強制した場合、またはスタンドアロンデータベースを pgactivelink に変換するときに既存の排他制約を削除しない場合、レプリケーションが中断する可能性があります。レプリケーションの進行状況を回復するには、受信リモートタプルと競合するローカルタプルを削除または変更し、リモートトランザクションを適用できるようにします。

### グローバルデータの競合
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict12"></a>

pgactivelink を使用する場合、ノード間でロールなどの PostgreSQL システム全体のグローバルデータが異なると、競合が発生する可能性があります。これらの競合により、オペレーション (主に DDL) が 1 つのノードで成功してコミットされるものの、他のノードには適用されない可能性があります。

ユーザーが 1 つのノードに存在するものの、別のノードには存在しない場合、レプリケーションの問題が発生する可能性があります。
+ Node1 には `fred` という名前のユーザーがいますが、このユーザーは Node2 には存在しません。
+ `fred` が Node1 にテーブルを作成すると、テーブルは `fred` を所有者としてレプリケートされます。
+ この DDL コマンドを Node2 に適用すると、ユーザー `fred` が存在しないため、失敗します。
+ この失敗により、Node2 の PostgreSQL ログに ERROR が生成され、`pgactive.pgactive_stats.nr_rollbacks` カウンターが増分されます。

**解決策:** Node2 でユーザー `fred` を作成します。ユーザーが同じアクセス許可を持つ必要はありませんが、両方のノードに存在する必要があります。

1 つのノードにテーブルが存在するものの、別のノードには存在しない場合、データ変更オペレーションは失敗します。
+ Node1 には、Node2 に存在しない `foo` という名前のテーブルがあります。
+ Node1 の `foo` テーブルに対する DML オペレーションは、Node2 にレプリケートされると失敗します。

**解決策:** 同じ構造で Node2 にテーブル `foo` を作成します。

**注記**  
pgactivelink は現在、CREATE USER コマンドまたは DDL オペレーションをレプリケートしません。DDL レプリケーションは将来のリリースが予定されています。

### ロックの競合とデッドロックの中止
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict13"></a>

pgactive 適用プロセスは通常のユーザーセッションのように動作するため、標準的な行とテーブルのロックルールに従います。そのため、pgactivelink 適用プロセスは、ユーザートランザクションまたは他の適用プロセスによって保持されているロックを待機する可能性があります。

以下のタイプのロックは適用プロセスに影響を与える可能性があります。
+ ユーザーセッションによる明示的なテーブルレベルのロック (LOCK TABLE...)
+ ユーザーセッションによる明示的な行レベルのロック (SELECT ... FOR UPDATE/FOR SHARE)
+ 外部キーからのロック
+ ローカルアクティビティまたは他のサーバーからの行の UPDATE、INSERT、または DELETE による暗黙的なロック

デッドロックは、次の間で発生する可能性があります。
+ pgactivelink 適用プロセスとユーザートランザクション
+ 2 つの適用プロセス

デッドロックが発生すると、PostgreSQL のデッドロック検出機能は問題のトランザクションのうち 1 つを終了します。pgactivelink 適用ワーカーのプロセスが終了すると、自動的に再試行され、通常は成功します。

**注記**  
これらの問題は一時的なものであり、通常は管理者の介入は必要ありません。適用プロセスがアイドル状態のユーザーセッションのロックによって長期間ブロックされている場合は、ユーザーセッションを終了してレプリケーションを再開できます。この状況は、ユーザーが別のユーザーセッションに影響を与える長期間にわたるロックを保持する場合に似ています。
ロック関連の再生遅延を特定するには、PostgreSQL で `log_lock_waits` 機能を有効にします。

### 相違による競合
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict14"></a>

ノード間で同一であるはずのデータが予期せず異なる場合、相違による競合が発生します。これらの競合は発生すべきではないものの、現在の実装ではすべてを確実に防止できるわけではありません。

**注記**  
 行の PRIMARY KEY を変更すると、すべてのノードが変更を処理する前に別のノードが同じ行のキーを変更した場合、相違による競合が発生する可能性があります。プライマリキーの変更を避けるか、変更を指定された 1 つのノードに制限してください。詳細については、「[PRIMARY KEY の UPDATE 競合](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflict5)」を参照してください。

行データが関係した相違による競合には通常、管理者の介入が必要です。これらの競合を解決するには、`pgactive.pgactive_do_not_replicate` を使用してレプリケーションを一時的に無効にし、一方のノードのデータをもう一方のノードに合わせて手動で調整する必要があります。これらの競合は、pgactive を記載通りに使用し、安全でないとマークされた設定や関数を回避すれば、発生しません。

 管理者は、これらの競合を手動で解決する必要があります。競合タイプによっては、`pgactive.pgactive_do_not_replicate` などの高度なオプションを使用する必要があります。不適切に使用すると状況が悪化する可能性があるため、これらのオプションは慎重に使用してください。競合にはさまざまな可能性が考えられるため、普遍的な解決の手順を提供することはできません。

異なるノード間で同一であるはずのデータが予期せず異なる場合、相違による競合が発生します。これらの競合は発生すべきではないものの、現在の実装ではこのような競合をすべて確実に防止できるわけではありません。

## 競合の回避または許容
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.avoidconflicts"></a>

 ほとんどの場合、適切なアプリケーション設計を使用することで、競合を回避したり、アプリケーションが競合を許容するようにしたりできます。

 競合は、複数のノードで同時操作が行われた場合にのみ発生します。競合を回避するには、以下を行います。
+ 1 つのノードにのみ書き込む
+ 各ノードの独立したデータベースサブセットに書き込む (各ノードに個別のスキーマを割り当てるなど)

INSERT と INSERT の競合の場合は、グローバルシーケンスを使用して競合を完全に防止します。

 競合が許容できないユースケースの場合は、アプリケーションレベルで分散ロックを実装することを検討してください。多くの場合、最善の方法は、すべての競合を防ぐのではなく、pgactive の競合解決メカニズムと連携するようにアプリケーションを設計することです。詳細については、「[競合のタイプ](#Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflicttypes)」を参照してください。

## 競合のログ記録
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.actact.conflictlogging"></a>

pgactivelink は、競合インシデントを `pgactive.pgactive_conflict_history` テーブルに記録し、アクティブ/アクティブ競合の診断と処理に役立つようにします。このテーブルへの競合ログは、`pgactive.log_conflicts_to_table` を true に設定した場合にのみ記録されます。pgactive 拡張機能は、log\$1min\$1messages が `LOG` または `lower` に設定されている場合に、`pgactive.log_conflicts_to_table` 設定に関係なく、競合を PostgreSQL ログファイルにも記録します。

 競合履歴テーブルは、以下の目的で使用します。
+ アプリケーションに競合が起きる頻度を測定する
+ 競合が発生する場所を特定する
+ アプリケーションを改善し、競合率を低減する
+ 競合の解決策により望ましい結果が得られないケースを検出する
+ ユーザー定義の競合トリガーまたはアプリケーション設計の変更が必要な場所を特定する

 行が競合した場合、オプションで行の値をログに記録できます。これは `pgactive.log_conflicts_to_table` 設定によって制御されます。以下の点に注意してください。
+ これはデータベース全体のグローバルオプションです。
+ 行値のログ記録をテーブル別に制御することはできません。
+ フィールド番号、配列要素、またはフィールド長に制限はありません。
+ 競合を引き起こす可能性のある数メガバイトの行を使用する場合は、この機能を有効にすることはお勧めできません。

 競合履歴テーブルには、データベース内のすべてのテーブルのデータ (それぞれ異なるスキーマを持つ可能性がある) が含まれているため、ログに記録された行値は JSON フィールドとして保存されます。JSON は、SQL から直接呼び出す場合と同様に、`row_to_json` を使用して作成されます。PostgreSQL では `json_to_row` 関数が提供されていないため、ログに記録された JSON から複合型のタプルを再構築するには、テーブル固有のコード (PL/pgSQL、PL/Python、PL/Perl など) が必要です。

**注記**  
ユーザー定義の競合のサポートは、今後の拡張機能として計画されています。

# pgactive スキーマについて
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.schema"></a>

pgactive スキーマは、RDS for PostgreSQL のアクティブ/アクティブレプリケーションを管理します。このスキーマには、レプリケーション設定とステータス情報を保存するテーブルが含まれています。

**注記**  
pgactive スキーマは進化しており、変更される可能性があります。これらのテーブルのデータを直接変更しないでください。

pgactive スキーマのキーテーブルには以下のものが含まれます。
+ `pgactive_nodes` − アクティブ/アクティブレプリケーショングループ内のノードに関する情報を保存します。
+ `pgactive_connections` − 各ノードの接続の詳細を保存します。

## pgactive\$1nodes
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.schema.nodes"></a>

pgactive\$1nodes は、アクティブ/アクティブレプリケーショングループに参加しているノードに関する情報を保存します。


| 列 | タイプ | 照合 | Nullable | デフォルト | 
| --- | --- | --- | --- | --- | 
| node\$1sysid | text | – | NOT NULL | – | 
| node\$1timeline | oid | – | NOT NULL | – | 
| node\$1dboid | oid | – | NOT NULL | – | 
| node\$1status | char | – | NOT NULL | – | 
| node\$1name | text | – | NOT NULL | – | 
| node\$1dsn | text | – | NOT NULL | – | 
| node\$1init\$1from\$1dsn | text | – | NOT NULL | – | 
| node\$1read\$1only | ブール値 | – | – | false | 
| node\$1seq\$1id | smallint | – | NOT NULL | – | 

**node\$1sysid**  
ノードの一意の ID。`pgactive_create_group` または `pgactive_join_group` 中に生成されます。

**node\$1status**  
ノードの準備状況:  
+ **b** - セットアップの開始
+ **i** - 初期化
+ **c** - キャッチアップ
+ **o** - アウトバウンドスロットの作成
+ **r** - 準備完了
+ **k** - 強制終了
この列は、ノードが接続されているか切断されているかを示しません。

**node\$1name**  
ユーザーが指定した一意のノード名。

**node\$1dsn**  
接続文字列またはユーザーマッピング名

**node\$1init\$1from\$1dsn**  
このノードが作成された DSN。

## pgactive\$1connection
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.schema.connection"></a>

pgactive\$1connections は、各ノードの接続の詳細を保存します。


| 列 | タイプ | 照合 | Nullable | デフォルト | 
| --- | --- | --- | --- | --- | 
| conn\$1sysid | text | なし | NOT NULL | なし | 
| conn\$1timeline | oid | なし | NOT NULL | なし | 
| conn\$1dboid | oid | なし | NOT NULL | なし | 
| conn\$1dsn | text | なし | NOT NULL | なし | 
| conn\$1apply\$1delay | integer | なし | なし | なし | 
| conn\$1replication\$1sets | text | なし | なし | なし | 

conn\$1sysid  
このエントリが参照するノードのノード識別子。

conn\$1dsn  
pgactive.pgactive\$1nodes `node_dsn` と同じです。

conn\$1apply\$1delay  
設定されている場合、リモートノードから各トランザクションを適用するまで待機するミリ秒数。主にデバッグ用。null の場合、グローバルデフォルトが適用されます。

## レプリケーションセットの使用
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.replication"></a>

レプリケーションセットは、レプリケーションオペレーションに含めるテーブルと除外するテーブルを決定します。デフォルトでは、次の関数を使用して指定しない限り、すべてのテーブルがレプリケートされます。
+ `pgactive_exclude_table_replication_set()` - 指定されたテーブルをレプリケーションから除外する
+ `pgactive_include_table_replication_set()` - 指定されたテーブルをレプリケーションに含める

**注記**  
レプリケーションセットを設定する前に、次の点を考慮してください。  
テーブルの包含または除外は、`pgactive_create_group()` の実行後、`pgactive_join_group()` を実行するより前にのみ設定できます。
`pgactive_exclude_table_replication_set()` を使用した後、`pgactive_include_table_replication_set()` を使用することはできません。
`pgactive_exclude_table_replication_set()` を使用した後、`pgactive_include_table_replication_set()` を使用することはできません。

システムは、初期設定に基づいて新しく作成されたテーブルを異なる方法で処理します。
+ テーブルを除外した場合: `pgactive_join_group()` 以降に作成された新しいテーブルは、自動的にレプリケーションに含まれます。
+ テーブルを含めた場合: `pgactive_join_group()` 以降に作成された新しいテーブルは、自動的にレプリケーションから除外されます。

特定のテーブルのレプリケーションセット設定を表示するには、`pgactive.pgactive_get_table_replication_sets()` 関数を使用します。

# pgactive 関数リファレンス
<a name="pgactive-functions-reference"></a>

以下に、pgactive 関数のリストとそのパラメータ、戻り値、実用的な使用上の注意事項を示します。

## get\$1last\$1applied\$1xact\$1info
<a name="get-last-applied-xact-info"></a>

指定されたノードに最後に適用されたトランザクション情報を取得します。

**引数**  
+ sysid (テキスト) - タイムライン OID
+ dboid (OID)

**戻り型**  
以下を記録します。  
+ last\$1applied\$1xact\$1id (OID)
+ last\$1applied\$1xact\$1committs (タイムゾーン付きのタイムスタンプ)
+ last\$1applied\$1xact\$1at (タイムゾーン付きのタイムスタンプ)

**使用に関する注意事項**  
この関数を使用して、指定されたノードに最後に適用されたトランザクション情報を取得します。

## pgactive\$1apply\$1pause
<a name="pgactive-apply-pause"></a>

レプリケーション適用プロセスを一時停止します。

**引数**  
なし

**戻り型**  
boolean

**使用に関する注意事項**  
この関数を呼び出して、レプリケーション適用プロセスを一時停止します。

## pgactive\$1apply\$1resume
<a name="pgactive-apply-resume"></a>

レプリケーション適用プロセスを再開します。

**引数**  
なし

**戻り型**  
void

**使用に関する注意事項**  
この関数を呼び出して、レプリケーション適用プロセスを再開します。

## pgactive\$1is\$1apply\$1paused
<a name="pgactive-is-apply-paused"></a>

レプリケーション適用が現在一時停止されているかどうかを確認します。

**引数**  
なし

**戻り型**  
boolean

**使用に関する注意事項**  
この関数を使用して、レプリケーション適用が現在一時停止されているかどうかを確認します。

## pgactive\$1create\$1group
<a name="pgactive-create-group"></a>

スタンドアロンデータベースを初期ノードに変換して pgactive グループを作成します。



**引数**  
+ node\$1name (テキスト)
+ node\$1dsn (テキスト)
+ apply\$1delay integer DEFAULT NULL::integer - replication\$1sets text[] DEFAULT ARRAY[‘default’::text]

**戻り型**  
void

**使用に関する注意事項**  
スタンドアロンデータベースを初期ノードに変換して pgactive グループを作成します。この関数は、ノードを pgactive ノードに変換する前に、サニティチェックを実行します。この関数を使用する前に、PostgreSQL クラスターに pgactive バックグラウンドワーカーをサポートするのに十分な `max_worker_processes` が使用可能であることを確認してください。

## pgactive\$1detach\$1nodes
<a name="pgactive-detach-nodes"></a>

pgactive グループから指定されたノードを削除します。

**引数**  
+ p\$1nodes (text[])

**戻り型**  
void

**使用に関する注意事項**  
この関数を使用して、pgactive グループから指定されたノードを削除します。

## pgactive\$1exclude\$1table\$1replication\$1set
<a name="pgactive-exclude-table-replication-set"></a>

レプリケーションから特定のテーブルを除外します。

**引数**  
+ p\$1relation (regclass)

**戻り型**  
void

**使用に関する注意事項**  
この関数を使用して、レプリケーションから特定のテーブルを除外します。

## pgactive\$1get\$1replication\$1lag\$1info
<a name="pgactive-get-replication-lag-info"></a>

ノードの詳細、WAL ステータス、LSN 値など、詳細なレプリケーションラグ情報を取得します。

**引数**  
なし

**戻り型**  
SETOF record - node\$1name text - node\$1sysid text - application\$1name text - slot\$1name text - active boolean - active\$1pid integer - pending\$1wal\$1decoding bigint - Approximate size of WAL in bytes to be decoded on the sender node - pending\$1wal\$1to\$1apply bigint - Approximate size of WAL in bytes to be applied on receiving node - restart\$1lsn pg\$1lsn - confirmed\$1flush\$1lsn pg\$1lsn - sent\$1lsn pg\$1lsn - write\$1lsn pg\$1lsn - flush\$1lsn pg\$1lsn - replay\$1lsn pg\$1lsn

**使用に関する注意事項**  
この関数を呼び出して、ノードの詳細、WAL ステータス、LSN 値などのレプリケーションラグ情報を取得します。

## pgactive\$1get\$1stats
<a name="pgactive-get-stats"></a>

pgactive レプリケーションの統計を取得します。

**引数**  
なし

**戻り型**  
SETOF record - rep\$1node\$1id oid - rilocalid oid - riremoteid text - nr\$1commit bigint - nr\$1rollback bigint - nr\$1insert bigint - nr\$1insert\$1conflict bigint - nr\$1update bigint - nr\$1update\$1conflict bigint - nr\$1delete bigint - nr\$1delete\$1conflict bigint - nr\$1disconnect bigint

**使用に関する注意事項**  
この関数を使用して、pgactive レプリケーションの統計を取得します。

## pgactive\$1get\$1table\$1replication\$1sets
<a name="pgactive-get-table-replication-sets"></a>

特定のリレーションのレプリケーションセット設定を取得します。

**引数**  
+ リレーション (regclass)

**戻り型**  
SETOF レコード

**使用に関する注意事項**  
この関数を呼び出して、特定のリレーションのレプリケーションセット設定を取得します。

## pgactive\$1include\$1table\$1replication\$1set
<a name="pgactive-include-table-replication-set"></a>

レプリケーションに特定のテーブルを含めます。

**引数**  
+ p\$1relation (regclass)

**戻り型**  
void

**使用に関する注意事項**  
この関数を使用して、レプリケーションに特定のテーブルを含めます。

## pgactive\$1join\$1group
<a name="pgactive-join-group"></a>

既存の pgactive グループにノードを追加します。

**引数**  
+ node\$1name (テキスト)
+ node\$1dsn (テキスト)
+ join\$1using\$1dsn (テキスト)
+ apply\$1delay (整数、オプション)
+ replication\$1sets (text[]、デフォルト: ['default'])
+ bypass\$1collation\$1check (ブール値、デフォルト: false)
+ bypass\$1node\$1identifier\$1creation (ブール値、デフォルト: false)
+ bypass\$1user\$1tables\$1check (ブール値、デフォルト: false)

**戻り型**  
void

**使用に関する注意事項**  
この関数を呼び出して、既存の pgactive グループにノードを追加します。PostgreSQL クラスターに pgactive バックグラウンドワーカー用の十分な max\$1worker\$1processes があることを確認します。

## pgactive\$1remove
<a name="pgactive-remove"></a>

ローカルノードからすべての pgactive コンポーネントを削除します。

**引数**  
+ force (ブール値、デフォルト: false)

**戻り型**  
void

**使用に関する注意事項**  
この関数を呼び出して、ローカルノードからすべての pgactive コンポーネントを削除します。

## pgactive\$1snowflake\$1id\$1nextval
<a name="pgactive-snowflake-id-nextval"></a>

ノード固有の一意のシーケンス値を生成します。

**引数**  
+ regclass

**戻り型**  
bigint

**使用に関する注意事項**  
この関数を使用して、ノード固有の一意のシーケンス値を生成します。

## pgactive\$1update\$1node\$1conninfo
<a name="pgactive-update-node-conninfo"></a>

pgactive ノードの接続情報を更新します。

**引数**  
+ node\$1name\$1to\$1update (テキスト)
+ node\$1dsn\$1to\$1update (テキスト)

**戻り型**  
void

**使用に関する注意事項**  
この関数を使用して、pgactive ノードの接続情報を更新します。

## pgactive\$1wait\$1for\$1node\$1ready
<a name="pgactive-wait-for-node-ready"></a>

グループの作成または参加オペレーションの進行状況をモニタリングします。

**引数**  
+ タイムアウト (整数、デフォルト: 0)
+ progress\$1interval (整数、デフォルト: 60)

**戻り型**  
void

**使用に関する注意事項**  
この関数を呼び出して、グループの作成または参加オペレーションの進行状況をモニタリングします。

# アクティブ/アクティブレプリケーションの競合の処理
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.handle-conflicts"></a>

`pgactive` 拡張は、クラスターごとではなく、データベースごとに機能します。`pgactive` を使用する各 DB インスタンスは、独立したインスタンスであり、あらゆるソースからのデータ変更を受け入れることができます。変更が DB インスタンスに送信されると、PostgreSQL は変更をローカルにコミットし、`pgactive` を使用して他の DB インスタンスに非同期に変更をレプリケートします。2 つの PostgreSQL DB インスタンスが同じレコードをほぼ同時に更新すると、競合が発生する可能性があります。

`pgactive` 拡張は、競合の検出と自動解決のためのメカニズムを提供します。両方の DB インスタンスでトランザクションがコミットされた時点のタイムスタンプを追跡し、最新のタイムスタンプで変更を自動的に適用します。また、`pgactive` 拡張は、`pgactive.pgactive_conflict_history` テーブルで競合が発生した場合もログに記録します。

`pgactive.pgactive_conflict_history` は継続的に増大します。パージポリシーを定義するとよいでしょう。これを行うには、一部のレコードを定期的に削除するか、この関係のパーティションスキームを定義します (その後で対象のパーティションをデタッチ、ドロップ、切り捨てることができます)。パージポリシーを定期的に実装するには、 `pg_cron` 拡張機能を使用するというオプションがあります。`pg_cron` 履歴テーブルの例については、「[PostgreSQL pg\$1cron 拡張機能を使用したメンテナンスのスケジュール](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/PostgreSQL_pg_cron.html)」の次の情報を参照してください。

# アクティブ/アクティブレプリケーションでのシーケンスの処理
<a name="Appendix.PostgreSQL.CommonDBATasks.pgactive.handle-sequences"></a>

`pgactive` 拡張を使用した RDS for PostgreSQL DB インスタンスは、2 つの異なるシーケンスメカニズムを使用して固有の値を生成します。

**グローバルシーケンス**  
グローバルシーケンスを使用するには、`CREATE SEQUENCE` ステートメントを使用してローカルシーケンスを作成します。`usingnextval(seqname)` の代わりに `pgactive.pgactive_snowflake_id_nextval(seqname)` を使用すると、シーケンスの次の固有な値を取得できます。

次の例では、グローバルシーケンスを作成します。

```
app=> CREATE TABLE gstest (
      id bigint primary key,
      parrot text
    );
```

```
app=>CREATE SEQUENCE gstest_id_seq OWNED BY gstest.id;
```

```
app=> ALTER TABLE gstest \
      ALTER COLUMN id SET DEFAULT \
      pgactive.pgactive_snowflake_id_nextval('gstest_id_seq');
```

**分割シーケンス**  
分割ステップまたは分割シーケンスでは、通常の PostgreSQL シーケンスをノードごとに使用します。各シーケンスは同じ量ずつインクリメントされ、異なるオフセットから始まります。例えば、ステップ 100 の場合、ノード 1 は 101、201、301 などとしてシーケンスを生成し、ノード 2 は 102、202、302 などとしてシーケンスを生成します。このスキームは、ノードが長時間通信できない場合でも適切に機能しますが、設計者はスキーマを確立するときに最大ノード数を指定する必要があり、ノードごとの設定が必要になります。間違えると、シーケンスが重複しやすくなります。

次に示すように、ノードで目的のシーケンスを作成することで、このアプローチを `pgactive` で比較的簡単に設定できます。

```
CREATE TABLE some_table (generated_value bigint primary key);
```

```
app=> CREATE SEQUENCE some_seq INCREMENT 100 OWNED BY some_table.generated_value;
```

```
app=> ALTER TABLE some_table ALTER COLUMN generated_value SET DEFAULT nextval('some_seq');
```

次に、各ノードで `setval` を呼び出して、次のように異なるオフセットの開始値を指定します。

```
app=>
-- On node 1
SELECT setval('some_seq', 1);

-- On node 2
SELECT setval('some_seq', 2);
```