메뉴 건너뛰기

Cloudera, BigData, Semantic IoT, Hadoop, NoSQL

Cloudera CDH/CDP 및 Hadoop EcoSystem, Semantic IoT등의 개발/운영 기술을 정리합니다. gooper@gooper.com로 문의 주세요.


*출처 : https://blog.qodot.me/post/postgresql-replication-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0/


PostgreSQL Replication 구축하기

Mar 2, 2017 00:00 · 4234 words · 9 minutes readDATABASE POSTGRESQL REPLICATION

실제 서비스를 운용할 때, 아키텍쳐 안의 거의 대부분의 컴포넌트를 이중화 하는 것은 필수에 가까우며, 데이터베이스 역시 예외는 아니다. 이번 포스팅에서는 PostgreSQL의 내장 기능을 이용해서 복제 스탠바이 서버를 구축하는 과정을 공유하려고 한다.

리눅스/데이터베이스에 대한 별다른 지식이랄 것도 없는 상태에서, 운영 중인 데이터베이스를 건드려가면서 이중화 작업을 한다는 것은 상당히 손떨리는 일이라 ㅜㅜ 최대한 안전하게 적용하기 위해서 나름 상당한 시간을 들여서 리서치와 테스트를 진행했다. 만약 이 글을 보고 자신의 서비스에 복제 대기 DB를 구축하려고 하시는 분들이 있다면, 꼭!! 테스트용 서버 두 대(이상)를 구해서 충분히 테스트 해보고 개발 DB -> 운영 DB 순으로 적용하시기를 바란다.

WAL

PostgreSQL에서 제공하는 복제 서버 구축 방식을 요약하면 다음과 같다.

  1. 마스터 서버에서 발생하는 모든 작업을 로그로 만든다.
  2. 이 로그를 스탠바이 서버(들)로 전달한다.
  3. 스탠바이 서버(들)에서 받은 로그를 복원(재실행)한다.

이렇게 하면 마스터 서버와 같은 스키마/데이터를 가지는 복제 서버가 탄생하게 된다. 이 때, 마스터 서버의 로그를 WAL(Write Ahead Log)이라고 하며, 이 로그는 CentOS 기준 /var/lib/pgsql/9.x/data/pg_xlog 디렉토리에 쌓이게 된다.

WAL 전달 방식

구축 과정 2번의 로그를 스탠바이 서버로 전달하는 방식을 조금 더 자세히 보면, pg_xlog 디렉토리 안의 WAL 파일 자체를 스탠바이 서버로 전달(file copy)하면 Log-Shipping 방식이 되고, WAL 파일 저장 여부와 관계 없이 로그의 내용을 스탠바이 서버로 직접 전달하면 Streaming 방식이 되는 것이다.

Log-Shipping

Log-Shipping 방식의 경우, 마스터 서버에서 지정된 WAL 파일의 크기를 다 채워야 스탠바이 서버로 전송이 일어나기 때문에, 그 시간 동안 마스터/스탠바이 서버의 데이터가 어긋나 있는 상태가 유지된다. 만약 이 때 마스터 서버에 장애가 발생한다면, WAL 파일을 다 채우지 못해서 전달되지 못한 로그는 유실될 수 밖에 없다.

Streaming

Streaming 방식은 PostgreSQL 9.0 이상에서 사용이 가능하다.

그러나 Streaming 방식의 경우, 두 서버간의 네트워크에 문제가 없다는 가정하에, 거의 실시간으로 동작한다고 봐도 무방하다(1초 미만의 작은 지연 발생). 따라서 데이터 유실에 대한 걱정을 그만큼 덜 수 있으므로 Streaming 방식을 선택하지 않을 이유가 없다.

그러나 Streaming 방식의 경우, 만약 스탠바이 서버에 긴 장애가 발생할 경우 문제가 생길 수 있다. 이는 마스터 서버에서 WAL 파일을 재활용하기 때문이다. 만약 스탠바이 서버에 장애가 길어져서, 그동안 마스터 서버가 가장 오래된 WAL 파일을 덮어써버린다면, 스탠바이 서버에가 복구된 이후에도 유실된 WAL 내용을 복원할 수 있는 방법이 없다.

