참고:

Oracle Cloud Infrastructure에 고가용성 Postgres 클러스터 배포

소개

이 자습서에서는 Patroni 및 기타 구성 요소를 사용한 HA 구성에서 Postgres의 설계 및 구현에 대해 간략하게 설명합니다. PostgreSQL에는 클러스터에 실패한 마스터를 다시 추가하기 위한 내장된 자동 페일오버 및 자동 방식이 없습니다. Patroni는 페일오버/스위치오버 및 자동화된 부트스트랩 및 복제 설정을 위한 클라우드 전용 기능과 고급 옵션을 갖춘 PostgreSQL의 새로운 HA(고가용성) 솔루션입니다.

Patroni는 Python을 사용하여 자체 커스터마이즈된 HA 솔루션을 만들고 최대한의 접근성을 위해 etcd와 같은 분산형 구성 저장소를 만드는 템플릿입니다.

다음은 네이티브 Postgres 복제와 Patroni 솔루션의 몇 가지 제한 사항입니다.

기본 Postgres 복제 제한 사항 Patroni 기반 솔루션
기본 복제 방식은 자동 페일오버를 지원하지 않습니다. Patroni는 자동 페일오버를 제공합니다.
페일오버를 위해 외부 도구를 사용하려면 이러한 도구를 작동 및 실행 상태로 유지해야 할 수 있습니다. Patroni는 페일오버를 처리합니다.
Postgres 모니터링도 문제가 될 수 있습니다. Patroni에는 Postgres 서비스를 모니터링하는 내장 메커니즘이 있습니다.
실패한 노드를 클러스터에 다시 자동으로 추가하려면 고급 스크립팅 기술이 필요합니다. Patroni는 장애가 발생한 노드를 클러스터로 되돌릴 수 있도록 자동화 기능이 내장되어 있습니다.
스플릿 브레인 시나리오를 처리할 수 없습니다. ETCD의 도움으로 Patroni는 새로운 리더를 선택할 수 있습니다.

기타 PostgreSQL HA 솔루션은 다음과 같습니다.

그러나 Patroni를 Postgres 구현과 함께 사용하면 전체 클러스터 관리 수명 주기가 크게 간소화됩니다.

목표

이 사용지침서에서는 고객이 Postgres 데이터베이스(AWS 또는 기타 클라우드 공급업체)를 OCI로 마이그레이션할 수 있는 잠재적 대안과 더불어 실행 가능한 고성능 솔루션에 대해 설명합니다. 핵심 요구사항은 HA 및 실시간 데이터 마이그레이션입니다.

구조

다음 아키텍처는 ETCD 서버 3개, (Postgres + Patroni + Pgbackrest) 서버 3개, 오브젝트 스토리지 버킷 및 네트워크 로드 밸런서로 구성됩니다.

구조 다이어그램

권장 사항

  1. HA의 경우 ETCD 서버 3개, PostgreSQL의 노드 3개를 사용하여 다른 가용성 도메인에 배치합니다.
  2. 처리 능력을 향상시키려면 데이터, 임시, WAL 및 로그 파일에 대해 별도의 블록 볼륨을 생성하십시오.
  3. 클러스터를 만들 때 patroni.yaml 부트스트랩 섹션에서 모든 사용자 정의 매개변수를 정의합니다.

PostgreSQL HA 구성 요소 구성 및 설치

설정은 두 부분으로 나뉩니다.

작업 1: 기반 구조 프로비전

  1. 컴퓨트 VM 생성:

    • 3 ETCD 서버
    • Postgres용 서버 3개 + Patroni(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를 수정합니다.

      페이지-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"
      
      

      페이지-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"
      

      페이지-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 설치 스크립트

      주: 복제의 경우 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 주소 가용성 도메인
    페이지-db-01 192.0.2.1 AD1
    페이지-db-02 192.0.2.2 AD2
    페이지-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
    

    주: 복제 노드에서 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를 시작하면 Leader로부터 자동으로 캐치업이 시작됩니다.

    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 Explorer가 됩니다.

제품 설명서는 Oracle Help Center를 참조하십시오.