0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PostgreSQL + repmgr fencing処理の実装

Last updated at Posted at 2024-09-24

はじめに

PostgreSQLのHA管理ツールであるrepmgrでfencing処理を実装する方法について紹介します。

SplitBrainとfencingの必要性

repmgrでHA構成を組む場合に、SplitBrainが発生するリスクを検討して、対処しておく必要があります。

SplitBrainとは、Primary(Active)-StandbyのHA構成などで、Primary-Standby間のネットワーク断などの影響により、Standbyが昇格し、両ノードが更新可能なPrimaryとなり、ノード間でデータの不整合が発生する状態を指します。
また、fencing処理とは、SplitBrain 発生時に早急に旧Primaryを停止させ、データ不整合を回避する為の処理です。

2ノード構成の場合

まず、単純な2ノード構成を想定します。

role DC
Primary AZ1
Standby AZ2

AZ1-AZ2間にネットワーク断が発生したとします。
Primaryは正常に稼働を続けますが、StandbyからPrimaryに疎通は出来ないため、repmgrdはStandbyを昇格させます。その結果、AZ1、AZ2のPostgreSQLが共にPrimaryとなり、SplitBrainが発生してしまいます。
image.png

3ノード構成の場合

次に3ノード構成を想定します。

role DC
Primary AZ1
Standby AZ2
Witness AZ3

repmgrにWitnessという監視ノードの配置が可能です。
Witnessを配置して、primary_visibility_consensusをtrueにすることによって、(Witnessを含む)クラスタを構成する過半数ノードの合意を得なければ、Failoverしないように構成する事が出来ます。
この設定により、2ノード構成の例で説明したような、単純なAZ1-AZ2間のネットワーク断によるSplitBrainを防ぐ事が出来ます。

primary_visibility_consensus=true

では、AZ1がネットワーク的に隔離され、AZ2/AZ3と疎通出来ないケースではどうでしょうか?
この場合、AZ2のStandbyに加えて、AZ3のWitnessもPrimaryと疎通が出来ないと主張します。その結果、クラスタ内の2/3の合意が得られるので、FailoverしてSplitBrainが発生してしまいます。
この際に、AZ1のPrimaryと同じDCにアプリケーションが配置されていた場合、AZ1の古いPrimaryは更新され続けてしまいます。

image.png

こういったPrimaryがネットワーク的に隔離されたケースを想定して、fencing処理の実装が必要となります。

Environment

primary 1台 + standby 1台 + witnessの構成を想定しています。

role host IP
primary postgres-node1 192.0.2.1
standby postgres-node2 192.0.2.2
witness witness-node 192.0.2.3

Version

# Version
OS Rocky Linux 8.10
DB PostgreSQL 15.4
HA repmgr 5.3.3

How?

repmgrには子ノードの切断、接続をモニタリングする機能があります。
一定間隔でPrimaryのpg_stat_replicationを監視して、子ノードが切断された場合にrepmgrdにchild_node_disconnectイベントを生成させる事が出来ます。
また、一定数の子ノードがPrimaryから切断され、一定期間が経過した場合に、child_nodes_disconnect_commandに指定された任意のスクリプトを実行させる事が出来ます。
この機能を利用して、Primaryがネットワークから孤立した場合のfencingを実装する事が出来ます。

具体的な例を挙げて以下で説明します。

repmgr configuration

具体的なrepmgr.confの設定例を以下に示します。
この設定で、Primaryがネットワークから隔離され、Primary視点で子ノード(Standby + Witness)が切り離された状態になった場合、3-4秒(child_nodes_check_interval + child_nodes_disconnect_timeout)経過後、child_nodes_disconnect_commandに指定された fencing.sh を実行する、といったことが実現出来ます。

name setting
child_nodes_check_interval 1
child_nodes_disconnect_timeout 3
child_nodes_connected_min_count 1
child_nodes_disconnect_min_count -
child_nodes_connected_include_witness true
child_nodes_disconnect_command /home/postgres/fencing.sh

各パラメータの意味は以下の通りです。

  • child_nodes_check_interval はrepmgrに登録されたノードリストとpg_stat_replicationの比較チェックを行う間隔を指定します。(秒)
  • child_nodes_disconnect_timeout は接続されている子ノードの数が不十分と判断されてから、child_nodes_disconnect_command が実行されるまでの時間を指定します。(秒)
  • child_nodes_connected_include_witness は子ノードの定義にWitnessを含むかどうかを定義します。child_nodes_connected_min_count と child_nodes_disconnect_min_count にWitnessを含むかどうかに影響します。
  • child_nodes_connected_min_count はPrimaryに接続されている子ノードの数が、このパラメータで指定された数を下回ると、child_nodes_disconnect_command に指定されたスクリプトがrepmgrdによってトリガーされます。
  • child_nodes_disconnect_min_count は今回は設定していませんが、child_nodes_connected_min_count と排他的なパラメータになっています。
    child_nodes_connected_min_count が接続されているべき子ノードの数を指定するのに対して、child_nodes_disconnect_min_count は切断された子ノードの数の閾値となります。

パラメータ説明の詳細は以下の文書をご確認ください。
https://www.repmgr.org/docs/5.3/repmgrd-primary-child-disconnection.html

Test

擬似的にPrimaryのネットワークが孤立した状態を発生させます。
iptablesで、PrimaryとStandby、Witness間の通信を遮断します。
192.0.2.2 .... Standby
192.0.2.3 .... Witness

iptables -A OUTPUT -d 192.0.2.2/32 -o eth0 -j REJECT
iptables -A INPUT  -d 192.0.2.2/32 -i eth0 -j REJECT
iptables -A OUTPUT -d 192.0.2.3/32 -o eth0 -j REJECT
iptables -A INPUT  -d 192.0.2.3/32 -i eth0 -j REJECT

fencing.shは実際にpostgresは停止させずにechoするだけにします。

cat /home/postgres/fencing.sh
#!/bin/bash
date >> /tmp/fencing.log
echo "systemctl stop postgres" >> /tmp/fencing.log

iptables実行後、repmgr cluster eventを確認します。

repmgr cluster event
 Node ID | Name         | Event                          | OK | Timestamp           | Details
---------+--------------+--------------------------------+----+---------------------+----------------------------------------------------------------------------------------
 1       | node1        | child_nodes_disconnect_command | t  | 2024-09-10 19:52:07 | "child_nodes_disconnect_command" successfully executed
 1       | node1        | child_node_disconnect          | t  | 2024-09-10 19:52:04 | standby node "node2" (ID: 2) has disconnected
 1       | node1        | child_node_disconnect          | t  | 2024-09-10 19:52:02 | witness node "witness10001" (ID: 10001) has disconnected

Witness、Standbyの順にchild_node_disconnectイベントが発生して、Primaryから切り離されたことを確認出来ます。
また、最後の子ノード(今回だとStandby)が切り離されてから、3秒後に、child_nodes_disconnect_commandイベントが発生して、コマンド実行が成功したことを確認できます。

次にfencing.logを確認します。
child_nodes_disconnect_commandが発生した際に、fencing.shが実行されたことが確認出来ます。

cat /tmp/fencing.log
Tue Sep 10 19:52:07 JST 2024
systemctl stop postgres

まとめ

repmgrの子ノードの監視機能を使って、fencingの実装を行う方法を紹介しました。
引き続き、repmgrやPostgreSQLに関しての記事を作成していきたいと思いますので、よろしくお願いいたします。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?