마스터 서버 postgresql.conf 설정 파일 안의 wal_keep_segments 옵션에 따라 저장하고 있는 WAL 파일의 최대 갯수가 정해진다.

만약 wal_keep_segments 값이 32라면, 스탠바이 서버에 장애가 발생한 순간부터, 마스터 서버에서 33번째 WAL을 쓰기 시작한다면 1번째 파일은 유실된다.

만약 유실되는 데이터가 생길 경우, 다시 데이터를 동기화 할 방법은 스탠바이 서버를 처음부터 다시 구축하는 방법 밖에는 없다. 따라서 데이터의 빠른 동기화를 위해서 Streaming 방식을 사용하더라도, 이와 같은 문제를 피하기 위해서 Log-Shipping 방식을 적용해 놓는 것이 좋다. (스탠바이 서버의 장애가 길어지더라도 그동안 WAL 파일의 복사는 계속 되므로 장애 복구 후 WAL 복원이 가능)

Streaming Replication 적용

우선 기본적으로 Streaming 방식을 적용해서 스탠바이 서버를 구축해보자. 두 개의 서버가 존재한다고 가정하고, 서버의 호스트를 각각 MASTERSTANDBY라고 하자. 이 포스트에서 PostgreSQL의 설치 부분은 생략한다.

CentOS 기준으로 PostgreSQL의 중요 데이터 및 설정 파일에 접근할 수 있는 유저는 postgres이며, 이 유저의 홈 디렉토리는 /var/lib/pgsql이다.

복제 전용 유저 생성

Streaming 방식을 적용하기 위해서 스탠바이 서버에서 마스터 서버에 접근할 Replication 전용 유저를 생성한다.

CREATE ROLE repluser WITH REPLICATION PASSWORD 'password' LOGIN;

방금 생성한 이 계정의 권한을 설정하기 위해 pg_hba.conf 파일을 편집한다. (CentOS 기준 /var/lib/pgsql/9.x/data/pg_hba.conf) 복제 전용 유저이기 때문에 복제 권한을 부여한다.

host    replication     repluser    192.168.x.x/32    md5

마스터 서버 설정

다음은 마스터 서버에서 복제를 수행하기 위한 설정을 편집한다. (CentOS 기준 /var/lib/pgsql/9.x/data/postgresql.conf)

listen_addresses = '*'  # 인증/권한 관리는 pg_hba.conf 파일에서 진행
wal_level = hot_standby  # 대기 서버에 읽기전용 작업 가능
max_wal_senders = 2  # WAL 파일을 전송할 수 있는 최대 서버 수
wal_keep_segments = 32  # 마스터 서버 디렉토리에 보관할 최근 WAL 파일의 수

wal_level 옵션을 archive로 하면 스탠바이 서버를 대상으로 아무 작업도 하지 못하기 때문에, 복제가 제대로 수행되고 있는지 확인할 방법도 없다.

스탠바이 서버 최초 백업

pg_basebackup 명령을 이용해서 최초 백업을 진행할 수 있다. 이 명령은 마스터 서버의 /var/lib/pgsql/9.x/data 디렉토리를 통째로 스탠바이 서버의 /var/lib/pgsql/9.x/data 디렉토리로 복제/복원하는 명령이다. 이 때 스탠바이 서버 해당 경로의 모든 파일을 덮어쓰기 때문에, postgresql.conf 파일을 미리 백업해두는 것이 좋다.

sudo -u postgres cp /var/lib/pgsql/9.x/data/postgresql.conf /path/to/backup/postgresql.conf

그리고 다음 명령을 통해 최초 백업을 진행한다.

sudo -u postgres /usr/pgsql-9.x/bin/pg_basebackup -h MASTER -D /var/lib/pgsql/9.x/data -U repluser -v -P --xlog-method=stream

CentOS에서 PostgreSQL를 yum을 통해 설치했을 경우 /usr/pgsql-9.x/bin에 실행 파일들이 들어가게 된다.

조금 전에 백업해놓았던 postgresql.conf 파일을 다시 복구한다.

sudo -u postgres cp /path/to/backup/postgresql.conf /var/lib/pgsql/9.x/data/postgresql.conf

