본문 바로가기

Database/PostgreSQL

PostgreSQL HA 구성 - 3. PGPool을 활용한 FailOver 구현

반응형

pgpool.conf Configuration II

이전 포스트 'PostgreSQL HA 구성 - 2. PGPool을 활용한 Load Balance 구현' 에서 PGPool이 제공하는 기능 중 Failover, Failback이 있었다고 했다. 이를 활성화 하기 위해서는 pgpool.conf를 수정해야 하는데 대부분의 내용은 이전 장에 거의 다 되있다. 제일 중요한 설정 내용이 'backend_flag' 인자를 ALLOW_TO_FAILOVER로 하는 것이고, 그외에는 아래 내용이 포함되야 한다.

...
#------------------------------------------------------------------------------
# FAILOVER AND FAILBACK
#------------------------------------------------------------------------------

failover_command = '/usr/pgsql-9.6/share/failover.sh %d %H /var/lib/pgsql/9.6/data/failover_trigger'
...

위 내용은 PGPool에서 DB Server 중 1 대에서 이상 현상을 감지했을 때 실행할 명령을 정의한 것이다. 즉, /usr/pgsql-9.6/share에 위치한 failover.sh script를 실행시키게 설정했으며 parameter로 %d, %H,  /var/lib/pgsql/9.6/data/failover_trigger를 사용한다. 이 중 %d, %H와 같은 parameter는 PGPool에서 전달할 수 있는 인자들로, PGPool은 아래와 같이 제공하고 있고, 우리는 이상 현상이 감지된 Server와 새로 Master Server가 될 Server 정보를 위해 %d, %H를 사용하였다.

    • PGPool에서 제공하는 Paramter
      • %d : node id. 이벤트 Trigger를 발생한 Node의 ID.
      • %h : host name.  이벤트 Trigger를 발생한 Node의 Host먕이나 IP
      • %p : port number. 이벤트 Trigger를 발생한 Node의 Port
      • %D : database cluster path. 이벤트 Trigger를 발생한 Node의 Cluster Path
      • %n : new master node id. 새로 Master가 될 Node의 ID
      • %H : hostname of the new master node. 새로 Master가 될 Node의 Host명이나 IP.
      • %M : old master node id. 이전 Master Node ID (%P와 차이를 잘 모르겠다.)
      • %P : old primary node id. 이전 Primary Node ID (%M과 차이를 잘 모르겠다.)
      • %r : new master port number. 새로운 Master 서버의 Port Number
      • %R : new master database cluster path. 새로운 Master 서버의 Cluster Path.
      • %% : '%' character

그리고 3번쨰 Parameter인 /var/lib/pgsql/9.6/data/failover_trigger 는 'PostgreSQL HA 구성 -1. Streaming Replication'에서 recovery.conf에서 Trigger File 인자의 값으로 설정한 사항이다. Standby Server는 이 Trigger File의 존재여부를 Check하고 있다가 해당 파일을 인지하는 순간 Replication을 멈추고 Primary Server로 전환한다


failover.sh 작성

위에서 언급한 failover.sh는 pgpool 문서에서 예제나 Boilermake Code를 제공해 주지 않기 때문에 직접 작성해야 한다. 필자는 아래와 같이 작성하였다.

