[PostgreSQL] pg_rewind 에 대해 알아보자

Ja L·2024년 6월 16일
0

[PostgreSQL] Operation

목록 보기
38/39

pg_rewind 란?

pg_rewind는 PostgreSQL에서 제공하는 유틸리티 중 하나로, 스트리밍 복제 또는 로그 복제를 사용하는 PostgreSQL 서버들 간에 데이터 디렉토리를 동기화하는 데 사용됩니다. 주로 스트리밍 복제를 설정한 후 스트리밍 장애나 서버 간 데이터 불일치 문제를 해결할 때 유용하게 사용됩니다.

보통 PostgreSQL 스트리밍 복제 설정에서는 마스터(Master)와 슬레이브(Slave) 서버가 있습니다. 마스터 서버의 데이터베이스가 변경될 때마다 이 변경 사항이 슬레이브로 전송되어 데이터 일관성을 유지합니다. 그러나 때로는 슬레이브가 마스터와 동기화되지 않거나, 스트리밍 장애로 인해 슬레이브가 마스터보다 뒤처진 상태가 될 수 있습니다.

이런 상황에서 pg_rewind는 슬레이브 서버의 데이터 디렉토리를 마스터 서버와 일치시키는 도구로 사용됩니다. 주요 기능은 다음과 같습니다:

  1. 데이터 디렉토리 동기화: 마스터와 슬레이브 서버의 데이터 디렉토리를 비교하여 슬레이브의 데이터 디렉토리를 마스터와 일치시킵니다.

  2. 재설정된 장애 복구: 스트리밍 장애로 인해 데이터 디렉토리가 불일치할 경우, pg_rewind를 사용하여 슬레이브를 마스터의 상태로 되돌립니다.

  3. 복제 불일치 해결: 슬레이브가 마스터와 동기화되지 않은 경우, pg_rewind를 사용하여 슬레이브를 마스터의 레벨로 동기화할 수 있습니다.


내부에서 어떤 커맨드로 동작할까?

검색해본 결과 rsync를 사용한다고 합니다. pg_rewind는 데이터 디렉토리를 동기화하기 위해 rsync를 사용합니다. pg_rewind는 PostgreSQL 데이터 디렉토리의 변경 사항을 식별하고, 이를 기반으로 마스터 데이터 디렉토리와 슬레이브 데이터 디렉토리 간의 차이를 확인합니다. 그 후 rsync를 이용하여 마스터 데이터 디렉토리의 변경 사항을 슬레이브 데이터 디렉토리에 적용하여 동기화를 수행합니다.

rsync는 파일과 디렉토리를 동기화하기 위해 널리 사용되는 유틸리티로, 변경된 부분만 효율적으로 전송하여 대상 디렉토리를 원본과 동일하게 유지시키는 기능을 제공합니다. 이를 통해 pg_rewind는 PostgreSQL 데이터 디렉토리의 동기화 작업을 효율적으로 처리할 수 있습니다.

따라서 pg_rewind는 PostgreSQL 스트리밍 복제 환경에서 스트리밍 장애나 데이터 불일치 문제를 해결하는 데 사용될 때, rsync를 통해 데이터 디렉토리를 빠르게 동기화할 수 있는 장점을 가지고 있습니다.

pg_rewind 사용해보자

테스트를 할 때 구글 시트에 커맨드를 기록하고 정리합니다. 테스트한 구글 시트 내용을 공유합니다.

과정primarysecondary비고
primary 기본 설정listen_addresses = '*'
archive_mode = on
archive_command = 'test ! -f /archive/%f && cp %p /archive/%f'
logging_collector = on
log_filename = 'postgresql-%Y-%m-%d.log'

wal_level = replica
synchronous_commit = local

wal_keep_size = 32
synchronous_standby_names = '*'
promote_trigger_file = '/home/agensql/data/trigger.signal'
hot_standby = on
primary 기본 설정host all all 0.0.0.0/0 trust
host replication repluser 0.0.0.0/0 trust
primary 기동ag_ctl start
repluser 생성 및 권한 부여create user repluser with replication password '1234' login;
grant all privileges on database agensdb to repluser;
Replication 초기 구성pg_basebackup -h 192.168.54.184 -D $PGDATA -U repluser -p 5333 -v -P -R --wal-method=stream
ag_ctl start
recovery 모드 확인select pg_is_in_recovery();
wal_reciever 확인select * from pg_stat_replication;
Primary 장애 상황ag_ctl stoppostgres=# select * from pg_stat_replication;
pid | usesysid | usename | application_name | client_addr | client_hostname | clien
t_port | backend_start | backend_xmin | state | sent_lsn | write_lsn
| flush_lsn | replay_lsn | write_lag | flush_lag | replay_lag | sync_priority | sync_state
| reply_time
--------+----------+----------+------------------+---------------+-----------------+------
-------+-------------------------------+--------------+-----------+-----------+-----------
+-----------+------------+-----------+-----------+------------+---------------+-----------
-+-------------------------------
382500 | 16384 | repluser | walreceiver | 192.168.54.83 | |
35792 | 2024-06-04 08:44:55.378618+09 | | streaming | 0/3000060 | 0/3000060
| 0/3000060 | 0/3000060 | | | | 1 | sync
| 2024-06-04 08:45:35.489058+09
(1 row)


