본문 바로가기
PostgreSQL

PostgreSQL 14.2 File-based Log Shipping Replication 구축하기

by 울라불라오미짱 2023. 6. 2.
반응형

PostgreSQL의 고가용성을 높이기 위한 방법 중, 가장 기본적인 방법인 File-based Log Shipping Replication에 대해 알아보자!

File-based Log Shipping Replication 이란?

primary 서버에서 만드는 WAL 파일을 정기적으로 standby 서버로 전송하여 옮기고, primary 서버가 장애로 멈추게 되면 standby 서버를 승격하여 가용성을 향상할 수 있는 방법입니다.

File-based Log Shipping Replication의 특징

File-based Log Shipping Replication은 다음과 같은 특징이 있습니다.

  • Primary, Standby 서버가 모두 실행 중이어야 한다. 하지만 두 서버 연결 상태가 별로 좋지 않아도 가능하다는 장점이 있습니다.
  • 로그 전달 방식은 비동기 방식입니다
  • 전송하는 WAL의 내용은 이미 커밋 된 자료이기 때문에 전달되기 전에 Primary 서버가 멈춰버리면, 그 자료는 손실 되게 됩니다.
    • 자료 손실량을 줄이기 위해 archive_timeout 파라미터 값을 짧게 지정하면 되겠지만 너무 짧게 하면 네트워크 사용량이 증가할 것이다. 이를 보완하기 위해 Streaming Replication을 사용하면 이 손실 되는 자료량을 최소화 할 수 있다.

장점

  • 다른 Replication 방식보다 구성이 단순합니다.
    • Standby 서버가 알아볼 수 있는 경로에 WAL 파일을 위치하면 됩니다.
  • archive_command 파라미터에 scp 커맨드를 이용하면 손쉽게 WAL 파일을 Standby 서버에 전송할 수도 있습니다.
  • 다중 Standby 서버에서도 각각 서버로 동시에 전송하여 여러 대의 Standby서버를 구성할 수도 있습니다.

단점

  • WAL 파일 사이즈가 지정된 사이즈 16M 에 도달하여 스위칭 된 파일, archive_timeout 파라미터에 의해 강제로 WAL 파일 세그먼트가 스위칭 된 파일만 전송하기 때문에 그 사이에 Primary 서버에서 장애가 발생한다고 하면, 최근애 발생한 데이터에 대한 유실이 있을 수 있습니다.
  • warm standby 방식으로 구현되면, Standby 서버 쪽에서는 어떤 쿼리도 사용할 수 없다. 읽기 쿼리를 사용하려면 Hot Standby 방식으로 구축해야 합니다.

File-based Log Shipping Replication 운영 방식

  • Primary 서버는 아카이브 모드로 운영 되어야 하며, 운영 중에 생기는 다 쓴 WAL 세그먼트 파일 (스위칭 된 WAL 파일) 을 차례대로 Standby서버에 보내고 Standby서버는 복구 모드 전용으로 실행된다.

File-based Log Shipping Replication 구축

File-based Log Shipping Replication 구축 전 준비

Streaming Replication을 구축하기 전에 준비를 해보겠습니다.

  1. 우선 primary 와 standby 서버로 각각 설정할 서버 2개가 필요합니다! (너무 당연한 얘기 ㅋ) 서버 하나에 포트 다르게 해서 구성할 수 도 있긴 하지만 저는 편하게 2개로 구성해보겠습니다.
  2. 그리고 두 개의 서버가 다 PostgreSQL이 설치된 상태여야 합니다! 저는 initdb 전 상태에서 시작해보겠습니다.
  primary standby
IP 192.168.40.133 192.168.40.134

File-based Log Shipping Replication 설정 (primary 서버)

  • bash_profile 수정 (test유저)

 

source ~/.bash_profile
#ref : <https://www.postgresql.org/docs/current/libpq-envars.html>
# PostgreSQL ENV
PS1="[\\u@\\h:\\W]$ "
export PGVERSION=14
if [ -f "/usr/pgsql-$PGVERSION/bin/pg_ctl" ]; then
        export PGINST=/usr/pgsql-$PGVERSION                                 #postgresql binary installed path
        export MANPATH=/usr/pgsql-$PGVERSION/share/man:$MANPATH             #postgresql Man path
        export LD_LIBRARY_PATH=/usr/pgsql-$PGVERSION/lib:$LD_LIBRARY_PATH   #ld library path
        export PATH=/usr/pgsql-$PGVERSION/bin:$PATH                         #postgresql binary path
        export PGLIB=/usr/pgsql-$PGVERSION/lib                              #postgresql libary path