if [ $# -ne 3 ]
then
        echo "failover failed_node new_master trigger_file"
        exit 1
fi

FAILED_NODE=$1
NEW_MASTER=$2
TRIGGER_FILE=$3

# Do nothing if standby server goes down
if [$FAILED_NODE = 1]; then
        echo "Standby Server is downed\n" >> /usr/pgpool-9.6/log/failover.log
        exit 0
fi

echo "failover.sh FAILED_NODE:${FAILED_NODE}; NEW_MASTER:${NEW_MASTER}; at $(date)\n" >> /usr/pgpool-9.6/log/failover.log

sudo -u postgres ssh -T postgres@$NEW_MASTER touch $TRIGGER_FILE

exit 0

간단히 Script 내용을 설명하면 다음과 같다. Parameter가 3개가 아니거나 이상 Server가 Standby Server일 경우에도 별다른 동작을 수행하지 않고 빠져나가고, Primary Server이상으로 인한 Failover 시에 SSH를 통해 Standby Server에 Trigger File을 생성하게 된다. 위의 Script를 저장 후에 권한을 아래와 같이 변경한다.

...
[root@ha-test-1 /]# chmod 755 /usr/pgsql-9.6/share/failover.sh 
...

여기까지 하면 기본 설정은 마무리 되게 되는데 실제 Failover Operation이 이루어 지지 않을 것이다. 그 이유는 SSH로 원격지에서 명령어를 실행할 때 Password 입력을 통한 인증 절차가 필요한데, PGPool에서는 이런 과정이 이루어지지 않아 Script에 명시된 touch 명령이 실행되지 않는다.


SSH 인증 설정

Password 입력 과정 없이 SSH를 통해 원격으로 명령을 실행시키려면 접속하려는 Client Side(이 Post에서는 HA-1)에서 RSA key를 생성한 후
Public Key를 Server Side(HA-2)에 복사하는 과정이 필요하다. 아래 내용을 참고하면 되고 관련 자료도 많으니 좀 더 자세한 내용을 원하면 찾아보길 권장한다.


우선 ssh-keygen으로 SSH Key를 생성한다. 별다른 값을 입력하지 않으면 {사용자 Root 폴더}/.ssh 아래에 Key가 만들어 지게 된다. (Password도 별다른 입력없이 넘어갔다.)

...
[postgres@ha-test-1 /]$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/var/lib/pgsql/.ssh/id_rsa): 
Created directory '/var/lib/pgsql/.ssh'.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /var/lib/pgsql/.ssh/id_rsa.
Your public key has been saved in /var/lib/pgsql/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:D7NRHcy79fSuun6J7xqJozi9hC/OHPe3lHLVQALkMtY postgres@ha-test-2
The key's randomart image is:
+---[RSA 2048]----+
|         .o+o .  |
|         o .o+   |
|        + E ...  |
|       . +  . .o.|
|        S    o.oo|
|       . * ..+  o|
|      o.+ = *. o |
|     oo*.o =o.o .|
|     .=o+..o*O+. |
+----[SHA256]-----+

실행이후 해당 디렉토리를 조회하면 아래와 같이 3개의 파일이 확인된다.

...
[postgres@ha-test-1 /]$ ls -l -a /var/lib/pgsql/.ssh/
합계 16
drwx------. 2 postgres postgres   57 10월 16 14:56 .
drwx------. 6 postgres postgres 4096 10월 16 14:54 ..
-rw-------. 1 postgres postgres 1675 10월 16 14:55 id_rsa
-rw-r--r--. 1 postgres postgres  400 10월 16 14:55 id_rsa.pub
-rw-r--r--. 1 postgres postgres  173 10월 16 14:56 known_hosts
...

이 중에서 public key 파일인 id_rsa.pub를 서버에 등록하면 된다. 매우 다행스럽게 RHEL 7 계열에서는 ssh-copy-id 명령문으로 이 작업이 손쉽게 이루어 진다. (예전에는 좀 더 귀찮은 과정을 거쳐야했다) 아래가 실행 결과 이다.

...
[postgres@ha-test-1 /]$ ssh-copy-id postgres@16.8.35.228
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/var/lib/pgsql/.ssh/id_rsa.pub"
The authenticity of host '16.8.35.228 (16.8.35.228)' can't be established.
ECDSA key fingerprint is SHA256:Z9qkn9wWNCJ9aPT4NuCpYlWfdOf1Leq0yewOPih35Go.
ECDSA key fingerprint is MD5:f1:a8:72:67:fe:94:1e:53:55:8b:03:98:8f:e1:80:b7.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
postgres@16.8.35.228's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'postgres@16.8.35.228'"
and check to make sure that only the key(s) you wanted were added.
...

