이번에 다룰 주제는 PostgreSQL에 고가용성 구축을 위한 Maser-Slave 구성에 대해서 얘기해보려고 한다.
먼저 고가용성 시스템을 구축하기 위해서는 pgpool이라는 것을 알아야 되는데 간단하게 말해서 postgresql 서버와 클라이언트 사이에서 작동하는 미들웨어이다. 이를 사용하면 고가용성과 부하 분산이라는 두 가지 요구를 해결할 수 있다.
주로 다중 리더(Multiple leader) 설정에서 유용하며, 특정 테이블 또는 데이터에 대해서만 복제를 할 수 있다.

- 항상 쓰기는 마스터 서버로 이동하지만, 여러 서버에 걸쳐 선택의 균형을 맞추도록 pgpool 미들웨어 구성이 가능함
- 서버의 가중치를 할당해서 특정 서버에 얼마나 많은 부하를 보낼지 결정 가능(단 선택으로 실행되는 함수는 주의!)
pgpool에서 블랙 함수 목록을 조회하여 문제를 해결할 수 있다.
연결 풀링만 제공하는 솔루션을 찾는다면 pgbouncer를 공부해보자.
Failover
기본 노드에서 장애가 감지되면 pgpool이 스크립트를 실행해서 장애를 처리할 수 있지만 스크립트를 작성해야 되지만, 대기 승격을 처리하는 방법을 결정할 수 있다.
고가용성
pgpool은 자체적으로도 고가용성을 제공한다. 전체 시스템의 고가용성을 구현한다고 하면 pgpool 자체도 이중화해야 된다는 점!
Watch dog
두 개 이상의 마스터 노드를 동시에 사용할 경우 스플릿 브레인이 발생한다. 이렇게 되면 각 노드는 서로 다른 정보를 갖게 되면서 클러스터의 데이터 불일치 현상이 발생한다.
위의 상황을 해결하기 위해서는 일관성과 가용성을 모두 보장하는 것은 어렵다 어느 한쪽을 우선 순위에 두느냐에 따라 다르다.
Pgpool 복제도 좋은 기능이었지만, 이제 Streaming 복제가 PostgreSQL에 내장되어 있어 이를 사용하는 것이 좋다.
(부작용이나 잠재적인 문제에 대해 걱정 안해도 되기 때문에)
initdb -D /tmp/primary_db
1-2. 복제를 위한 기본 서버를 미리 구성
/tmp/primary_db/postgresql.conf
위 경로에 들어가서 listen_address = "*" 이 설정을 찾아서 주석을 해제하고 자신이 접속하는 서버에 IP 주소를 할당하자!
port = 5433를 찾아서 포트 충돌이 일어나지 않도록 수정하자
(로컬)쿠버네티스의 경우 쿠버네티스가 할당하는 IP를 찾아서 바꿔주도록 하자. 보통은 파드가 여러 개가 띄워지고 파드가 계속 재시작이 될 경우 IP주소가 바뀌니까 고정 IP로 설정하고 진행하면 될 것 같다.
pg_ctl -D /tmp/primary_db -l logfile start
그러면 성공적으로 5433 포트에서 시작된 서버를 확인할 수 있다.
1-3. 복제를 위한 별도의 사용자 만들기
psql --port=5433 (mydatabase)
먼저 우리가 만들었던 primary_db에 접속하고
create user repli replication;
새로운 사용자를 만들자.
/tmp/primary_db/pg_hpa.conf
위의 경로에 접속해서 설정을 수정해줘야 되는데 host all all 127.0.0.1/32 trust를 복사해서
host all all 127.0.0.1/32 trust
host all repli 127.0.0.1/32 trust
이런 느낌으로 새로운 사용자로 대체하자.
pg_ctl -D /tmp/primary_db restart
이제 다시 서버를 시작해주면 된다.
1-4. pg-basebackup 만들기
pg_basebackup -h localhost -U repli --checkpoint=fast -D /tmp/replication_db/ -R --slot=some_name -C --port=5433
1-5. 포트 충돌을 피하기 위해서 복제본의 포트 변경
/tmp/replication_db/postgresql.conf
위의 경로에 들어가서 Port=5434 포트를 수정하자.
pg_ctl -D /tmp/replication_db start
복제본을 시작하자. 복제본은 이제 읽기 전용 대기 모드이고 스트리밍 복제는 정상적으로 진행되고 있음을 확인할 수 있다.
brew install pgpool-ii
먼저 pgpool을 설치하자
cd /usr/local/etc
cp pgpool.conf.sample pgpool.conf
복사를 하고 나면 편집을 할 수 있다.
2-2. pgpool 설정파일 수정
이제 복제본을 수정
backend_hostname0 = 'localhost' 대기 서버 주소로 바꿔주자.
backend_port0 = 5434 기본 인스턴스를 시작한 이후
backend_weight = 1 기본 쿼리 값을 1으로 셋팅
=> 그러면 선택쿼리가 항상 대기쿼리로 이동한다는 의미
backend_data_directory0 = '/tmp/replication_db/'
-> 백엔드 DB가 있는 디렉터리를 기본 DB에 설정
log_statement = on
log_per_node_statement = on 노드당 로그 문도 검색
=> 이러한 변경사항을 저장하려면 프로덕션에서 로그를 꺼야 되며 피드 파일 이름도 변경해야된다.
pid_file_name = 'pgpool.pid'
sr_check_user = 'repli' 사용자 이름도 변경해주자
health-check_period = 10 10초마다 서버가 살아있는지 확인
health_check_user = 'repli' 사용자 수정
이제 저장하고 끄자
etc 경로에서 pgpool을 하게 되면 백그라운드에서 그냥 실행만 됨 로그 안뜸
pgpool -n &
로그를 확인하고 primary node와 standby node가 정상적으로 실행되고 있는지 확인하자
nano /tmp/primary_db/postgresql.conf
pg_ctl -D /tmp/primary_db restart
그리고 이제 서버를 다시 시작한다.
장애 조치를 하기 위해 스크립트 파일을 작성해야된다.
nano /tmp/pgsql/failover.sh
failed_node=$1
trigger_file=$2
if [ $failed_node = 1 ];
then exit 0;
fi
touch $trigger_file
exit 0;
위와 같이 스크립트를 작성하자. 위 스크립트는 기본 노드가 실패가 되면 이 스크립트가 실행된다.
장애가 발생한 노드가 1번 노드가 보조 노드인지 기본 노드인지 확인하고 대기 실패를 처리하고 싶지 않으면 종료
trigger_file이 보조노드에 의해 발견될 경우 touch 명령을 이용해 파일을 트리거하면 스트리밍 복제가 종료되고 대기가 승격되서 마스터노드가 된다.
nano /usr/local/etc/pgpool.conf
nano /tmp/replication_db/postgresql.conf
pg_ctl -D /tmp/replication_db restart
이제 다시 서버를 재시작하자.
일부에서 master_node를 사용할 수 없다고 가정하자.
1. 초기 상태 :
[참고문서]
https://www.youtube.com/watch?v=qpxKlH7DBjU&list=PLBrWqg4Ny6vVwwrxjgEtJgdreMVbWkBz0