fi
export PGHOME=/test/pg                   #engine directory
export PGDATA=/test/pg/$PGVERSION/data   #database clsuter directory
export PGHOST=/var/run/test            #socket directory
export PGUSER=postgres                   #Basic DB User Name
#PostgreSQL ALIAS
alias pginst="cd $PGINST"
alias pglib="cd $PGLIB"
alias pghome="cd $PGHOME"
alias pgdata="cd $PGDATA"
alias pglog="cd $PGHOME/$PGVERSION/log/pg_log"
alias pgwal="cd $PGHOME/$PGVERSION/pg_wal"
alias pgconf="vi $PGDATA/postgresql.conf"
alias pghba="vi $PGDATA/pg_hba.conf"
source ~/.bash_profile

 

  • 데이터 클러스터 생성 (test유저)
initdb -U postgres -D $PGDATA -X /test/pg/$PGVERSION/pg_wal
  • standby 서버로 패스워드 없이 파일을 전송하기 위해 SSH 연결을 구성합니다.
    • test유저의 패스워드를 설정하지 않은 경우 설정해주어야합니다!
    mkdir ~/.ssh 
    chmod 700 ~/.ssh 
    cd ~/.ssh 
    ssh-keygen -t rsa
    
    ssh-copy-id -i id_rsa.pub test@192.168.40.134
    
    • SSH 연결 구성이 잘 되었는지 접속 테스트를 해봅니다.
ssh test@192.168.40.134

 

  • postgresql.conf 설정 (test유저)
    • 기본 설정에 streaming replication을 위한 파라미터 설정을 추가하여 설정해줍니다.
    cat << EOF >> $PGDATA/postgresql.conf                                   
    listen_addresses = '*'
    port = 5432
    unix_socket_directories = '/var/run/test'
    logging_collector = on
    log_directory = '/test/pg/14/log/pg_log'
    log_filename = 'postgresql-%Y-%m-%d-%H%M%S.log'
    log_rotation_age = 0
    log_rotation_size = 100MB
    wal_level=replica # WAL 아카이빙 및 Streaming replication을 하려면 replica 이상 사용
    archive_mode = on
    archive_command='scp %p test@192.168.40.134:/test/pg/14/archive/%f'
    # 'scp %p test@[Standby IP]:/test/pg/14/archive/%f'
    archive_timeout = 30 # 미설정시 WAL Segments를 16M을 채우고 스위치가 발생된 WAL 세그먼트를 전송
    EOF
  • pg_hba.conf 설정 (test 유저)
    • primary 서버의 데이터베이스에 standby 서버의 접속을 허용하는 설정을 해줍니다.
    cat << EOF >> $PGDATA/pg_hba.conf
    host    all             all            192.168.40.134/32    trust
    host    replication   all           192.168.40.134/32       trust
    EOF
    
    • 여기서 만약 primary 서버에 장애가 발생하여 standby 서버가 primary 서버가 되고, 장애가 났던 primary 서버를 다시 살려 standby서버로 기동할 수 있습니다. 즉, 서로 바뀐 상태가 되었을 때 pg_hba.conf 는 현 standby(구 primary) 서버의 IP가 없기 때문에 재설정 해주어야합니다. 그 상황을 대비하여 저는 primary 서버의 IP도 같이 적어 주겠습니다.
cat << EOF >> $PGDATA/pg_hba.conf 
host all all 192.168.40.134/24 trust 
host replication all 192.168.40.134/24 trust 
EOF
  • PostgreSQL 기동 (test 유저)
pg_ctl start

File-based Log Shipping Replication 설정 (standby 서버)

  • bash_profile 수정 (test 유저)
vi ~/.bash_profile
#ref : <https://www.postgresql.org/docs/current/libpq-envars.html>
# PostgreSQL ENV
PS1="[\\u@\\h:\\W]$ "
export PGVERSION=14
if [ -f "/usr/pgsql-$PGVERSION/bin/pg_ctl" ]; then
        export PGINST=/usr/pgsql-$PGVERSION                                 #postgresql binary installed path
        export MANPATH=/usr/pgsql-$PGVERSION/share/man:$MANPATH             #postgresql Man path
        export LD_LIBRARY_PATH=/usr/pgsql-$PGVERSION/lib:$LD_LIBRARY_PATH   #ld library path
        export PATH=/usr/pgsql-$PGVERSION/bin:$PATH                         #postgresql binary path
        export PGLIB=/usr/pgsql-$PGVERSION/lib                              #postgresql libary path