그리고 Server Side(HA-2)에 들어가서 폴더를 확인해보면 postgres 사용자의 Root Directory에 .ssh 폴더가 생성되어 있고 거기에authorized_keys 라는 파일이 만들어져 있는 것을 확인할 수 있다. 이게 HA-1에서 만들어진 3개의 File 중 id_rsa.key 파일이다.

...
[postgres@ha-test-2 /]$ ls -l -a /var/lib/pgsql/
합계 20
drwx------. 7 postgres postgres 4096 10월 16 15:01 .
drwxr-xr-x. 4 root     root       34  9월 28 23:01 ..
-rw-------. 1 postgres postgres 1036 10월 15 15:41 .bash_history
-rw-r--r--. 1 postgres postgres   18  10월 25  2018 .bash_logout
-rw-r--r--. 1 postgres postgres  193  9월 11  2018 .bash_profile
-rw-r--r--. 1 postgres postgres  231  9월 11  2018 .bashrc
drwxrwxr-x. 3 postgres postgres   18 9월  17 15:00 .cache
drwxrwxr-x. 3 postgres postgres   18 9월  17 15:00 .config
drwx------. 2 postgres postgres   29 10월 16 14:55 .ssh
drwxrwxr-x. 3 postgres postgres   36 9월  11 18:23 9.6
...
[postgres@ha-test-2 /]$ ls -l -a /var/lib/pgsql/.ssh
합계 8
drwx------. 2 postgres postgres   29 10월 16 14:55 .
drwx------. 7 postgres postgres 4096 10월 16 15:01 ..
-rw-------. 1 postgres postgres  400 10월 16 14:55 authorized_keys
...

SSH 명령어가 Password 입력 과정없이 진행되는 지 Test 해보자. HA1에서 SSH를 통해 HA2에 File을 생성하는 예이다.

...
[postgres@ha-test-1 /]$ ssh -T postgres@16.8.35.228 touch /tmp/test
...

HA2에서 해당 위치를 확인해 보니 파일이 만들어 진 것을 확인할 수 있다.

...
[postgres@ha-test-2 /]$ ls -l -a /tmp/test
-rw-rw-r--. 1 postgres postgres 0 10월 16 15:04 /tmp/test
...

Failover Test

이제 PGPool로 Failover 동작을 테스트 해보겠다. Primary-Stanby가 잘 동작하고 있는 지 show pool_nodes; 명령을 통해서 확인해 보았다.

...
postgres=# show pool_nodes;
 node_id |  hostname   | port | status | lb_weight |  role   | select_cnt | load_balance_node | replication_delay 
---------+-------------+------+--------+-----------+---------+------------+-------------------+-------------------
 0       | 16.8.35.227 | 5432 | up     | 0.500000  | primary | 0          | false             | 0
 1       | 16.8.35.228 | 5432 | up     | 0.500000  | standby | 0          | true              | 0
(2개 행)
...

이제 Primary DB를 정지 시킨다.

...
[postgres@ha-test-1 /]$ systemctl stop postgresql-9.6.service 
[postgres@ha-test-1 /]$ systemctl status postgresql-9.6.service 
● postgresql-9.6.service - PostgreSQL 9.6 database server
   Loaded: loaded (/usr/lib/systemd/system/postgresql-9.6.service; enabled; vendor preset: disabled)
   Active: inactive (dead) since 화 2018-10-16 18:57:41 KST; 4min 33s ago
     Docs: https://www.postgresql.org/docs/9.6/static/
  Process: 7679 ExecStart=/usr/pgsql-9.6/bin/postmaster -D ${PGDATA} (code=exited, status=0/SUCCESS)
  Process: 7669 ExecStartPre=/usr/pgsql-9.6/bin/postgresql96-check-db-dir ${PGDATA} (code=exited, status=0/SUCCESS)
 Main PID: 7679 (code=exited, status=0/SUCCESS)

이후 Log를 통해 Standby Server의 동작을 확인해 보면 이전에 동작하던 Streaming Replication이 갑자기 Primary Server를 연결할 수 없다고 하고 이후 Trigger File을 인지한 후에 Master Server 역할을 수행하는 과정을 보여준다.

