ノート:

可用性の高いPostgresクラスタをOracle Cloud Infrastructureにデプロイ

イントロダクション

このチュートリアルでは、Patroniおよびその他のコンポーネントを使用したHA構成でのPostgresの設計および実装の概要を示します。PostgreSQLには、障害が発生したマスターをクラスタに追加するための組込みの自動フェイルオーバーおよび自動メカニズムがありません。Patroniは、クラウドネイティブ機能とフェイルオーバー/スイッチオーバーおよび自動ブートストラップおよびレプリカの設定のための高度なオプションを備えた、PostgreSQLの時代の高可用性(HA)ソリューションです。

Patroniは、Pythonを使用して独自のカスタマイズされたHAソリューションを作成し、アクセス性を最大限に高めるためのテンプレートで、etcdなどの分散構成ストアを作成します。

次に、PatroniのネイティブPostgresレプリケーションとそのソリューションに関するいくつかの制限事項を示します。

ネイティブのPostgresレプリケーションの制限 パトロニベースのソリューション
デフォルトのレプリケーションメカニズムでは、自動フェイルオーバーはサポートされません。 Patroniは自動フェイルオーバーを提供します。
外部ツールをフェイルオーバーに使用すると、それらを起動して実行し続けるために追加の作業が必要になる場合があります。 パトロニはフェイルオーバーを処理します。
Postgresのモニタリングも課題です。 Patroniには、Postgresサービスを監視する組込みメカニズムがあります。
障害が発生したノードをクラスタに自動的に追加するには、高度なスクリプト・スキルが必要です。 Patroniには、障害が発生したノードをクラスタに戻すための自動化が組み込まれています。
スプリット・ブレインのシナリオを処理できません。 ETCDの助けを借りたパトロニは、新しいリーダーを選ぶことができるだろう。

その他のPostgreSQL HAソリューションには次のものがあります。

ただし、PatroniをPostgres実装とともに使用すると、クラスタ管理のライフサイクル全体が大幅に簡略化されます。

目標

このチュートリアルでは、Postgresデータベースを(AWSまたは他のクラウド・ベンダーから)OCIに移行する可能性のある代替手段を備えた、実行可能な高パフォーマンス・ソリューションをリストします。HAおよびリアルタイムのデータ移行の主な要件。

アーキテクチャ

次のアーキテクチャは、3つのETCDサーバー、3つの(Postgres + Patroni + Pgbackrest)サーバー、Object StorageバケットおよびNetwork Load Balancerで構成されます。

アーキテクチャ図

推奨

  1. HA: 3つのETCDサーバーを使用し、PostgreSQLには3つのノードを使用し、異なるアベイラビリティ・ドメインに配置します。
  2. スループットを向上させるには、データ、一時、ウォルおよびログ・ファイル用に個別のブロック・ボリュームを作成します。
  3. クラスタ作成時のpatroni.yamlブートストラップ・セクションで、すべてのカスタム・パラメータを定義します。

PostgreSQL HAコンポーネントの構成およびインストール

設定は次の2つの部分に分かれています。

タスク1: インフラストラクチャのプロビジョニング

  1. コンピュートVMの作成:

    • 3つのETCDサーバー
    • Postgres + Patroni用の3台のサーバー(1人のリーダーと2つのレプリカ)
  2. バックアップを格納するためのオブジェクト・ストレージ・バケットを作成します。

  3. 前述のオブジェクト・ストア・バケットに対するREAD/WRITEアクセス権を持つOCIテナンシ・ユーザーを作成します。