스탠바이 서버 설정

스탠바이 서버에서 WAL 내용을 Streaming 방식으로 받을 수 있게 하기 위해 먼저 postgresql.conf 파일을 다음과 같이 설정한다.

listen_addresses = '*'  # 인증/권한 관리는 pg_hba.conf 파일에서 진행
hot_standby = on  # 대기 서버에 읽기전용 작업 가능

추가로, postgresql.conf 파일과 같은 경로에 recovery.conf라는 이름의 파일을 생성한다.

standby_mode = on
primary_conninfo = 'host=MASTER port=5432 user=repluser password=password'

primary_conninfo 옵션의 정보로 마스터 서버에 접속해서 실시간으로 WAL 내용을 전달 받는다.

PostgreSQL 프로세스 실행

마스터 서버와 스탠바이 서버에서 차례로 PostgreSQL 프로세스를 실행하면 아마도 다음과 유사한 리스트가 나올 것이다.

마스터 서버

postgres 15597     1  0 Feb27 ?        00:00:02 /usr/pgsql-9.x/bin/postmaster -p 5432 -D /var/lib/pgsql/9.x/data
postgres 15599 15597  0 Feb27 ?        00:00:00 postgres: logger process
postgres 15601 15597  0 Feb27 ?        00:00:01 postgres: checkpointer process
postgres 15602 15597  0 Feb27 ?        00:00:01 postgres: writer process
postgres 15603 15597  0 Feb27 ?        00:00:01 postgres: wal writer process
postgres 15604 15597  0 Feb27 ?        00:00:02 postgres: autovacuum launcher process
postgres 15605 15597  0 Feb27 ?        00:00:00 postgres: archiver process   last was 00000001000000040000003A
postgres 15606 15597  0 Feb27 ?        00:00:05 postgres: stats collector process
postgres 15650 15597  0 Feb27 ?        00:00:11 postgres: wal sender process repluser 192.168.x.x(36972) streaming 4/3B000000

wal sender process가 눈에 띈다. 스탠바이 서버의 IP에서 repluser로 접속한 것이 보인다.

스탠바이 서버

postgres 20553     1  0 Feb23 ?        00:00:00 /usr/pgsql-9.x/bin/postmaster -p 5432 -D /var/lib/pgsql/9.x/data
postgres 20555 20553  0 Feb23 ?        00:00:00 postgres: logger process
postgres 20556 20553  0 Feb23 ?        00:00:03 postgres: startup process   recovering 00000001000000040000003A
postgres 20557 20553  0 Feb23 ?        00:00:00 postgres: checkpointer process
postgres 20558 20553  0 Feb23 ?        00:00:01 postgres: writer process
postgres 20559 20553  0 Feb23 ?        00:00:00 postgres: stats collector process
postgres 31615 20553  0 Feb27 ?        00:01:06 postgres: wal receiver process   streaming 4/3B000000

wal reciever process를 보면, 마스터 서버의 wal sender process에서 보내고 있는 키(4/3B000000)와 같은 키를 받고 있는 것을 확인 할 수 있다. (키는 매번 바뀜)

마스터 서버에서 다음과 같은 쿼리를 날려보면 더 확실하게 복제 서버가 작동하고 있다는 것을 확인할 수 있다.

SELECT * FROM pg_stat_replication;

  pid  | usesysid | usename  | application_name |  client_addr  | client_hostname | client_port |         backend_start         |   state   | sent_location | write_location | flush_location | replay_location | sync_priority | sync_state
-------+----------+----------+------------------+---------------+-----------------+-------------+-------------------------------+-----------+---------------+----------------+----------------+-----------------+---------------+------------
 15650 |    18014 | repluser | walreceiver      | 192.168.x.x   |                 |       36972 | 2017-02-27 17:37:42.226689+09 | streaming | 4/3B000000    | 4/3B000000     | 4/3B000000     | 4/3B000000      |             0 | async
(1 row)

Log-Shipping Replication 적용

위에서 설명했듯, 혹시 모를 스탠바이 서버의 오랜 기간 장애에도 대응하기 위해서 Log-Shipping 방식을 함께 적용할 수 있다. 스탠바이 서버의 WAL 복원 자체는 Streaming 방식으로 받는 내용으로 하되, 만약에 사태에 대비해서 WAL 파일을 쌓아두고만 있는 것이다.