...
[postgres@ha-test-2 /]# tail -f /var/lib/pgsql/9.6/data/pg_log/postgresql-Tue.log 
...
< 2018-10-16 18:55:07.035 KST > 로그:  데이터베이스 시스템이 읽기 전용으로 연결을 수락할 준비가 되었습니다.
< 2018-10-16 18:55:07.041 KST > 로그:  주 서버의 WAL 스트리밍 시작 위치: 0/11000000 (타임라인 1)
< 2018-10-16 18:56:24.217 KST > 로그:  주 서버에 의해서 복제가 끝남
< 2018-10-16 18:56:24.217 KST > 상세정보:  타임라인 1, 위치 0/110000D0 에서 WAL 끝에 도달함
< 2018-10-16 18:56:24.217 KST > 치명적오류:  주 서버로 스트리밍 종료 메시지를 보낼 수 없음: 처리 가운데 COPY가 없음
	
< 2018-10-16 18:56:24.218 KST > 로그:  잘못된 레코드 길이: 0/110000D0, 기대값 24, 실재값 0
< 2018-10-16 18:56:24.221 KST > 치명적오류:  주 서버에 연결 할 수 없음: 서버에 연결할 수 없음: 연결이 거부됨
		"16.8.35.227" 호스트에 서버가 가동 중인지,
		5432 포트로 TCP/IP 연결이 가능한지 살펴보십시오.
	
< 2018-10-16 18:56:29.223 KST > 로그:  트리거 파일이 있음: /var/lib/pgsql/9.6/data/failover_trigger
< 2018-10-16 18:56:29.223 KST > 로그:  0/11000060에서 redo 작업 완료
< 2018-10-16 18:56:29.364 KST > 로그:  지정한 새 타임라인 ID: 2
< 2018-10-16 18:56:29.725 KST > 로그:  아카이브 복구 완료
< 2018-10-16 18:56:29.876 KST > 로그:  멀티 트랜잭션 번호 겹침 방지 기능이 활성화 되었음
< 2018-10-16 18:56:29.878 KST > 로그:  이제 데이터베이스 서버로 접속할 수 있습니다
< 2018-10-16 18:56:29.878 KST > 로그:  autovacuum 실행기가 시작됨
...

Standby Server의 Data 폴더를 보면 이전에 recovery.conf로 만들어 놓은 파일이 recovery.done으로 변경되어 있는 것을 확인할 수 있다.

...
[postgres@ha-test-2 /]$ ls -l -a /var/lib/pgsql/9.6/data
합계 80
drwx------. 20 postgres postgres  4096 10월 16 18:56 .
drwx------.  4 postgres postgres    51 10월  4 15:21 ..
...
-rw-------.  1 postgres postgres 22292 10월 16 18:54 postgresql.conf
-rw-------.  1 postgres postgres    87 10월 16 18:55 postmaster.pid
-rw-r--r--.  1 postgres postgres   188 10월 16 18:54 recovery.done
...

'show pool_nodes;' 명령을 다시 실행해보면 두 서버 모두 status가 up인 상태에서 이전 Primary Server Status가 down으로 변경되어 있고 (역할도 standby server로 변경되어 있다.) 이전 StandBy Server가 Primary Server로 동작함을 확인할 수 있다.

...
postgres=# show pool_nodes;
 node_id |  hostname   | port | status | lb_weight |  role   | select_cnt | load_balance_node | replication_delay 
---------+-------------+------+--------+-----------+---------+------------+-------------------+-------------------
 0       | 16.8.35.227 | 5432 | down   | 0.500000  | standby | 0          | false             | 0
 1       | 16.8.35.228 | 5432 | up     | 0.500000  | primary | 0          | true              | 0
(2개 행)
...
postgres=# \c dwarf postgres;
접속정보: 데이터베이스="dwarf", 사용자="postgres".
dwarf=# select * from public.star;
 id | name | class | age  | radius | lum | magnt 
----+------+-------+------+--------+-----+-------
  1 | Sun  | G2V   | 4500 |   1391 |   5 |     1
(1개 행)
...

참조