본문 바로가기
PostgreSQL

PostgreSQL 14 Streaming Replication

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

PostgreSQL의 고가용성을 높이기 위한 방법 중에 하나이자, 가장 많이 사용 하는 방법인 streaming replication에 대해 알아보자!

Streaming Replication 이란?

standby는 WAL파일이 채워질 때까지 기다리지 않고 WAL레코드가 생성하는 대로 primary에 연결합니다. 그렇기 때문에 File-based log shipping 보다 더 최신 상태를 유지할 수 있습니다.

Streaming Replication의 특징

Streaming Replication은 다음과 같은 특징이 있습니다.

  1. WAL Record가 생성되면 즉시 Standby 서버로 보내기 때문에 Logshipping 보다 Standby 서버를 최신 상태로 유지 할 수 있습니다.
  2. 기본적으로 비동기로 작동하기 때문에 primary 트랜잭션을 커밋하고, standby에 변경사항이 적용되는 과정에서 생기는 약간의 딜레이가 발생합니다.
    • 네트워크 환경이 양호하고 Standby 서버의 성능이 좋다면 굉장히 작습니다. 심지어 같은 네트워크 대역대 안에 있다면, 거의 실시간으로 동기화가 됩니다.
    • 이 딜레이 타임은 File-based Log shipping 방식보다 훨씬 짧습니다.
  3. WAL 세그먼트 재활용
    • standby 서버에 WAL 세그먼트 파일을 수신하기 전에 primary 에서 WAL 세그먼트를 재활용 하는 상황이 생길 수 있습니다.
    • 이럴때에는 wal_keep_size 파라미터를 큰 값으로 설정해 재활용 주기를 늘리거나 어디까지 수신됐는지 확인할 수 있는 replication slot을 생성하여 해결 할 수 있습니다!
  4. Streaming Replication의 가장 큰 장점은 SELECT 조회가 가능하다는 점입니다.
    • Log Shipping 은 Restore 만 수행하기 때문에 데이터베이스에 접속도 못하지만 Hot Standby이기 때문에 SELECT 문을 실행할 수 있습니다.
  5. postgresql.conf의 primary_conninfo 파라미터를 사용하여 primary와 standby 서버를 연동합니다.

Streaming Replication 운영 방식

  • Standby 서버는 primary_conninfo의 설정정보를 가지고 Primary 서버에 연결합니다. 접속 성공을하면 archive 경로에서 사용 가능한 모든 WAL 파일을 탐색하고 restore합니다. 이후에 walreceiver 프로세스를 만들어 Primary 서버의 walsender 프로세스에서 보내는 트랜잭션 정보를 하나씩 받아서 자신의 서버에 적용합니다.
  • 파일단위가 아니라 Record단위로 적용하기 때문에 거의 실시간으로 동작한다고 볼 수 있습니다.
  • 하지만 긴 장애가 발생했을경우, WAL 파일을 사용하지 못하는 경우가 발생할 수 있기 때문에 Log Shipping 방식을 추가로 적용해 WAL 파일을 사전에 Standby 서버에 전송하게 하여 긴 장애시에도 정상적인 복원이 가능하도록 합니다.

Streaming Replication 구축

Streaming Replication 구축 전 준비

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

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

PostgreSQL Streaming Replication 설정 (primary 서버)

  • 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
  • 데이터 클러스터 생성 (test유저)
initdb -U postgres -D $PGDATA -X /test/pg/$PGVERSION/pg_wal
  • 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'
    wal_level = replica
    max_wal_senders = 10
    max_replication_slots = 10
    EOF
    
    • wal_level : WAL 아카이빙 및 Streaming Replication을 하려면 replica이상 사용
    • max_wal_senders : 동시에 실행되는 wal sender 프로세스의 최대 개수
    • max_replication_slots : 동시에 정의할 수 있는 최대 replication slot의 개수
  • 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 

 

  • postgres 유저 패스워드 설정 및 replication 전용 유저 생성 (test 유저)
psql -c "ALTER USER postgres PASSWORD 'password';"
psql -c "CREATE USER repluser WITH REPLICATION PASSWORD 'password' LOGIN;"
  • replication slot 생성 (test 유저)
    • wal 세그먼트 재활용을 막기 위한 replication slot을 생성해줍니다.
    psql  -c "SELECT * FROM pg_create_physical_replication_slot('192_168_40_134')"
    

PostgreSQL Streaming 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_65505"
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
  • recovery.conf 작성
    • postgresql.conf 파일 내에 설정해주어도 되지만, primary 정보 관련 파라미터를 관리하기 편하게 파일을 따로 빼서 작성해주겠습니다.
    • postgresql.conf 에 '/test/pg/14/data/myrecovery.conf' 에 작성된 파라미터도 적용하는 include_if_exists 파라미터를 입력합니다.
    cat << EOF >> $PGDATA/postgresql.conf
    include_if_exists = '/test/pg/14/data/myrecovery.conf'
    EOF
    
    • primary 서버의 정보, replication 전용 유저 정보와 primary에서 만든 replication slot 정보를 입력합니다.
    cat << EOF >> $PGDATA/myrecovery.conf
    primary_conninfo='host=192.168.40.133 port=5432 user=repluser password=password'
    primary_slot_name='192_168_40_134'
    EOF
    
  • standby.signal 파일 생성
    • 이 서버가 standby서버임을 증명하는 signal 파일을 생성합니다.
    touch $PGDATA/standby.signal
    
  • standby 서버 기동!