WAL 파일을 쌓아둘 디렉토리 설정

반드시 스탠바이 서버 안에 쌓을 필요는 없다. 스탠바이 서버가 파일로 복구할 수 있도록 접근 가능한 위치라면 어디든 상관 없다. 이 포스트에서는 스탠바이 서버 postgres 유저의 홈 디렉토리에 저장을 진행한다.

sudo -u postgres mkdir /var/lib/pgsql/archives
sudo chown postgres:postgres /var/lib/pgsql/archives
sudo chmod 700 /var/lib/pgsql/archives

비밀번호 입력 없이 scp가 동작하도록 설정

마스터 서버에서 스탠바이 서버로 WAL 파일을 전달하는 방법은 단순히 설정에 등록된 shell 명령어를 실행하는 것이다. 따라서 주로 scp 명령을 사용하는데, 자동화를 하려면 ssh 접속시 비밀번호 입력을 기다려서는 안된다. 이를 위해 마스터 서버에서 다음과 같은 작업을 진행한다.

sudo -u postgres ssh-keygen
sudo -u postgres ssh-copy-id /var/lib/pgsql/.ssh/id_rsa.pub postgres@STANDBY

ssh-copy-id 명령은 대상 계정의 authorized_keys 파일에 원하는 키를 등록한다.

WAL 파일 전송 설정

실제로 마스터 서버에서 WAL 파일을 전송할 수 있게 설정을 편집한다.

archive_command = 'scp -i /var/lib/pgsql/.ssh/id_rsa %p postgres@STANDBY:/var/lib/pgsql/9.x/archives/%f'
archive_timeout = 30

%p는 archive(WAL) 파일의 full path이고 %f는 파일의 이름이다.

마스터 서버를 재시작 하면, 스탠바이 서버의 지정된 디렉토리에 파일이 쌓이는 것을 확인할 수 있다.

Failover / Failback

드디어 스탠바이 서버를 구축하는데 성공했다. 아마 마스터 서버에 스키마 혹은 row를 추가한다면, 곧바로 스탠바이 서버에 같은 내용이 적용된 것을 확인할 수 있을 것이다. 그럼 이제 구축된 서버를 써먹는 일만 남았는데, 필요한 일은 다음과 같다.

  • 마스터 서버에 장애가 발생했을 때 어떻게 스탠바이 서버를 써먹을 수 있는지 (Failover)
  • 마스터 서버에 발생했던 장애가 복구된 이후 어떻게 최초의 상황으로 돌아갈 수 있는지 (Failback)

PostgreSQL 자체적으로는 기본적인 기능만 제공하고 있다. 고급 기능을 더 편리하게 이용하고 싶다면 pgpool-II나 slony-I 같은 도구를 리서치하는 것도 좋은 방법으로 보인다. 이 외에도 각종 3rd party 도구들을 한눈에 비교한 자료를 PostgreSQL Wiki의 한 페이지에서 볼 수 있으니 참고바란다.

일단 이 포스팅에서는 PostgreSQL이 지원하는 기능 위주로 사용해보려고 한다.

Failover

스탠바이 서버를 운영 서버로 전환하는 방법은 두 가지가 있는데 하나는 pg_ctl promote 명령어를 사용하는 방법이고, 또 하나는 recovery.conf 파일에 trigger_file 옵션을 이용하는 방법이다. trigger_file에 경로를 등록해 놓으면 해당 경로에 파일이 생성되었을 때(touch 등으로), 스탠바이 서버가 새로운 마스터 서버로 승격된다.

trigger_file = '/path/of/triggerfile'

스탠바이 서버를 승격시킬때는 기존 마스터 서버가 확실하게 다운된 상태인지 확인해야 한다. 만약 마스터 서버가 살아있는 상태에서 스탠바이 서버를 승격시킬 경우, 데이터 손실 등의 예상치 못한 문제가 발생할 수 있으니 주의가 필요하다.

Auto Failover