fi
export PGHOME=/test/pg                   #engine directory
export PGDATA=/test/pg/$PGVERSION/data   #database clsuter directory
export PGHOST=/var/run/test            #socket directory
export PGUSER=postgres                   #Basic DB User Name
#PostgreSQL ALIAS
alias pginst="cd $PGINST"
alias pglib="cd $PGLIB"
alias pghome="cd $PGHOME"
alias pgdata="cd $PGDATA"
alias pglog="cd $PGHOME/$PGVERSION/log/pg_log"
alias pgwal="cd $PGHOME/$PGVERSION/pg_wal"
alias pgconf="vi $PGDATA/postgresql.conf"
alias pghba="vi $PGDATA/pg_hba.conf"
source ~/.bash_profile
  • primary 서버를 pg_basebackup 진행
pg_basebackup -h 192.168.40.133 -p 5432 -D /test/pg/14/data --waldir /test/pg/14/pg_wal -P -v -X stream
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_53042"
26937/26937 kB (100%), 1/1 tablespace
pg_basebackup: write-ahead log end point: 0/2000100
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: syncing data to disk ...
pg_basebackup: renaming backup_manifest.tmp to backup_manifest
pg_basebackup: base backup completed
  • postgresql.conf 파라미터 추가
cat << EOF >> $PGDATA/postgresql.conf 
restore_command = 'cp /test/pg/14/archive/%f %p' 
archive_cleanup_command='pg_archivecleanup /test/pg/14/archive/ %r' 
EOF
  • restore_command : 복구 과정에서 사용할 WAL 세그먼트 파일들을 서버에 적용 시킬 커맨드입니다. 아카이브 모드 복구 작업을 하는 경우에 이 매개변수는 반드시 지정해야 합니다. 시작 시 standby는 아카이브에서 사용 가능한 모든 WAL을 복원하여 시작하고, 사용 가능한 WAL의 끝에 도달하고 실패하면 WAL을 복원하려고 시도합니다.
  • archive_cleanup_command : standby에서 더 이상 사용하지 않은 파일을 제거하기 위해 사용합니다.
  • standby.signal 파일 생성
    • 이 서버가 standby서버임을 증명하는 signal 파일을 생성합니다.
    touch $PGDATA/standby.signal
    
  • standby 서버 기동!
pg_ctl start

File-based Log Shipping Replication 확인

primary 서버

  • 프로세스 조회
    • primary 서버에서 archiver 프로세스가 standby 서버로 WAL(xx000F) 파일을 전송하였습니다.
ps -ef | grep postgres
test      55722      1  0 14:20 ?        00:00:00 /usr/pgsql-14/bin/postgres
test      55723  55722  0 14:20 ?        00:00:00 postgres: logger
test      55725  55722  0 14:20 ?        00:00:00 postgres: checkpointer
test      55726  55722  0 14:20 ?        00:00:00 postgres: background writer
test      55727  55722  0 14:20 ?        00:00:00 postgres: walwriter
test      55728  55722  0 14:20 ?        00:00:00 postgres: autovacuum launcher
test      55729  55722  0 14:20 ?        00:00:00 postgres: archiver last was 00000001000000000000000F
test      55730  55722  0 14:20 ?        00:00:00 postgres: stats collector
test      55731  55722  0 14:20 ?        00:00:00 postgres: logical replication launcher

standby 서버

  • 프로세스 조회
    • start up 프로세스가 restore를 위한 WAL(xx0010)파일을 기다리고 있습니다.
