Citusサポート
Patroniを使用すると、マルチノードCitus クラスターを非常に簡単に構築できます。
要点
必要なのは、次の簡単なルールに従うことだけです。
- PostgreSQLのデータベース拡張Citus を、すべてのノードで使用できるようにしてください。サポートされる最低バージョンはCitus 10.0ですが、ワーカーの透過的なスイッチオーバーと再起動の利点をすべて活用するには、Citus 11.2以降を推奨します。
- クラスター名(
scope)は、すべてのCitusノードで同じにする必要があります。 - コーディネーターとすべてのワーカーノードで同じスーパーユーザーの認証情報を使用し、
pg_hba.confで全ノード間のスーパーユーザーアクセスを許可してください。 - ワーカーノードからコーディネーターへのREST API アクセスを許可する必要があります。たとえば認証情報は同じにし、クライアント証明書を設定している場合は、コーディネーターがワーカーノードの証明書を受け入れる必要があります。
patroni.yamlに次のセクションを追加します。
後はPatroniを起動するだけで、残りの処理を実行します。
bootstrap.dcs.synchronous_modeを明示的に別の値に設定していなければ、Patroniはquorum に設定します。- citus
拡張を
shared_preload_librariesに自動的に追加します。 - グローバルな動的設定
で
max_prepared_transactionsを明示的に設定していなければ、Patroniは2*max_connectionsに設定します。 citus.local_hostnameのGUC値を、localhostからPatroniがローカルのPostgreSQLインスタンスへの接続に使用する値へ変更します。PostgreSQLがlocalhostでリッスンしていない場合があるため、別の値が必要になることがあります。citus.databaseを自動的に作成し、続いてCREATE EXTENSION citusを実行します。- ノード間の通信を可能にするため、現在のスーパーユーザーの認証情報
を
pg_dist_authinfoテーブルに追加します。後からスーパーユーザーのusername/password/sslcert/sslkeyを変更する場合は、この情報の更新も忘れないでください。 - コーディネーターのプライマリーノードは、ワーカーのプライマリーノードを自動検出し、
citus_add_node()関数でpg_dist_nodeテーブルに追加します。 - コーディネーターまたはワーカーのクラスターでフェイルオーバーやスイッチオーバーが発生した場合も、Patroniが
pg_dist_nodeを維持します。
patronictl
コーディネーターとワーカーのクラスターは、物理的には異なるPostgreSQL/Patroniクラスターです。PostgreSQLのデータベース拡張Citus で論理的にまとめているだけなので、多くの場合は単一の実体として管理できません。
このため、patroni.yamlにcitus
セクションがある場合、patronictl
の動作には通常と比べて2つの主な違いがあります。
listとtopologyは、デフォルトでCitus構成全体のメンバー(コーディネーターとワーカー)を出力します。新しいGroup列に、所属するCitusグループが表示されます。- すべてのpatronictl
コマンドに、新しい
--groupオプションが追加されます。一部のコマンドでは、グループのデフォルト値をpatroni.yamlから取得する場合があります。たとえばpatronictl_pause は、デフォルトでcitus セクションのgroupに対してメンテナンスモードを有効にします。一方、patronictl_switchover やpatronictl_remove などでは、グループを明示的に指定する必要があります。
Citusクラスターでのpatronictl_list の出力例:
postgres@coord1:~$ patronictl list demo
+ Citus cluster: demo ----------+----------------+---------+----+-------------+-----+------------+-----+
| Group | Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+-------+---------+-------------+----------------+---------+----+-------------+-----+------------+-----+
| 0 | coord1 | 172.27.0.10 | Replica | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| 0 | coord2 | 172.27.0.6 | Quorum Standby | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| 0 | coord3 | 172.27.0.4 | Leader | running | 1 | | | | |
| 1 | work1-1 | 172.27.0.8 | Quorum Standby | running | 1 | 0/31D3198 | 0 | 0/31D3198 | 0 |
| 1 | work1-2 | 172.27.0.2 | Leader | running | 1 | | | | |
| 2 | work2-1 | 172.27.0.5 | Quorum Standby | running | 1 | 0/31CDFC0 | 0 | 0/31CDFC0 | 0 |
| 2 | work2-2 | 172.27.0.7 | Leader | running | 1 | | | | |
+-------+---------+-------------+----------------+---------+----+-------------+-----+------------+-----+
--groupオプションを追加すると、出力は次のように変わります。
postgres@coord1:~$ patronictl list demo --group 0
+ Citus cluster: demo (group: 0, 7179854923829112860) -+-------------+-----+------------+-----+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+--------+-------------+----------------+---------+----+-------------+-----+------------+-----+
| coord1 | 172.27.0.10 | Replica | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| coord2 | 172.27.0.6 | Quorum Standby | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| coord3 | 172.27.0.4 | Leader | running | 1 | | | | |
+--------+-------------+----------------+---------+----+-------------+-----+------------+-----+
postgres@coord1:~$ patronictl list demo --group 1
+ Citus cluster: demo (group: 1, 7179854923881963547) -+-------------+-----+------------+-----+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+---------+------------+----------------+---------+----+-------------+-----+------------+-----+
| work1-1 | 172.27.0.8 | Quorum Standby | running | 1 | 0/31D3198 | 0 | 0/31D3198 | 0 |
| work1-2 | 172.27.0.2 | Leader | running | 1 | | | | |
+---------+------------+----------------+---------+----+-------------+-----+------------+-----+
Citusワーカーのスイッチオーバー
Citusワーカーノードのスイッチオーバーを調整して実行する場合、Citusでは、アプリケーションからほぼ透過的に切り替えることができます。アプリケーションはコーディネーターに接続し、そこからワーカーノードへ接続するため、ワーカーノード上のシャードに対するSQLトラフィックを、Citusでコーディネーター上に一時停止 できます。そのトラフィックをコーディネーターに保持している間にスイッチオーバーを行い、新しいプライマリーのワーカーノードが読み書きのクエリーを受け付ける準備を終え次第、トラフィックを再開します。
ワーカークラスターでのpatronictl_switchover の例:
postgres@coord1:~$ patronictl switchover demo
+ Citus cluster: demo ----------+----------------+---------+----+-------------+-----+------------+-----+
| Group | Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+-------+---------+-------------+----------------+---------+----+-------------+-----+------------+-----+
| 0 | coord1 | 172.27.0.10 | Replica | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| 0 | coord2 | 172.27.0.6 | Quorum Standby | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| 0 | coord3 | 172.27.0.4 | Leader | running | 1 | | | | |
| 1 | work1-1 | 172.27.0.8 | Leader | running | 1 | | | | |
| 1 | work1-2 | 172.27.0.2 | Quorum Standby | running | 1 | 0/31D3198 | 0 | 0/31D3198 | 0 |
| 2 | work2-1 | 172.27.0.5 | Quorum Standby | running | 1 | 0/31CDFC0 | 0 | 0/31CDFC0 | 0 |
| 2 | work2-2 | 172.27.0.7 | Leader | running | 1 | | | | |
+-------+---------+-------------+----------------+---------+----+-------------+-----+------------+-----+
Citus group: 2
Primary [work2-2]:
Candidate ['work2-1'] []:
When should the switchover take place (e.g. 2024-08-26T08:02 ) [now]:
Current cluster topology
+ Citus cluster: demo (group: 2, 7179854924063375386) -+-------------+-----+------------+-----+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+---------+------------+----------------+---------+----+-------------+-----+------------+-----+
| work2-1 | 172.27.0.5 | Quorum Standby | running | 1 | 0/31CDFC0 | 0 | 0/31CDFC0 | 0 |
| work2-2 | 172.27.0.7 | Leader | running | 1 | | | | |
+---------+------------+----------------+---------+----+-------------+-----+------------+-----+
Are you sure you want to switchover cluster demo, demoting current primary work2-2? [y/N]: y
2024-08-26 07:02:40.33003 Successfully switched over to "work2-1"
+ Citus cluster: demo (group: 2, 7179854924063375386) --------+---------+------------+---------+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+---------+------------+---------+---------+----+-------------+---------+------------+---------+
| work2-1 | 172.27.0.5 | Leader | running | 1 | | | | |
| work2-2 | 172.27.0.7 | Replica | stopped | | unknown | unknown | unknown | unknown |
+---------+------------+---------+---------+----+-------------+---------+------------+---------+
postgres@coord1:~$ patronictl list demo
+ Citus cluster: demo ----------+----------------+---------+----+-------------+-----+------------+-----+
| Group | Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+-------+---------+-------------+----------------+---------+----+-------------+-----+------------+-----+
| 0 | coord1 | 172.27.0.10 | Replica | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| 0 | coord2 | 172.27.0.6 | Quorum Standby | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| 0 | coord3 | 172.27.0.4 | Leader | running | 1 | | | | |
| 1 | work1-1 | 172.27.0.8 | Leader | running | 1 | | | | |
| 1 | work1-2 | 172.27.0.2 | Quorum Standby | running | 1 | 0/31D3198 | 0 | 0/31D3198 | 0 |
| 2 | work2-1 | 172.27.0.5 | Leader | running | 2 | | | | |
| 2 | work2-2 | 172.27.0.7 | Quorum Standby | running | 2 | 0/31CDFC0 | 0 | 0/31CDFC0 | 0 |
+-------+---------+-------------+----------------+---------+----+-------------+-----+------------+-----+
コーディネーター側では、次のようになります。
# The worker primary notifies the coordinator that it is going to execute "pg_ctl stop".
2024-08-26 07:02:38,636 DEBUG: query(BEGIN, ())
2024-08-26 07:02:38,636 DEBUG: query(SELECT pg_catalog.citus_update_node(%s, %s, %s, true, %s), (3, '172.19.0.7-demoted', 5432, 10000))
# From this moment all application traffic on the coordinator to the worker group 2 is paused.
# The old worker primary is assigned as a secondary.
2024-08-26 07:02:40,084 DEBUG: query(SELECT pg_catalog.citus_update_node(%s, %s, %s, true, %s), (7, '172.19.0.7', 5432, 10000))
# The future worker primary notifies the coordinator that it acquired the leader lock in DCS and about to run "pg_ctl promote".
2024-08-26 07:02:40,085 DEBUG: query(SELECT pg_catalog.citus_update_node(%s, %s, %s, true, %s), (3, '172.19.0.5', 5432, 10000))
# The new worker primary just finished promote and notifies coordinator that it is ready to accept read-write traffic.
2024-08-26 07:02:41,485 DEBUG: query(COMMIT, ())
# From this moment the application traffic on the coordinator to the worker group 2 is unblocked.
セカンダリーノード
Patroni v4.0.0以降では、noloadbalanceタグ
が付いていないCitusセカンダリーノードもpg_dist_nodeに登録されます。ただし、アプリケーションが読み取り専用クエリーにセカンダリーノードを使用するには、citus.use_secondary_nodes
のGUCを変更する必要があります。
DCSの内部構造
Citusクラスター(コーディネーターとワーカー)は、論理的にまとめたPatroniクラスター群としてDCSに保存されます。
/service/batman/ # scope=batman
/service/batman/0/ # citus.group=0, coordinator
/service/batman/0/initialize
/service/batman/0/leader
/service/batman/0/members/
/service/batman/0/members/m1
/service/batman/0/members/m2
/service/batman/1/ # citus.group=1, worker
/service/batman/1/initialize
/service/batman/1/leader
/service/batman/1/members/
/service/batman/1/members/m3
/service/batman/1/members/m4
...
この方式を採用したのは、ほとんどのDCSで、1回の再帰的な読み取り要求によりCitusクラスター全体を取得できるためです。ツリー全体を読み取るのは、ワーカーノードを検出する必要があるCitusコーディネーターノードだけです。ワーカーノードは、自身のグループのサブツリーだけを読み取り、場合によってはコーディネーターグループのサブツリーも読み取ります。
Kubernetes上のCitus
Kubernetesは階層構造をサポートしないため、Patroniが作成するすべてのK8sオブジェクトにcitusグループを含める必要がありました。
batman-0-leader # the leader config map for the coordinator
batman-0-config # the config map holding initialize, config, and history "keys"
...
batman-1-leader # the leader config map for worker group 1
batman-1-config
...
つまり、命名パターンは${scope}-${citus.group}-${type}です。
Patroniはラベルセレクター
を使用してすべてのKubernetesオブジェクトを検出します。そのため、PatroniとCitusを実行するすべてのPodとEndpoints/ConfigMapsには同様のラベルを付け、Patroniがそれらを使用するようにKubernetesの設定
またはenvironment variables <kubernetes_environment>で指定する必要があります。
Podの環境変数を使用したPatroni設定の例を2つ示します。
- コーディネータークラスターの場合
- グループ2のワーカークラスターの場合
どちらの例でも、citus-groupラベルが設定されています。このラベルにより、PatroniはオブジェクトがどのCitusグループに属するかを識別します。また、citus-groupラベルと同じ値を持つPATRONI_CITUS_GROUP環境変数もあります。Patroniが新しいKubernetesのConfigMapsやEndpointsを作成すると、自動的にcitus-group: ${env.PATRONI_CITUS_GROUP}ラベルを付けます。
Citusに対応したPatroniをKubernetesにデプロイする完全な例は、Patroniリポジトリのkubernetes フォルダーにあります。
重要なファイルは次の2つです。
- Dockerfile.citus
- citus_k8s.yaml
CitusのアップグレードとPostgreSQLのメジャーアップグレード
まず、ドキュメント
でCitusのバージョンアップグレードについて確認してください。手順に小さな違いが1つあります。アップグレード時にPostgreSQLを再起動するには、systemctl restartの代わりにpatronictl_restart
を使用する必要があります。
Citusを使用したPostgreSQLのメジャーアップグレードは、もう少し複雑です。Citusのメジャーアップグレードのドキュメントと、PatroniのPostgreSQL major upgrade<major_upgrade>のドキュメントにある手法を組み合わせる必要があります。Citusクラスターは多数のPatroniクラスター(コーディネーターとワーカー)で構成されており、それぞれを個別にアップグレードする必要がある点に注意してください。