タスク2: ソフトウェアのインストールおよび構成

  1. ETCDを設定します。

    • 3台のサーバーにETCDをインストールします。

      cd /tmp
      wget https://github.com/etcd-io/etcd/releases/download/v3.5.2/etcd-v3.5.2-linux-amd64.tar.gz
      tar xzvf /tmp/etcd-v3.5.2-linux-amd64.tar.gz
      cd etcd-v3.5.2-linux-amd64
      cp etcdutl etcdctl etcd /usr/local/bin/
      mkdir -p /etc/etcd
      mkdir -p /var/lib/etcd
      groupadd -f -g 1501 etcd
      useradd -c "etcd user" -d /var/lib/etcd -s /bin/false -g etcd -u 1501 etcd
      chown -R etcd:etcd /var/lib/etcd
      
    • 3台すべてのサーバーでETCDを設定および起動します。

      以下は、ETCDサーバーの詳細です。

      | Hostname | IP Address | Availability Domain |
      | --- | --- | --- |    
      | pg-etcd-01 | 192.0.2.4  | AD1 |
      | pg-etcd-02 | 192.0.2.5  | AD2 |
      | pg-etcd-03 | 192.0.2.6  | AD3 |
      

      ノート: 要件に従ってIPを変更します。

      pg- etcd-01

      vi /etc/etcd/etcd.conf
      
      ###Node1
      ##192.0.2.4
      
      ETCD_NAME="pg-etcd-01"
      ETCD_INITIAL_CLUSTER="pg-etcd-01=http://192.0.2.4:2380"
      ETCD_LISTEN_CLIENT_URLS="http://192.0.2.4:2379,http://127.0.0.1:2379"
      ETCD_ADVERTISE_CLIENT_URLS="http://192.0.2.4:2379"
      ETCD_LISTEN_PEER_URLS="http://192.0.2.4:2380,http://127.0.0.1:7001"
      ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.0.2.4:2380"
      ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
      ETCD_INITIAL_CLUSTER_STATE="new"
      ETCD_DATA_DIR="/var/lib/etcd"
      ETCD_ELECTION_TIMEOUT="5000"
      ETCD_HEARTBEAT_INTERVAL="1000"
      ETCD_ENABLE_V2="true"
      
      

      pg- etcd-02

      vi /etc/etcd/etcd.conf
      
      ##Node2
      ##192.0.2.5
      ETCD_NAME=" pg-etcd-02"
      ETCD_INITIAL_CLUSTER="pg-etcd-01=http://192.0.2.4:2380,pg-etcd-02=http://192.0.2.5:2380"
      ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
      ETCD_INITIAL_CLUSTER_STATE="existing"
      ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.0.2.5:2380"
      ETCD_LISTEN_PEER_URLS="http://192.0.2.5:2380,http://127.0.0.1:7001"
      ETCD_LISTEN_CLIENT_URLS="http://192.0.2.5:2379,http://127.0.0.1:2379"
      ETCD_ADVERTISE_CLIENT_URLS="http://192.0.2.5:2379"
      ETCD_DATA_DIR="/var/lib/etcd"
      ETCD_ELECTION_TIMEOUT="5000"
      ETCD_HEARTBEAT_INTERVAL="1000"
      ETCD_ENABLE_V2="true"
      

      pg- etcd-03

      vi /etc/etcd/etcd.conf
      
      ##Node3
      ##192.0.2.6
      ETCD_NAME="pg-etcd-03"
      ETCD_INITIAL_CLUSTER="pg-etcd-01=http://192.0.2.4:2380,pg-etcd-02=http://192.0.2.5:2380,pg-etcd-03=http://192.0.2.6:2380"
      ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
      ETCD_INITIAL_CLUSTER_STATE="existing"
      ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.0.2.6:2380"
      ETCD_LISTEN_PEER_URLS="http://192.0.2.6:2380,http://127.0.0.1:7001"
      ETCD_LISTEN_CLIENT_URLS="http://192.0.2.6:2379,http://127.0.0.1:2379"
      ETCD_ADVERTISE_CLIENT_URLS="http://192.0.2.6:2379"
      ETCD_DATA_DIR="/var/lib/etcd"
      ETCD_ELECTION_TIMEOUT="5000"
      ETCD_HEARTBEAT_INTERVAL="1000"
      ETCD_ENABLE_V2="true"
      
    • pg- etcd-01にメンバーを追加します。

      etcdctl member add pg-etcd-02 --peer-urls=http://192.0.2.5:2380
      etcdctl member add pg-etcd-03 --peer-urls=http://192.0.2.6:2380
      
    • 次のコマンドを実行して、メンバー・リストを表示します。

      etcdctl member list
      
    • サービスを作成します。

      vi /etc/systemd/system/etcd.service
      
      [Unit]
      Description=Etcd Server
      After=network.target
      After=network-online.target
      Wants=network-online.target
      
      [Service]
      Type=notify
      WorkingDirectory=/var/lib/etcd
      EnvironmentFile=-/etc/etcd/etcd.conf
      User=etcd
      # set GOMAXPROCS to number of processors
      ExecStart=/bin/bash -c "GOMAXPROCS=$(nproc) /usr/local/bin/etcd"
      Restart=on-failure
      LimitNOFILE=65536
      IOSchedulingClass=best-effort
      IOSchedulingPriority=0
      
      [Install]
      WantedBy=multi-user.target
      
      systemctl daemon-reload
      
      systemctl enable etcd
      
  2. Postgresをすべてのノードにインストールします。次のスクリプトを実行してPostgresをインストールします。

    • Postgresインストール・スクリプト

      ノート: Replicaの場合、postgresqlを停止し、Patroni構成が完了するとリーダーからコピーされるため、データ・ディレクトリを削除します。

      /opt/pgsql/bin/pg_ctl -D /opt/pgsql/data/$MAJORVERSION stop
      cd /opt/pgsql/data/
      rm *
      
  3. 拡張機能をインストール: pg_squeezeおよびpgaudit。

    • PGAUDITのインストール

      cd /usr/local/src/postgresql-12.6/contrib/
      wget https://github.com/pgaudit/pgaudit/archive/refs/heads/REL_12_STABLE.zip
      unzip REL_12_STABLE.zip
      make install USE_PGXS=1 PG_CONFIG=/opt/pgsql/bin/pg_config
      
    • PG_SQUEEZEのインストール

      cd /usr/local/src/postgresql-12.6/contrib/
      wget https://github.com/cybertec-postgresql/pg_squeeze/archive/refs/heads/master.zip
      unzip master.zip
      make install USE_PGXS=1 PG_CONFIG=/opt/pgsql/bin/pg_config
      
  4. すべてのノードにPatroniをインストールします。

    yum update –y
    yum -y install epel-release
    yum -y install python3
    yum install -y python3-devel
    yum install -y psutils
    yum install -y gcc
    yum install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
    yum install python3-psycopg2
    pip3 install python-etcd
    pip3 install patroni
    
  5. すべてのノードにpgBackrestをインストールして構成します。

    • Pgbackrestのインストール

      yum install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
      sudo yum install pgbackrest -y
      
    • すべてのノードでPgbackrestを構成します

      /etc/pgbackrest.conf
      [global]
      repo1-type=s3
      repo1-path=/backup
      repo1-s3-uri-style=path
      repo1-s3-region=us-ashburn-1
      repo1-s3-endpoint=https://xxxxx0011.compat.objectstorage.us-ashburn-1.oraclecloud.com
      repo1-s3-key=0000000a90d57eddexxxxxa3dc7c4f700000ed2e6
      repo1-s3-key-secret=1UhXj69xxxx1e6OyF+00000cccccyyyuuu=
      repo1-s3-bucket=pg_backup
      repo1-retention-full=10
      log-level-console=info
      log-level-file=debug
      log-path=/var/log/pgbackrest/
      
      [stanza-name]
      pg1-path=/opt/pgsql/data
      pg1-user=Postgres
      
    • すべてのノードでブートストラップ・ファイルを作成します。

      vi /etc/patroni/boot_pgbackrest.sh
      
      #!/ usr / bin /env bash
      while getopts ": -:" optchar ; do
              [[ "${ optchar }" == "-" ]] || continue
              case "${ OPTARG }" in
              datadir =* )
                      DATA_DIR =${ OPTARG #*=}
                      ;;
              scope =* )
                      SCOPE =${ OPTARG #*=}
                      ;;
              esac
      done
      /bin/pgbackrest --stanza=$SCOPE --link-all restore
      
  6. すべてのノードでPatroniを構成します。

    ホスト名 IPアドレス 可用性ドメイン
    pg- db-01 192.0.2.1 AD1
    pg- db-02 192.0.2.2 AD2
    pg- db-03 192.0.2.3 AD3

    ノート: 要件に従ってIPを変更します。

    mkdir -p /etc/patroni
    mkdir -p /opt/pgsql/patroni
    chown postgres:postgres -R /opt/pgsql/patroni
    chmod 700 /opt/pgsql/patroni
    
    vi /etc/patroni/patroni.yml
    
    scope:pg-ha-cluster
    name:pg-db-01
    namespace:/opt/pgsql/patroni/
    ###
    restapi:
      listen: "192.0.2.1:8008"
      connect_address: "192.0.2.1:8008"
    ###ETCD Configuration
     etcd:
       hosts: "192.0.2.4:2379,192.0.2.5:2379, 192.0.2.6:2379"
     ###Bootstrap
     bootstrap:
       dcs:
         ttl: 120
         loop_wait: 10
         retry_timeout: 10
         maximum_lag_on_failover: 1048576
         postgresql:
           use_pg_rewind: true
           use_slots: true
         parameters:
           archive_command: "pgbackrest --stanza=<stanza-name> archive-push %p"
           archive_mode: on
           archive_timeout: 900s
           log_file_mode: "0640"
           log_filename: postgresql-%u.log
           log_rotation_age: 1d
           log_truncate_on_rotation: "on"
           logging_collector: "on"
           max_connections: 2000
           max_replication_slots: 10
           max_wal_senders: 10
           max_wal_size: 5GB
           max_worker_processes: 40
           min_wal_size: 1GB
           wal_level: "replica"
           password_encryption: scram-sha-256
           superuser_reserved_connections: 200
           create_replica_methods:
             - pgbackrest
           pgbackrest:
             command: "/usr/bin/pgbackrest --stanza=<stanza-name>  restore --delta --link-all"
             keep_data: True
             no_params: True
         recovery_conf:
           recovery_target_timeline: latest
           restore_command: '/usr/bin/pgbackrest --stanza=<stanza-name>  archive-get %f %P'
        method: pgbackrest
        pgbackrest:
          command: /etc/patroni/boot_pgbackrest.sh
          keep_existing_recovery_conf: False
          recovery_conf:
            recovery_target_timeline: latest
            restore_command: '/usr/bin/pgbackrest --stanza=<stanza-name>  archive-get %f %P'
       initdb:
         - encoding: UTF8
         - data-checksums
       pg_hba:
         - host replication replicator 127.0.0.1/32 md5
         - host replication replicator 192.0.2.1/32 md5
         - host replication replicator 192.0.2.2/32 md5
         - host replication replicator 192.0.2.3/32 md5
         - host all all x.x.x.0/0 md5
       users:
         admin:
           password: admin
           options:
             - createrole
             - createdb
     #####Local Postgresql Parameters
     postgresql:
     listen: "192.0.2.1:5432"
     connect_address: "192.0.2.1:5432"
     data_dir: /opt/pgsql/data
     pgpass: /opt/pgsql/patroni/pgpass
     authentication:
       replication:
         username: replicator
         password: password
       superuser:
         username: postgres
         password: password
     #    rewind:
     #      username: replicator
     #      password: password
     parameters:
       unix_socket_directories: "/var/run/postgresql, /tmp"
     ###Any Tags
     tags:
       nofailover: false
       noloadbalance: false
       clonefrom: false
       nosync: false
    

    ノート: 各ノードのIPをそれぞれ変更します。

    chmod 640 /etc/patroni/patroni.yml
    chown postgres:postgres -R /etc/patroni/patroni.yml
    
    • すべてのノードでPatroniサービスを作成
    vi /etc/systemd/system/patroni.service
    
    [Unit]
    Description=Runners to orchestrate a high-availability PostgreSQL - patroni
    After=syslog.target network.target
    
    [Service]
    Type=simple
    
    User=postgres
    Group=postgres
    
    # Read in configuration file if it exists, otherwise proceed
    EnvironmentFile=-/etc/patroni_env.conf
    
    WorkingDirectory=~
    
    # Where to send early-startup messages from the server
    # This is normally controlled by the global default set by systemd
    # StandardOutput=syslog
    
    # Pre-commands to start watchdog device
    # Uncomment if watchdog is part of your patroni setup
    #ExecStartPre=-/usr/bin/sudo /sbin/modprobe softdog
    #ExecStartPre=-/usr/bin/sudo /bin/chown postgres /dev/watchdog
    
    # Start the patroni process
    ExecStart=/usr/local/bin/patroni /etc/patroni/patroni.yml
    
    # Send HUP to reload from patroni.yml
    ExecReload=/bin/kill -s HUP $MAINPID
    
    # Only kill the patroni process, not its children, so it will gracefully stop postgres
    KillMode=process
    
    # Give a reasonable amount of time for the server to start up/shut down
    TimeoutSec=60
    
    # Do not restart the service if it crashes, we want to manually inspect database on failure
    Restart=no
    
    [Install]
    WantedBy=multi-user.target
    
    sudo systemctl daemon-reload
    sudo systemctl enable patroni
    sudo systemctl start patroni
    sudo systemctl status patroni
    

    ノート: Replicaノードで、Patroniを構成しますが、サービスは起動しません。

    • 次のコマンドを実行して、マスター上のPatroniクラスタ・ステータスを確認します。

      patronictl -c /etc/patroni/patroni.yml list
      
      [root@pg-db-01 ~]# /usr/local/bin/patronictl -c /etc/patroni/patroni.yml list
      +--------------+-------------+---------+---------+----+-----------+
      | Member       | Host        | Role    | State   | TL | Lag in MB |
      + Cluster: pg-ha-cluster (7089354141421597068) --+----+-----------+
      | pg-db-01 | 192.0.2.1 | Leader  | running | 1 |           |
      +--------------+-------------+---------+---------+----+-----------+
      
  7. Stanzaを作成し、完全バックアップを実行します。

    pgbackrest --stanza=<stanza-name> stanza-create
    pgbackrest  --type=full --stanza= pgha --process-max=10 backup
    pgbackrest info
    
  8. ReplicaノードでPatroniを起動し、リーダーから自動的にキャッチアップを開始します。

    sudo systemctl start patroni
    sudo systemctl status patroni
    
    • 次のコマンドを実行して、クラスタのステータスを確認します。
    patronictl -c /etc/patroni/patroni.yml list
    

    ステータスは次のとおりです:

    [root@pg-db-01 ~]# /usr/local/bin/patronictl -c /etc/patroni/patroni.yml list
    +--------------+-------------+---------+---------+----+-----------+
    | Member       | Host        | Role    | State   | TL | Lag in MB |
    + Cluster: pg-ha-cluster (7089354141421597068) --+----+-----------+
    | pg-db-01 | 192.0.2.1 | Leader  | running | 2 |           |
    | pg-db-02 | 192.0.2.2  | Replica | running |2 |         0 |
    | pg-db-03 | 192.0.2.3  | Replica | running | 2 |         0 |
    +--------------+-------------+---------+---------+----+-----------+
    
  9. 最後に、ログ・クリーンアップ、バックアップなどのcronジョブを設定します。

    crontab –e
    #Pgbackrest FULL Backup on Sunday @1AM
    00 01 * * 0 postgres pgbackrest  --type=full --stanza=ash1-adeprod1-pgcluster --process-max=10 backup  &> /dev/null
    #Pgbackrest INC Backup on Mon-Sat @1AM
    00 01 * * 1-6 postgres pgbackrest  --type=diff --stanza=ash1-adeprod1-pgcluster --process-max=10 backup &> /dev/null
    #Delete PostgreSQL logs
    08 * * * find /opt/pgsql/log/* -mtime +15 -exec rm {} \; &>/dev/null
    

その他のPatroniコマンド

確認

その他の学習リソース

他のラボをdocs.oracle.com/learnで探すか、Oracle LearningのYouTubeチャネルでより無料の学習コンテンツにアクセスします。また、education.oracle.com/learning-explorerにアクセスしてOracle Learningエクスプローラになります。

製品のドキュメントは、Oracle Help Centerを参照してください。