위의 방법은 모두 수동으로 진행해야 하는 방법이고, 만약 자동으로 Failover를 하고 싶다면 다른 도구나 방법을 강구해야 한다. (위에서 소개한 도구들에서 자동 Failover를 지원하는 것으로 보임) 사실 이 부분은 아직 자세히 알아보지 못한 부분인데 ㅜㅜ 반드시 필요한 기능이기 때문에 추가로 리서치를 해봐야겠다.

Failover 후 운영

스탠바이 서버를 승격시키고 난 후에는, 기존 마스터 서버의 장애가 복구되고 Failback 되기 전까지 마스터 서버 하나로 운영해야하는 상황이 발생한다. 기존 마스터 서버가 어떤 이유로 장애가 났는지 예측할 수 없기 때문에, 빠른 Failback을 장담할 수 없고, 그동안 위험한 상황이 발생할 수 있다.

이런 상황을 대비해서 미리 제 3의 머신을 준비해 놓거나, 혹은 애초에 2개의 복제 서버를 만들어 놓는 것도 방법이 될 수 있다. (위에서 소개한 도구들에서 멀티 혹은 Cascading 스탠바이를 지원하는 것으로 보임)

Failback

기본적으로는 Failback을 위해서 특별한 기능이 제공되지 않는다. 따라서 다음과 같이 번거로운 단계를 거쳐야 한다.

  1. 마스터 서버의 장애가 복구 되면 이 서버를 스탠바이 서버로 구축한다.
  2. 새 마스터 서버(기존 스탠바이 서버)를 강제로 다운시킨다.
  3. 새로 구축된 스탠바이 서버를 다시 마스터 서버로 승격 시킨다.
  4. 스탠바이 서버를 새로 구축한다.

이렇게 복잡한 작업을 하는게 정말 최선인지는 모르겠다. (혹시 다른 도구를 사용하지 않고도 Failback을 더 손쉽게 할 수 있는 방법을 아시는 분은 공유를 부탁드립니다 ㅜㅜ)

번호 제목 날짜 조회 수
561 ntp시간 맞추기 2018.09.12 494
560 ubuntu 커널 업그레이드 방법 2018.09.02 1530
559 oracle to hive data type정리표 2018.08.22 5112
558 postgresql-9.4에서 FATAL: remaining connection slots are reserved for non-replication superuser connections가 나올때 조치 2018.08.16 1421
557 sentry설정 방법및 활성화시 설정이 필요한 파일및 설정값, 계정생성 방법 2018.08.16 1121
556 컬럼및 라인의 구분자를 지정하여 sqoop으로 데이타를 가져오고 hive테이블을 생성하는 명령문 2018.08.03 1083
555 sqoop으로 mariadb에 접근해서 hive 테이블로 자동으로 생성하기 2018.08.03 1292
554 Last transaction was partial에 따른 Unable to load database on disk오류 발생시 조치사항 2018.08.03 4145
553 RHEL 7.4에 zeppelin 0.7.4 설치 2018.07.31 999
552 conda를 이용한 jupyterhub(v0.9)및 jupyter설치 (v4.4.0) 2018.07.30 1049
551 anaconda3 (v5.2) 설치및 머신러닝 관련 라이브러리 설치 절차 2018.07.27 866
550 anaconda3(v5.4)를 이용하여 tensorflow설치후 ipython프로그램을 실행하여 import할때 오류발생시 조치 2018.07.27 352
549 HiveServer2인증을 PAM을 이용하도록 설정하는 방법 2018.07.21 843
» [postgresql 9.x] PostgreSQL Replication 구축하기 2018.07.17 731
547 spark 2.3.0을 설치하가 위해서 parcel에 다음 url을 입력한다. 2018.07.15 400
546 sentry설정후 beeline으로 hive2server에 접속하여 admin계정에 admin권한 부여하기 2018.07.03 761
545 upsert구현방법(년-월-일 파티션을 기준으로) 및 테스트 script file 2018.07.03 2073
544 resouce manager에 dr.who가 아닌 다른 사용자로 로그인 하기 2018.06.28 1729
543 하둡기반 데이타 모델링(6편) 2018.06.27 424
542 CDH에서 Sentry 개념및 설정 file 2018.06.21 754
위로