ps -ef | grep postgres
test       9527      1  0 14:21 ?        00:00:00 /usr/pgsql-14/bin/postgres
test       9528   9527  0 14:21 ?        00:00:00 postgres: logger
test       9529   9527  0 14:21 ?        00:00:00 postgres: startup waiting for 000000010000000000000010
test       9533   9527  0 14:21 ?        00:00:00 postgres: checkpointer
test       9534   9527  0 14:21 ?        00:00:00 postgres: background writer
test       9535   9527  0 14:21 ?        00:00:00 postgres: stats collector
  • log 확인
    • 동기화 여부는 standby 서버의 로그에서 확인할 수 있습니다.
    .....
    cp: cannot stat ‘/test/pg/14/archive/00000001000000000000000D’: No such file or directory
    cp: cannot stat ‘/test/pg/14/archive/00000002.history’: No such file or directory
    .....
    2023-06-02 15:01:43.533 KST [9529] LOG:  restored log file "00000001000000000000000D" from archive
    cp: cannot stat ‘/test/pg/14/archive/00000001000000000000000E’: No such file or directory
    cp: cannot stat ‘/test/pg/14/archive/00000002.history’: No such file or directory
    .....
    cp: cannot stat ‘/test/pg/14/archive/00000001000000000000000E’: No such file or directory
    cp: cannot stat ‘/test/pg/14/archive/00000002.history’: No such file or directory
    2023-06-02 15:02:43.675 KST [9529] LOG:  restored log file "00000001000000000000000E" from archive
    cp: cannot stat ‘/test/pg/14/archive/00000001000000000000000F’: No such file or directory
    cp: cannot stat ‘/test/pg/14/archive/00000002.history’: No such file or directory
    .....
    cp: cannot stat ‘/test/pg/14/archive/00000001000000000000000F’: No such file or directory
    cp: cannot stat ‘/test/pg/14/archive/00000002.history’: No such file or directory
    2023-06-02 15:05:43.931 KST [9529] LOG:  restored log file "00000001000000000000000F" from archive
    cp: cannot stat ‘/test/pg/14/archive/000000010000000000000010’: No such file or directory
    cp: cannot stat ‘/test/pg/14/archive/00000002.history’: No such file or directory
    
    • primary 에서 WAL 파일을 restore한 후, 다음 WAL파일을 restore을 시도했으나 받지 못했기 때문에 파일을 찾을 수 없다고 표시됩니다.
    • restore을 시도하는 메세지는 약 5초 간격으로 발생하며, archive_timeout=30 으로 설정했기 때문에 30초마다 스위칭 된 파일을 standby가 전달 받습니다.

WAL 파일 확인

  • primary의 WAL 디렉토리
    • 오래된 파일들은 삭제되고, 새로운 naming의 WAL파일이 생성됩니다.
-rw-------. 1 test test      338 Jun  2 13:57 000000010000000000000002.00000028.backup
-rw-------. 1 test test 16777216 Jun  2 15:05 00000001000000000000000F
-rw-------. 1 test test 16777216 Jun  2 14:06 000000010000000000000010
-rw-------. 1 test test 16777216 Jun  2 14:06 000000010000000000000011
-rw-------. 1 test test 16777216 Jun  2 14:25 000000010000000000000012
-rw-------. 1 test test 16777216 Jun  2 15:01 000000010000000000000013
-rw-------. 1 test test 16777216 Jun  2 15:02 000000010000000000000014
  • standby의 archive 디렉토리
    • archive_cleanup_command='pg_archivecleanup /test/pg/14/archive/ %r‘ 에 명시된 대로 전송 받은 WAL 파일들이 삭제 되고 있습니다.
-rw-------. 1 test test      338 Jun  2 14:20 000000010000000000000002.00000028.backup
-rw-------. 1 test test 16777216 Jun  2 15:05 00000001000000000000000F

데이터 확인

두 개의 서버가 replication이 잘 연결 됐는지 데이터 동기화를 통해 확인을 해보겠습니다!

  • primary
postgres=# CREATE TABLE t1 AS SELECT gs as idx, md5('text'||gs) as text FROM generate_series(1,500) as gs;
SELECT 500
postgres=# SELECT * FROM t1 limit 5;
 idx |               text
-----+----------------------------------
   1 | cef7ccd89dacf1ced6f5ec91d759953f
   2 | fe6123a759017e4a2af4a2d19961ed71
   3 | 265246eadd25390e2406a0d9bd22242b
   4 | 2a3def1740220a8312f1d046093437b9
   5 | 48fa2467e5e644c8a594757d255db7eb
(5 rows)
  • standby
postgres=# select * from t1 limit 5;
 idx |               text
-----+----------------------------------
   1 | cef7ccd89dacf1ced6f5ec91d759953f
   2 | fe6123a759017e4a2af4a2d19961ed71
   3 | 265246eadd25390e2406a0d9bd22242b
   4 | 2a3def1740220a8312f1d046093437b9
   5 | 48fa2467e5e644c8a594757d255db7eb
(5 rows)

 

standby 서버에서도 데이터가 조회가 가능한 걸 보아 replication이 잘 구축된 걸 확인할 수 있습니다.

반응형