작성자: 서준섭 과장 ㅣDB R&D센터 l DB Tech 팀
1.pg_rewind 소개
1.1. pg_rewind란?
PostgreSQL 공식 문서에서 pg_rewind는 다음과 같이 소개하고 있습니다.
PostgreSQL 데이터 디렉터리를 자신으로부터 파생된 또 다른 데이터 디렉터리에게 맞춰 동기화합니다. |
pg_rewind는 클러스터의 또 다른 복사본에 맞춰 PostgreSQL 클러스터를 동기화 해주는 도구입니다. 이는 클러스터의 타임라인이 분기된 경우에도 적용할 수 있습니다. 일반적인 시나리오는 장애 복구 후 이전의 마스터 서버를 새로운 마스터 서버의 스탠바이로 되돌려주는 것입니다.
pg_rewind를 사용하면 대상 데이터 디렉터리가 원본 데이터 디렉터리의 베이스 백업본과 유사하게 만들어집니다. 다른 백업 방법과 다른 점은, pg_rewind는 변경된 블록만 복사하기 때문에 전체 파일을 복사할 필요가 없다는 것입니다. 또한, 대상 데이터 디렉터리에 없는 릴레이션 파일, 환경 설정 파일, WAL 파일 등은 그대로 복사됩니다. 데이터베이스가 크고 변경 사항이 크지 않는 경우, pg_rewind를 이용한 이 되감기 작업이 다른 구축 방법보다 빠릅니다.
pg_rewind는 source 클러스터와 target 클러스터 간의 타임라인 이력을 조사하여 분기 지점(replication 중단 시점)을 찾아냅니다. 그리고 타겟 클러스터의 pg_wal 디렉터리에서 분기된 시점으로 되돌릴 수 있는 전체 WAL 파일을 찾아냅니다. 이 분기 지점은 source/target 클러스터 또는 두 클러스터 간의 공통된 이전 타임라인에서 찾을 수 있습니다.
전형적인 장애 복구 시나리오에서 target 클러스터는 분기된 지 오래되지 않은 경우가 많습니다. 이 경우에는 문제가 없지만, target 클러스터가 분기된 이후에도 오랜 기간 운영되었다면, source 클러스터 측에서 오래된 WAL 파일이 없을 수 있습니다. 이런 경우에는 직접 해당 WAL 아카이브 파일을 pg_wal 디렉터리로 복사하거나, pg_rewind의 -c 옵션을 사용하여 복사할 수도 있습니다. pg_rewind 명령은 페일오버 용도로만 사용되는 것이 아니라, 대기 서버가 운영 서버로 전환되었다가 다시 대기 서버로 바뀌는 경우에도 사용될 수 있습니다.
pg_rewind 수행 후, 타겟 서버는 데이터의 일관성을 유지하기 위해 WAL 재반영 작업이 필요합니다. 서버가 시작되면 아카이브 복구 모드로 진입하고, 원본 데이터베이스 서버의 마지막 체크포인트 이후에 소스 서버에서 생성된 모든 WAL을 재생합니다. 문제는 필요한 WAL 파일이 없는 경우입니다. 이 상황에서는 pg_rewind 명령으로 이 파일들을 복사할 수 없습니다. 이런 경우, target 서버가 실행될 때 target 데이터 디렉터리 내에 recovery.signal 파일을 만들고, postgresql.conf 파일에서 복구에 필요한 적절한 restore_command 설정을 할 수 있습니다. 이를 통해 target 서버가 필요한 WAL 파일을 복구할 수 있습니다.
pg_rewind를 수행하기 위해서는 target 서버의 postgresql.conf 에서 다음과 같은 요구사항이 충족되어야 합니다:
1. wal_log_hints 옵션이 활성화되어 있어야 합니다.
2. initdb로 클러스터를 초기화할 때 체크섬(checksum)이 활성화되어 있어야 합니다.
또한 full_page_writes 값은 on으로 활성화되어 있어야 합니다. 이 옵션들은 모두 기본값으로 비활성화되어 있습니다. 이러한 설정이 완료되어야 pg_rewind를 성공적으로 수행할 수 있습니다.
[postgres@204b0624983f ~]$ $PGHOME/pg_rewind --help pg_rewind resynchronizes a PostgreSQL cluster with another copy of the cluster. Usage: pg_rewind [OPTION]... Options: -c, --restore-target-wal use restore_command in target configuration to retrieve WAL files from archives -D, --target-pgdata=DIRECTORY existing data directory to modify --source-pgdata=DIRECTORY source data directory to synchronize with --source-server=CONNSTR source server to synchronize with -n, --dry-run stop before modifying anything -N, --no-sync do not wait for changes to be written safely to disk -P, --progress write progress messages -R, --write-recovery-conf write configuration for replication (requires --source-server) --config-file=FILENAME use specified main server configuration file when running target cluster --debug write a lot of debug messages --no-ensure-shutdown do not automatically fix unclean shutdown -V, --version output version information, then exit -?, --help show this help, then exit Report bugs to <pgsql-bugs@lists.postgresql.org>. PostgreSQL home page: <https://www.postgresql.org/> |
1.2 wal_log_hints 파라미터의 역할
wal_log_hints 옵션을 on으로 설정하면 PostgreSQL의 Write-Ahead Logging (WAL) 메커니즘에 변화가 발생합니다. 이 옵션이 활성화되면, 데이터베이스는 힌트 비트(hint bits)를 업데이트할 때마다 WAL에 해당 로그를 기록하게 됩니다. 힌트 비트는 데이터베이스 인덱스 및 기타 메타데이터의 정합성을 유지하는 데 사용됩니다. 이 옵션이 중요한 이유는 다음과 같습니다:
hint bits란? PostgreSQL의 MVCC 메커니즘은 많은 유용한 기능을 제공하지만 구현 과정에서 몇 가지 혼란스러운 부작용이 발생할 수 있습니다. 그 중 하나는 힌트 비트(hint bits) 처리와 관련된 것입니다. MVCC는 힌트 비트를 사용하여 데이터의 가시성과 정합성을 관리합니다. 힌트 비트는 커밋되거나 중단된 트랜잭션에 의해 튜플이 생성 및/또는 삭제된 것을 표시하는 데 사용됩니다. 이러한 힌트 비트가 설정되지 않은 튜플의 가시성을 결정하려면 pg_clog 및 pg_subtrans를 참조해야 하므로 비용이 많이 드는 검사 작업이 필요합니다. 반면에 튜플에 비트가 설정된 경우, 해당 상태가 알려져 있어 현재 스냅샷에서 쉽게 계산할 수 있습니다. 문제는 이러한 힌트 비트 처리 과정에서 데이터베이스 테이블에 많은 쓰기 작업이 발생할 수 있다는 점입니다. 즉, 사용자가 데이터베이스 테이블을 단순히 읽기만 하는 경우에도, 힌트 비트 관리를 위한 쓰기 작업이 필요할 수 있습니다. 이는 MVCC 메커니즘의 부작용으로, 데이터베이스 성능에 부정적인 영향을 미칠 수 있습니다. |
wal_log_hints 설정으로 인한 변화
WAL 기록 증가:
- 힌트 비트(hint bits)는 MVCC(Multi-Version Concurrency Control) 구현의 일환으로 사용되며, 레코드의 상태를 추적하는데 사용됩니다.
- 힌트 비트 업데이트는 주로 커밋된 트랜잭션을 표시하거나 오래된 트랜잭션의 상태를 표시하는 데 사용됩니다.
- wal_log_hints를 on으로 설정하면, 이러한 힌트 비트 변경 사항이 WAL에 기록됩니다.
- 결과적으로 WAL 로그의 크기가 증가할 수 있습니다.
디스크 I/O 증가:
- WAL 로그의 크기 증가로 인해 디스크 I/O가 증가할 수 있습니다.
- 이는 시스템의 성능에 영향을 미칠 수 있으며, 특히 많은 업데이트가 발생하는 워크로드에서 두드러질 수 있습니다.
데이터 무결성 향상:
- wal_log_hints가 on으로 설정되면, 클러스터의 데이터를 다른 노드로 이동하거나 복구하는 과정에서 데이터 무결성을 유지하는 데 도움이 됩니다.
- 이는 주로 고가용성 환경에서 중요한 고려 사항입니다.
pg_rewind 시 wal_log_hints가 필요한 이유
pg_rewind는 PostgreSQL 클러스터를 특정 시점으로 되돌리기 위해 사용되는 도구입니다. 주로 장애 복구 상황이나 스탠바이 서버를 프라이머리 서버로 전환한 후 원래 프라이머리 서버를 다시 동기화할 때 사용됩니다.
pg_rewind가 제대로 작동하려면 두 서버 간의 차이를 식별하고 필요한 변경 사항을 동기화해야 합니다. wal_log_hints가 필요한 이유는 다음과 같습니다:
블록 수준 차이 검출:
- pg_rewind는 블록 수준에서 변경된 데이터를 식별합니다. WAL에 힌트 비트 변경 사항이 기록되지 않으면, pg_rewind는 정확한 변경 내역을 파악할 수 없습니다. 이는 데이터 일관성에 문제를 야기할 수 있습니다.
안전한 동기화:
- 힌트 비트의 변경 사항이 WAL에 기록되면, pg_rewind는 이러한 변경 사항을 인식하고 안전하게 동기화할 수 있습니다. 이는 클러스터의 무결성을 유지하고 데이터 손실을 방지하는 데 필수적입니다.
따라서, wal_log_hints 설정을 ‘on’으로 하는 것은 pg_rewind의 올바른 작동을 보장하고 데이터 일관성과 무결성을 유지하는 데 중요한 역할을 합니다. 이를 통해 PostgreSQL 클러스터의 안정성과 신뢰성을 높일 수 있습니다.
2. pg_rewind 목적
pg_rewind의 목적은 끊어진 Replication을 현재 운영중인 Primary DB와 Data Cluster를 동기화하고 Replication을 재연결하는 것입니다.
새롭운 Replication을 구성하는 간단한 방법으로 pg_basebackup을 고려할 수 있습니다. 그렇다면 pg_rewind가 pg_basebackup과 어떤 차이점과 장점이 있는지 살펴볼 필요가 있습니다. pg_basebackup의 경우 Data Cluster를 완전히 삭제하고 현재 운영 중인 Primary DB의 Data Cluster를 처음부터 물리적으로 복제합니다.
반면 pg_rewind는 source DB가 분기된 시점부터 target DB와의 차이점을 블록 단위로 확인하고 변경된 부분만 추가합니다. 따라서 데이터 용량이 큰 데이터베이스에서 끊어진 Replication을 재구성하는 데 소요되는 시간은 pg_rewind가 월등히 빠르다는 장점이 있습니다. 마찬가지로 pg_rewind를 수행하는 경우 pg_basebackup에 비해 빠른 속도로 failback이 가능하다는 장점이 있습니다.
3. pg_rewind 사용
과정 | primary | secondary |
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 stop | |
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 |
|
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 |
재기동 및 설정 등록 | 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 -R | |
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 | |
재기동 | ag_ctl start | |
과정 | new_secondary | new_primary |
recovery 모드 확인 | select pg_is_in_recovery(); | |
wal_receiver 확인 | select * from pg_stat_replication; |
3.1. pg_rewind를 이용한 failback
과정 | Primary | Standby |
초기 Replication 구성 | $PGHOME/pg_basebackup -h 172.18.0.2 -D $PGDATA -U repluser -p 5432 -v -P -R --wal-method=stream | |
$PGHOME/pg_ctl start | ||
select * from pg_stat_replication; | select pg_is_in_recovery(); | |
Primary 서버 장애 | $PGHOME/pg_ctl stop | |
Standby 서버 Read only 확인 | create table test123(id int); ERROR: cannot execute CREATE TABLE in a read-only transaction |
|
Standby 서버 Promote | [postgres@204b0624983f ~]$ $PGHOME/pg_ctl promote waiting for server to promote.... done server promoted |
|
과정 | DB off | Single (Promote) |
테이블 생성 및 데이터 삽입 | CREATE TABLE user_activity_log2 ( id SERIAL PRIMARY KEY, user_id INT NOT NULL, activity_type VARCHAR(50) NOT NULL, activity_timestamp TIMESTAMP NOT NULL, activity_details TEXT ); |
|
DO $$ DECLARE start_id INT := 1; end_id INT := 1000000; -- Adjust this to reach ~1GB data user_id INT; activity_types TEXT[] := ARRAY['login', 'logout', 'purchase', 'view', 'click']; activity_details TEXT; activity_timestamp TIMESTAMP; BEGIN FOR i IN start_id..end_id LOOP user_id := (i % 10000) + 1; -- Simulating 10,000 unique users activity_timestamp := NOW() - (random() * INTERVAL '1000 days'); activity_details := md5(random()::text); INSERT INTO user_activity_log2 (user_id, activity_type, activity_timestamp, activity_details) VALUES (user_id, activity_types[(random() * 4 + 1)::INT], activity_timestamp, activity_details); END LOOP; END $$; |
||
wal_log_hints 설정 | vi postgresql.conf wal_log_hints = on |
|
DB 재기동 | ag_ctl start ag_ctl stop |
|
pg_rewind 수행 | $PGHOME/pg_rewind --source-server='host=172.18.0.3 port=5432 user=postgres dbname=postgres' --target-pgdata=$PGDATA -P -R pg_rewind: connected to server pg_rewind: servers diverged at WAL location 0/630000A0 on timeline 2 pg_rewind: rewinding from last common checkpoint at 0/63000028 on timeline 2 pg_rewind: reading source file list pg_rewind: reading target file list pg_rewind: reading WAL in target pg_rewind: need to copy 537 MB (total source directory size is 1071 MB) 550000/550000 kB (100%) copied pg_rewind: creating backup label and updating control file pg_rewind: syncing target data directory pg_rewind: Done! |
|
postgresql.auto.conf 삭제 | rm $PGDATA/postgresql.auto.conf | |
복제 대상 설정 | vi postgresql.conf primary_conninfo='user=repluser password=1234 host=172.18.0.3 port=5432' |
|
DB 기동 | $PGHOME/pg_ctl start | |
과정 | new_standby | new_primary |
Replication 확인 | select pg_is_in_recovery(); | select * from pg_stat_replication; pid | usesysid | usename | application_name | client_addr | client_hostname | client_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 -------+----------+----------+------------------+-------------+-----------------+-------------+-------------------------------+--------------+-----------+------------+------------+------------+------------+ -----------+-----------+------------+---------------+------------+------------------------------- 97179 | 24576 | repluser | walreceiver | 172.18.0.2 | | 50820 | 2024-06-17 05:39:39.883996+00 | | streaming | 0/900633D8 | 0/900633D8 | 0/900633D8 | 0/900633D8 | | | | 1 | sync | 2024-06-17 05:39:50.838498+00 (1 row) |
wal_log_hints 설정 | vi postgresql.conf wal_log_hints = on |
|
DB 종료 | $PGHOME/pg_ctl stop | |
구 Primary promote | $PGHOME/pg_ctl promote | |
과정 | new_primary | DB off |
pg_rewind 수행 | $PGHOME/pg_rewind --source-server='host=172.18.0.2 port=5432 user=postgres dbname=postgres' --target-pgdata=$PGDATA -P -R | |
복제 대상 설정 | vi postgresql.conf primary_conninfo='user=repluser password=1234 host=172.18.0.2 port=5432' |
|
DB 기동 | $PGHOME/pg_ctl start | |
Replication 확인 | select * from pg_stat_replication; pid | usesysid | usename | application_name | client_addr | client_hostname | client_port | backend_start | backend_xmin | state | sent_lsn | write_lsn | flush_lsn | repl ay_lsn | write_lag | flush_lag | replay_lag | sync_priority | sync_state | reply_time -------+----------+----------+------------------+-------------+-----------------+-------------+-------------------------------+--------------+-----------+------------+------------+------------+----- -------+-----------+-----------+------------+---------------+------------+------------------------------- 53519 | 24576 | repluser | walreceiver | 172.18.0.3 | | 57092 | 2024-06-17 05:56:49.833254+00 | | streaming | 0/91005F98 | 0/91005F98 | 0/91005F98 | 0/91 005F98 | | | | 1 | sync | 2024-06-17 05:58:50.991647+00 (1 row) |
select pg_is_in_recovery(); |
4. pg_rewind 마무리
결론적으로, pg_rewind는 PostgreSQL 클러스터의 장애 복구 및 스탠바이 서버 전환에 유용한 도구입니다. 변경된 블록만을 복사하여 효율적으로 데이터를 동기화하며, 타임라인 분기 후에도 적용할 수 있어 유연합니다. 이를 통해 빠른 시간 내에 클러스터를 복구하거나 스탠바이 서버로 전환할 수 있습니다.
단, pg_rewind를 성공적으로 수행하기 위해서는 타겟 서버의 postgresql.conf 파일에서 필요한 설정이 충족되어야 하며, 필요한 WAL 파일을 확보해야 합니다. 특히, 복구 모드에서 WAL 파일이 없을 경우에는 별도로 아카이브 파일을 복사하거나 restore_command 설정을 통해 복구할 수 있습니다.
따라서, pg_rewind는 신속하고 효율적인 복구 및 서버 전환을 지원하는 중요한 도구로, 적절한 설정과 파일 관리가 필수적입니다. 이러한 점들을 고려하여 pg_rewind를 활용하면 PostgreSQL 클러스터의 안정성과 가용성을 크게 향상시킬 수 있습니다.
'POSTGRESQL > 단편' 카테고리의 다른 글
PostgreSQL 컨트리뷰터가 설명하는 pgPool의 문제점과 해결방안 (0) | 2024.07.10 |
---|---|
PostgreSQL에서의 오라클 사용자를 위한 가이드 (0) | 2024.07.09 |
PostgreSQL 글로벌 컨트리뷰터와의 기술 인터뷰_feat. 최신 PG 17버전 (0) | 2024.06.27 |
PostgreSQL 성능 저하 Troubleshooting 가이드-2부- (0) | 2024.06.26 |
PostgreSQL 성능 저하 Troubleshooting 가이드-1부- (0) | 2024.06.24 |