postgres=# select pg_is_in_recovery();
pg_is_in_recovery
-------------------
t
(1 row)
Secondary Promote[방법 2 가지]
1. pg_ctl promote -D $PGDATA
2. vi $PGDATA/postgresql.conf
promote_trigger_file = '/home/agens/data/trigger.signal'
pg_ctl reload / select pg_reload_conf();
touch /home/agens/data/trigger.signal
[agens@bitnine data]$ pg_ctl promote -D $PGDATA
waiting for server to promote.... done
server promoted
DDL 발생create table test(a int);
insert into test select * from generate_series(1,1000);
과정Single DB비고
설정 추가vi postgresql.conf
wal_log_hints = on
vi postgresql.conf
wal_log_hints = on
vi postgresql.conf
wal_log_hints = on 후 pg_reload_conf() 해도 반영안됨. 재기동 필요.
그리고 결정적으로 primary는 wal_log_hints off여도 pg_rewind 기능 적용됨 (깨진 standby 만 on으로 설정 후 재기동 한다면)
재기동 및 설정 등록ag_ctl start
ag_ctl stop
pg_ctl reload
pg_rewind(sync)pg_rewind --source-server='host=192.168.54.83 port=5333 user=agens dbname=postgres' --target-pgdata=$PGDATA -P[agens@bitnine data]$ pg_rewind --source-server='host=192.168.54.83 port=5333 user=agens dbname=postgres' --target-pgdata=$PGDATA -P
pg_rewind: connected to server
pg_rewind: servers diverged at WAL location 0/30000D8 on timeline 1
pg_rewind: rewinding from last common checkpoint at 0/3000060 on timeline 1
pg_rewind: reading source file list
pg_rewind: reading target file list
pg_rewind: reading WAL in target
pg_rewind: need to copy 86 MB (total source directory size is 124 MB)
88135/88135 kB (100%) copied
pg_rewind: creating backup label and updating control file
pg_rewind: syncing target data directory
pg_rewind: Done!
rm $PGDATA/postgresql.auto.conf
설정 추가vi postgresql.conf
primary_conninfo='user=repluser password=1234 host=192.168.54.83 port=5333'
standby.signal 추가touch $PGDATA/standby.signal[agens@bitnine ~]$ pg_rewind --source-server='host=192.168.54.83 port=5333 user=agens dbname=postgres' --target-pgdata=$PGDATA -P
pg_rewind: connected to server
pg_rewind: servers diverged at WAL location 0/50000A0 on timeline 1
pg_rewind: rewinding from last common checkpoint at 0/5000028 on timeline 1
pg_rewind: reading source file list
pg_rewind: reading target file list
pg_rewind: reading WAL in target
pg_rewind: need to copy 85 MB (total source directory size is 124 MB)
87921/87921 kB (100%) copied
pg_rewind: creating backup label and updating control file
pg_rewind: syncing target data directory
pg_rewind: Done!
재기동ag_ctl start
과정new_secondarynew_primary비고
recovery 모드 확인select pg_is_in_recovery();postgres=# select pg_is_in_recovery();
pg_is_in_recovery
-------------------
t
(1 row)
wal_reciever 확인select * from pg_stat_replication;postgres=# select * from pg_stat_replication;

Docker로 구성하는 방법

주변에서 pg_rewind에 대한 관심이 적지 않아 모두가 테스트해볼 수 있도록 팀 내 서버에 Docker Container로 구성해두었습니다. 이 내용은 향후 기록할 Docker 기본 커맨드를 정리할 때도 들어가겠지만, 구체적인 사례를 기록해두는 것도 좋을 것 같아 기록합니다.

Docker 컨테이너 간 네트워크 통신을 위해 Docker network를 생성합니다.

docker network create pg-network 

Rocky8.9에 pg15를 설치한 Docker container를 이미지로 만들어 사용합니다. 이미지를 만드는 방법에 대해서는 생략하겠습니다.

docker run --name pg15_1 -it -d --privileged=true --network pg-network pg_15_2 /sbin/init
docker run --name pg15_2 -it -d --privileged=true --network pg-network pg_15_2 /sbin/init

Docker 컨테이너 내부로 접속하여 네트워크를 확인한 결과는 다음과 같습니다.

Container_namePrviate_IP
pg15_1172.18.0.2
pg15_2172.18.0.3

Docker 관련한 커맨드는 다음과 같습니다.
pg_rewind 커맨드 사용

# 172.18.0.2 서버에서 실행
$PGHOME/pg_rewind --source-server='host=172.18.0.3 port=5432 user=postgres dbname=postgres' --target-pgdata=$PGDATA -P -R	
# 172.18.0.3 서버에서 실행
$PGHOME/pg_rewind --source-server='host=172.18.0.2 port=5432 user=postgres dbname=postgres' --target-pgdata=$PGDATA -P -R

개인 기록

부하 생성을 위한 Python 커맨드는 다음과 같습니다.

nohup python3.8 /var/lib/pgsql/test/threading_test.py &

Python threading을 이용해서 부하를 생성한 이유
Replication이 깨진 상태에서 promote된 새로운 Primary가 많은 트랜잭션이 일어나 max_wal_size를 넘는 wal파일이 쓰여질 경우 wal 파일은 덮어쓰기 되어 단순히 pg_wal파일만을 이용해서 동기화가 불가능할 것입니다.


rsync 방식을 통해 파일을 동기화하는 방식이기 때문에 이러한 상황에서 $PGDATA/base 디스크 파일 역시 동기화 될 것이기 때문에 pg_wal이 덮어쓰기된 것과 관계없이 Replication이 이어질 것입니다. 이를 확인해보고 싶었습니다. 결과는 예상한대로 정상적인 pg_rewind 후 replication이 복구되었습니다.

profile
DB Engineer

0개의 댓글

관련 채용 정보