pg_ctl start

Streaming Replication 확인

primary 서버

프로세스 조회

ps -ef |grep postgres
test      58759      1  0 20:19 ?        00:00:00 /usr/pgsql-14/bin/postgres
test      58760  58759  0 20:19 ?        00:00:00 postgres: logger
test      58762  58759  0 20:19 ?        00:00:00 postgres: checkpointer
test      58763  58759  0 20:19 ?        00:00:00 postgres: background writer
test      58764  58759  0 20:19 ?        00:00:00 postgres: walwriter
test      58765  58759  0 20:19 ?        00:00:00 postgres: autovacuum launcher
test      58766  58759  0 20:19 ?        00:00:00 postgres: stats collector
test      58767  58759  0 20:19 ?        00:00:00 postgres: logical replication launcher
test      65509  58759  0 21:14 ?        00:00:00 postgres: walsender repluser 192.168.40.134(51546) streaming 0/3000148
  • primary 서버에서는 walsender 프로세스가 WAL(xx0003)파일의 000148에 해당하는 WAL 레코드를 standby 서버로 보내는 중인 것을 확인할 수 있습니다.
  • statics collector 에서 replication 정보 조회
psql -c '\x' -c 'SELECT * FROM pg_stat_replication;'
Expanded display is on.
-[ RECORD 1 ]----+------------------------------
pid              | 65509
usesysid         | 16384
usename          | repluser
application_name | walreceiver
client_addr      | 192.168.40.134
client_hostname  |
client_port      | 51546
backend_start    | 2023-05-09 21:14:09.580705+09
backend_xmin     |
state            | streaming
sent_lsn         | 0/3000148
write_lsn        | 0/3000148
flush_lsn        | 0/3000148
replay_lsn       | 0/3000148
write_lag        |
flush_lag        |
replay_lag       |
sync_priority    | 0
sync_state       | async
reply_time       | 2023-05-31 19:54:24.745173+09
  • 각 항목의 설명은 따로 정리 해서 올려야겠다!

standby 서버

  • 프로세스 조회
ps -ef | grep postgres
test      43565      1  0 19:51 ?        00:00:00 /usr/pgsql-14/bin/postgres
test      43566  43565  0 19:51 ?        00:00:00 postgres: logger
test      43567  43565  0 19:51 ?        00:00:00 postgres: startup recovering 000000010000000000000003
test      43568  43565  0 19:51 ?        00:00:00 postgres: checkpointer
test      43569  43565  0 19:51 ?        00:00:00 postgres: background writer
test      43570  43565  0 19:51 ?        00:00:00 postgres: stats collector
test      43571  43565  0 19:51 ?        00:00:02 postgres: walreceiver streaming 0/3000148
test      45163  38942  0 20:32 pts/1    00:00:00 grep --color=auto postgres
  • start up 프로세스가 WAL(xx0003)파일을 recovery 하고있습니다.
  • walreceiver 프로세스가 WAL(xx0003)파일의 000148에 해당하는 WAL record를 받아서 streaming 중입니다.

 

  • statistics collector 에서 replication 정보 조회
psql -c '\\x' -c 'SELECT * FROM pg_stat_wal_receiver';
Expanded display is on.
-[ RECORD 1 ]---------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
pid                   | 43571
status                | streaming
receive_start_lsn     | 0/3000000
receive_start_tli     | 1
written_lsn           | 0/3000148
flushed_lsn           | 0/3000148
received_tli          | 1
last_msg_send_time    | 2023-05-09 21:21:28.614078+09
last_msg_receipt_time | 2023-05-31 19:58:45.299881+09
latest_end_lsn        | 0/3000148
latest_end_time       | 2023-05-09 21:15:57.833702+09
slot_name             | 192_168_40_134
sender_host           | 192.168.40.133
sender_port           | 5432
conninfo              | user=repluser password=******** channel_binding=prefer dbname=replication host=192.168.40.133 port=5432 fallback_application_name=walreceiver sslmode=prefer sslcompression=0 sslsni=1 ssl_min_protocol_version=TLSv1.2 gssencmode=prefer krbsrvname=postgres target_session_attrs=any

데이터 확인

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

1. 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)

2. standby

postgres=# SELECT * FROM t1 limit 5;
 idx |               text
-----+----------------------------------
   1 | cef7ccd89dacf1ced6f5ec91d759953f
   2 | fe6123a759017e4a2af4a2d19961ed71
   3 | 265246eadd25390e2406a0d9bd22242b
   4 | 2a3def1740220a8312f1d046093437b9
   5 | 48fa2467e5e644c8a594757d255db7eb
(5 rows)

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

반응형