Last Updated on 6월 25, 2024 by Jade(정현호)
안녕하세요
이번 포스팅글은 MHA(Master High Availability)글의 6번째글로 MHA에서 Failover 동작 시 VIP 전환(Failover)에 대해 Keepalived 를 활용하는 내용으로 2Node(서버) 환경에서 내용을 다루고 있습니다.
Contents
Post Purpose
이번 글의 작성 목표(목적)은 2개 노드(서버)에서 MHA를 통해 서버 측면 고가용성을 사용하는 환경에서 소스(Source,Master,Primary) 인스턴스와 리플리카(Replica,Slave,Secondary)를 접속에 대한, 클라이언트 측면의 고가용성 구현에 관한 내용을 설명하려고 합니다.
MHA에서 스크립트를 수정하여 소스(Source,Master) 인스턴스를 접속을 위한 VIP 구성 및 장애 발생시 다른 서버로의 이동(Failover)을 사용할 수 있습니다.
여기에서 계속 생각되는 부분은 리플리카 인스턴스를 사용하지 않은(소스 인스턴스만 사용하는) Active - Standby(Backup) 같은 구성이 아닌 보통의 사용 유형은 리플리카(Replica,Slave) 인스턴스에서 읽기 쿼리를 수행합니다.
그렇기 때문에 읽기 쿼리 수행이 계속 요청되는 리플리카 인스턴스 접속에 대한 방안 또는 고가용성은 어떻게 구성하는 해야 하는지와 같은 고민이 있을 수 있습니다.
이런 부분을 구현이나 해결하는 방법은 프록시(Proxy), DNS, VIP, L4(로드밸런서) .... 등 아주 다양할 것입니다.
글에서는 그림1과 같이 2노드(서버)환경에서 소스 인스턴스(Source) 와 리플리카(Replica) 인스턴스 모두 각각의 VIP를 사용해서 Writer IP(엔드포인트)로 접속과 Reader IP(엔드포인트)로 접속이 항상 이루어질 수 있도록 구현하는 내용을 담고 있습니다.
[그림1]
사용하는 환경이 1(소스) : N(리플리카) 환경이라면 ProxySQL이나 HAProxy와 같은 Proxy 솔루션 사용에 대한 포스팅을 참고하시면 될 것 같습니다.
이번 포스팅글에서는 1(소스) : 1(리플리카) 와 같이 2개의 노드(서버) 환경에서의 VIP사용에 대한 내용이 기술되어있습니다.
VRRP와 Keepalived
Keepalived에 대해서 이야기하기 전에 먼저 VRRP에 대해서 확인해보도록 하겠습니다.
VRRP(Virtual Router Redundancy Protocol)는 라우터나 게이트웨이에서 사용하기 위해 만들어진 프로토콜로 IBM에서 개발하였으며 1998년 10월에 RFC 2338으로 처음 표준화되었으며, 이후 2002년 RFC 3768, 2010년 RFC 5798으로 개정되었습니다.
VRRP는 두 개 이상의 라우팅 장치에 엔드포인트의 게이트웨이 이중화를 제공할 수 있도록 하는 프로토콜입니다.
즉, 하나의 라우터가 장애가 발생하더라도 다른 라우터가 대신 라우팅 정보를 제공하여 네트워크의 가용성을 높일 수 있습니다.
CISCO에서 만들고 사용하는 독점 프로토콜인 HSRP(Hot Standby Router Protocol)와 유사하지만, VRRP는 여러 벤더에서 사용할 수 있는 오픈 표준 프로토콜입니다.
[Introduction to Virtual Router Redundancy Protocol]
Master-Standby 아키텍처를 사용하여, 하나의 장치가 Master가 되어 라우팅 정보를 제공하고, 다른 장치들은 Standby로 대기합니다.
만약 Master 장치가 장애가 발생하면, Standby 장치 중 하나가 Master가 되어 라우팅 정보를 제공합니다.
VRRP는 다음과 같은 장점이 있습니다.
- 간단한 설정과 관리
- 높은 가용성
- 다양한 네트워크 환경에서 사용 가능
- VRRP는 현재 Cisco, Juniper, HP, Dell 등 다양한 네트워크 장비에서 지원하고 있습니다.
VRRP는 다음과 같은 특징을 가지고 있습니다.
- 가상 IP 주소(VIP)를 사용합니다. VIP는 접속을 위한 엔드포인트 주소입니다.
- VRRP는 224.0.0.18의 IP 주소와 112번 포트를 사용하여 멀티캐스트 패킷을 전송합니다.
- VRRP 광고 패킷(advertisement,멀티캐스트)을 사용하여 장애 감지 및 장애 복구를 수행합니다.
- 지정된 시간동안 Master로 부터 Advertisement가 오지 않으면 Master가 죽은것으로 판단하고 자신이 Master가 되었다고 광고 패킷을 전송하며 VIP를 할당합니다.
Keepalived는 C언어로 작성된 LoadBalancing 및 HA 기능을 제공하는 라우팅 소프트웨어(솔루션)입니다.
이 프로그램의 주요 목표는 Linux 시스템 및 Linux 기반의 인프라에서 로드밸런싱 및 고가용성을 위한 간단하고 강력한 기능 제공하는 것입니다.
로드밸런싱 프레임워크는 널리 사용되고 널리 알려진 Linux Virtual Server(IPVS) 커널 모듈을 통해 Layer4 로드 밸런싱을 제공합니다
또 하나의 주요 기능으로 위에서 설명한 VRRP 프로토콜을 통해서 고가용성(HA)을 기능을 제공합니다.
VRRP(Virtual Router Redundancy Protocol)는 라우터의 장애 조치(Failover)를 위한 기본적인 구성 요소입니다.
가장 빠른 네트워크 오류 감지를 제공하기 위해 Keepalived는 BFD 프로토콜을 구현합니다.
Keepalived는 고가용성 기능 수행을 위해 VIP를 할당(Assign) 및 해제를 직접 수행하며, 하며 장애 발생이 감지가 되면 서비스가 지속될 수 있도록 다른 Standby(backup) Keepalived 서버로 VIP를 Failover(장애조치) 합니다.
[Keepalived VIP Failover]
정리하면 Keepalived의 주요 기능인 고가용성(HA)는 설정된 조건에 따라서 장애 발생시 다른 서버로 VIP를 Failover 하는 기능을 수행합니다. 이번 글에서는 MHA 구성 환경에서 클라이언트의 접속에 대한 고가용성 확보에 Keepalived를 사용할 것입니다.
이와 같이 Keepalived는 주요 기능 중 하나인 고가용성(HA) 기능은 VRRP(Virtual Router Redundancy Protocol)을 통해 구현하고 있으며 포스팅에서는 Keepalived를 사용하여 각 노드(서버)에서 사용되는 VIP의 Failover 구현하였습니다.
Keepalived
Keepalived를 설치 및 설정하도록 하겠습니다.
구성 환경 설명
글의 시스템 환경은 이전 포스팅에서 이어지는 환경으로 다음의 버전과 환경에서 진행하였습니다.
• OS : RockyLinux 8.8(x86_64)
• MySQL 버전 : 8.0.34
• MHA : 0.58(+over)
MHA에서는 VIP를 구성하지 않았습니다.
• Keepalived : v2.1.5
• IP 설정 내역
Server1 - 192.168.56.63 / Hostname: mha1
Server2 - 192.168.56.64 / Hostname: mha2
mha-rw-vip : 192.168.56.67
mha-ro-vip : 192.168.56.68
MySQL 및 MHA 설치 및 구성 및 환경에 대한 정보는 이전 포스팅을 참조하시면 됩니다.
포스팅글 환경은 2개 서버를 사용하며 MHA Manager에서 다음과 같이 설정하였습니다.
[mysql]$ cat app1.cnf [server default] # user&password is DB User user=mha password=mha # ssh_user is OS User ssh_user=mysql # repl_user&repl_password is DB User repl_user=repl repl_password=repl manager_workdir=/home/mysql/mha/app1 manager_log=/home/mysql/mha/app1/app1_manager.log remote_workdir=/home/mysql/mha/app1 master_binlog_dir=/usr/local/mysql/data secondary_check_script=/usr/local/bin/masterha_secondary_check -s mha2 --user=mysql --master_host=mha1 --master_ip=mha1 --master_port=3306 # --user=mysql is os ssh user [server1] hostname=mha1 candidate_master=1 [server2] hostname=mha2 candidate_master=1
포스팅글에서는 MySQL 8 버전으로 진행하였으나 해당 내용은 MySQL 5.6, 5.7버전에서도 동일하게 적용할 수 있는 내용이며, 다른 HA솔루션인 MySQL Orchestrator에서도 동일하게 적용하여 사용할 수 있는 내용입니다.
설치
Keepalived 설치하는 방법은 여러가지가 있으며, 포스팅 글에서 dnf(yum) 패키지 시스템을 통해 설치하였습니다.
사전에 필요 패키지 설치
• CentOS/Oracle Linux 7
sudo yum install -y epel-release sudo yum install -y curl gcc gcc-c++ openssl-devel libnl3-devel net-snmp-devel \ pcre2 pcre2-devel systemd systemd-devel systemd-libs libnftnl libnftnl-devel \ libmnl-devel libmnl kernel-headers kernel-devel ipvsadm \ openssl11-devel openssl11-libs openssl11 rsyslog
• RockyLinux 8
sudo dnf config-manager --set-enabled powertools sudo dnf install -y \ https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm \ https://dl.fedoraproject.org/pub/epel/epel-next-release-latest-8.noarch.rpm sudo dnf install -y curl gcc gcc-c++ openssl-devel libnl3-devel net-snmp-devel \ pcre2 pcre2-devel systemd systemd-devel systemd-libs libnftnl libnftnl-devel \ libmnl-devel libmnl kernel-headers kernel-devel ipvsadm rsyslog
Keepalived 설치
## CentOS/Oracle Linux 7 sudo yum -y install keepalived ## RockyLinux 8 sudo dnf -y install keepalived
버전 확인
## RockyLinux 8 버전 기준 /usr/sbin/keepalived --version Keepalived v2.1.5 (07/13,2020)
방화벽 정책
Keepalived 에서 고가용성을 위해서 VRRP을 사용함에 따라 OS 방화벽이 활성화하여 사용중이라면 224.0.0.18의 IP 주소와 112번 포트를 사용하여 멀티캐스트 패킷에 대해서 허용 설정이 필요 합니다.
또는 정책에 따라서 OS 방화벽을 비활성화하여 사용하지 않는 것도 한가지 방법입니다.
firewalld를 통한 방화벽 사용환경 기준으로 다음과 같이 허용 정책을 설정합니다.
## 방화벽 rule 추가 sudo firewall-cmd --permanent --add-rich-rule='rule family=ipv4 destination address=224.0.0.18/32 protocol value=vrrp accept' ## 저장 sudo firewall-cmd --reload ## 방화벽 정책 조회 sudo firewall-cmd --list-all
Keepalived 로그 설정
keepalived는 기본적으로 로그를 /var/log/messages 기록합니다.
Keepalived 동작에 관한 모니터링시 /var/log/messages 에서 로그를 확인하면 여러 다른 내용이 같이 섞여 있어서 내용 확인이 어려울 수 있습니다. 그래서 가급적이면 로그를 별도의 파일로 분리하는 것이 권장됩니다.
포스팅 글 환경에서 다음과 같이 Keepalived 로그 내용을 별도 파일로 분리하였습니다.
Keepalived 설정 변경
다음과 같이 keepalived 설정파일을 수정합니다.
KEEPALIVED_OPTIONS="-D -d -S 0"
## 파일 편집 sudo vi /etc/sysconfig/keepalived ## 옵션 내용 변경 KEEPALIVED_OPTIONS="-D" to (OPTION 내용을 다음과 같이 변경) KEEPALIVED_OPTIONS="-D -d -S 0"
rsyslog 설정 추가 및 재시작
위와 같이 설정하면 로그 내용을 rsyslog 로 전달하게 됩니다.
이제 rsyslog에서 Keepalived 로그 내용을 저장할 파일 정보를 설정합니다.
참고로 rsyslog 는 keepalived 설치 전에 사전 패키지 설치시 같이 설치를 진행하였습니다.
## 파일 편집 sudo vi /etc/rsyslog.conf ### 아래의 내용을 추가합니다 # Keepalived log local0.* /var/log/keepalived.log
다음과 같이 rsyslog를 재시작합니다. 만약 Keepalived가 시작되어있다면 Keepalived도 같이 재시작을 합니다.
## rsyslog 재시작 systemctl restart rsyslog ## Keepalived가 시작되었을 경우 systemctl restart keepalived
Keepalived 설정
2개 서버 모두 각각 keepalived 설정 파일인 /etc/keepalived/keepalived.conf 편집을 해야합니다.
포스팅글 환경에서 다음과 같이 설정하였습니다.
keepalived.conf
• 서버 1
global_defs { router_id LVS vrrp_skip_check_adv_addr vrrp_strict vrrp_garp_interval 0.1 vrrp_gna_interval 0.1 } vrrp_script check_mysql_health_rw { script "/etc/keepalived/mysql_health_rw_ro_check.sh rw" interval 2 # every 2 seconds fall 2 } vrrp_script check_mysql_health_ro { script "/etc/keepalived/mysql_health_rw_ro_check.sh ro" interval 2 # every 2 seconds fall 2 } vrrp_instance mysql_source { state MASTER interface enp0s8 virtual_router_id 11 priority 101 advert_int 1 #nopreempt #Prevent failback authentication { auth_type PASS auth_pass xxxx } virtual_ipaddress { 192.168.56.67/24 } track_script { check_mysql_health_rw } } vrrp_instance mysql_replica { state BACKUP interface enp0s8 virtual_router_id 12 priority 100 advert_int 1 authentication { auth_type PASS auth_pass xxxx } virtual_ipaddress { 192.168.56.68/24 } track_script { check_mysql_health_ro } }
• 서버 2
global_defs { router_id LVS vrrp_skip_check_adv_addr vrrp_strict vrrp_garp_interval 0.1 vrrp_gna_interval 0.1 } vrrp_script check_mysql_health_rw { script "/etc/keepalived/mysql_health_rw_ro_check.sh rw" interval 2 # every 2 seconds fall 2 } vrrp_script check_mysql_health_ro { script "/etc/keepalived/mysql_health_rw_ro_check.sh ro" interval 2 # every 2 seconds fall 2 } vrrp_instance mysql_source { state BACKUP interface enp0s8 virtual_router_id 11 priority 100 advert_int 1 authentication { auth_type PASS auth_pass xxxx } virtual_ipaddress { 192.168.56.67/24 } track_script { check_mysql_health_rw } } vrrp_instance mysql_replica { state MASTER interface enp0s8 virtual_router_id 12 priority 101 advert_int 1 #nopreempt #Prevent failback authentication { auth_type PASS auth_pass xxxx } virtual_ipaddress { 192.168.56.68/24 } track_script { check_mysql_health_ro } }
설정 내역 요약
위의 설정 내용은 다음과 같습니다.
- vrrp_instance : Keepalived에서는 여러 VIP 및 동작 조건을 설정할 수 있으며 HA 체크 및 Failover 단위가 되는 것이 인스턴스입니다. 포스팅에서는 Source, Replica 를 위한 인스턴스(instance)를 2개 설정하였습니다.
- state : MASTER 또는 BACKUP으로 해당 인스턴스가 구동된 서버가 MASTER(주) 여부를 나타냅니다. 향후 설명할 failback과 관련도 있습니다.
- priority : 우선순위로 MASTER는 BACKUP보다 높게 설정합니다.
- interface : VIP가 할당 및 해제될 이더넷 디바이스명을 지정합니다.
- VIP를 MHA에서 또는 별도로 할당(UP) 하지 않아도 되며, Keepalived가 자동으로 할당과 해제합니다.
- 포스팅글 환경에서는 MHA에서 VIP 구성(설정) 하지 않았습니다.
- authentication : Keepalived의 인스턴스간의 인증을 위해 인증방법 등을 설정하며, 포스팅에서는 PASS 방식으로 하고 패스워드는 xxxx 으로 지정하였습니다.
- track_script : Keepalived 에서 정상 유무(또는 장애발생 여부)를 확인하는데 여러 방법이 있으며 포스팅에서는 별도의 스크립트 형태로 사용하였고 별도 스크립트 형태 또는 리눅스 명령어를 사용할 때 사용하는 것이 track_script 입니다.
- track_script 에서는 vrrp_script 에서 설정한 스크립트명을 입력합니다.
- 실제 수행 내용과 체크 조건 등의 설정은 vrrp_script 에서 지정합니다.
- vrrp_script : 서버의 다운여부나 TCP 체크 외에 실제 서비스나 프로세스의 동작 유무를 체크하기 위해서 명령어나 별도의 스크립트를 통해 체크할 수 있으며 이때 vrrp_script 절을 통해서 설정하여 사용합니다.
- 포스팅 글에서는 vrrp_script 를 통해서 DB 서비스 레벨에서의 Custom Condition 을 설정하여 사용하였습니다.
- 프로세스 리턴 코드 값을 통해서 정상유무를 확인하여 0은 정상 1 또는 다른 값은 오류로 판단합니다.
- nopreempt : MASTER 서버가 정상이 되었을 경우 failback 여부에 대한 설정으로 nopreempt 를 설정하면 failback을 방지합니다. 글에서는 failback 이 이루어지는 것으로 구현하였기 때문에 주석 처리하였습니다.
수치나 명칭 등은 사용환경에 따라서 변경하여 사용하시면 됩니다.
vrrp_script
vrrp_script 에서는 별도로 체크하기 위한 OS 명령어나 스크립트명이 들어가며, 그 외 체크 옵션 등을 설정합니다.
포스팅에서는 Source(Writer), Reaplica(Reader) 용 vrrp_script를 각각 설정하였고 실제로 사용하는 스크립트는 1개로 인자(argument)를 지정하여 사용하였습니다.
- mysql_health_rw_ro_check.sh rw
- mysql_health_rw_ro_check.sh ro
스크립트는 첨부파일 형태로 다운로드 받으시면 됩니다.
• 다운로드
샘플 스크립트에서는 정보 조회하는데 repl 계정을 사용하였으며, MySQL 8.0 명령어(replica)로 작성 되어있습니다.
실제 사용시에는 환경과 버전에 맞게 수정해서 사용하시면 됩니다.
mysql_health_rw_ro_check.sh 스크립트가 가장 중요한 부분이고 스크립트에서 다음과 같은 조건에 따라서 0(정상) 또는 1(오류) 프로세스 리턴 결과를 반환하도록 작성 되어있습니다.
mysql_health_rw_ro_check.sh rw
- read_only 가 0(off) 일 경우 0(정상) 리턴
- 그 외 조건은 1(오류) 리턴
mysql_health_rw_ro_check.sh ro
- show replica status 조회 결과 없음 + read_only가 1(on) : 1(오류)
- show replica status 조회 결과 있음 + read_only가 1(on) : 0(정상)
- show replica status 조회 결과 없음 + show replicas(show slave hosts) 조회 결과 없음 + read_only가 o(off) : 0(정상)
- show replica status 조회 결과 없음 + read_only가 o(off) : 1(오류)
포스팅글에서 설정한 Replica 인스턴스용 체크 정책에 대해서 추가로 설명을 하겠습니다.
1) failover 가 동작 후에 리플리카 인스턴스, 즉 이전 소스 인스턴스가 시작되었을 경우 MHA는 별도로 복제 구성원으로 추가를 해야 합니다. DBA가 Failover 진행된 다음에 후속작업으로 이전 소스 인스턴스(이제 리플리카 인스턴스)에 대해서 CHANGE MASTER(CHANGE REPLICATION SOURCE) 명령어를 수행하여 복제가 구성된 경우 리플리카 인스턴스에 대해서 정상으로 판정하였습니다.
2) 이전 소스 인스턴스(Master)의 서버가 중지 되어있거나, 서버는 시작되었지만 MySQL 인스턴스가 시작되지 않았을 경우에도 리플리카(Reader) VIP를 통해서 Failover로 승격된 새로운 소스 인스턴스(Master)로 접속해서 읽기 업무는 수행되어야 하기 때문에 이 경우에도 정상으로 판정하였습니다.
io_thread 나 sql_thread가 Yes 일 경우도 포함하려고 했으나 복제 에러가 발생하는 경우는 자주 있을 수 있으므로 복제 상태 정보도 판정 condition으로 사용하게 되면 Reader VIP에 대해서 failover(또는 fail) 될 부분이 있어서 해당 condition 은 제외하였습니다.
소스 인스턴스(Writer) 와 리플리카(Reader) 정상 유무에 대한 판단 또는 정책은 운영 환경이나 정책에 따라서 맞게 설정하시면 되며, 위의 조건은 포스팅글에서 예시입니다.
Keepalived 시작 및 VIP확인
다음과 명령어를 통해 Keepalived를 시작하겠습니다.
sudo systemctl start keepalived
참고로 Keepalived 를 통해 할당(Assign)된 VIP는 ifconfig 명령어로는 확인되지 않고 ip 명령어로 확인할 수 있습니다.
• VIP 확인
### 서버 1 $ ip addr show < ... 중략 ... > 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:e1:7e:04 brd ff:ff:ff:ff:ff:ff inet 192.168.56.63/24 brd 192.168.56.255 scope global noprefixroute enp0s8 valid_lft forever preferred_lft forever inet 192.168.56.67/24 scope global secondary enp0s8 <!!--- valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fee1:7e04/64 scope link noprefixroute valid_lft forever preferred_lft forever ### 서버 2 $ ip addr show < ... 중략 ... > 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:f4:a3:86 brd ff:ff:ff:ff:ff:ff inet 192.168.56.64/24 brd 192.168.56.255 scope global noprefixroute enp0s8 valid_lft forever preferred_lft forever inet 192.168.56.68/24 scope global secondary enp0s8 <!!-- valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fef4:a386/64 scope link noprefixroute valid_lft forever preferred_lft forever
위의 조회결과에서 확인할 수 있는 내용처럼 각각 서버에서 설정한 67번, 68번 VIP가 할당 되어있는 것을 확인할 수 있습니다.
Keepalived 로그에서 설정한 스크립트가 정상적으로 체크되었는지 등은 다음과 같이 확인할 수 있습니다.
Keepalived_vrrp[255227]: Script `check_mysql_health_rw` now returning 0 Keepalived_vrrp[255227]: VRRP_Script(check_mysql_health_rw) succeeded
문제가 있다면 returning 1 로 기록됩니다.
2개의 VIP를 통해서 접속을 해보고 서버 정보를 조회해보겠습니다.
• 접속 테스트
[mysql]$ mysql -uroot -proot -h 192.168.56.67 -P 3306 \ > --connect-timeout=1 -se "select @@hostname,@@read_only" @@hostname @@read_only mha1 0 [mysql]$ mysql -uroot -proot -h 192.168.56.68 -P 3306 \ > --connect-timeout=1 -se "select @@hostname,@@read_only" @@hostname @@read_only mha2 1
67번 IP로 접속한 서버는 mha1 이고 read_only=0(off) 로 소스 인스턴스(Writer)인 것을 확인할 수 있으며, 68번 IP로 접속한 서버는 mha2 이고 read_only=1(on) 으로 리플리카 인스턴스(Reader)인 것을 확인할 수 있습니다.
Failover
서버(MySQL서버) 레벨의 고가용성을 위해 MHA는 구성된 상태이고, 클라이언트 접속 가용성을 위해서 Keepalived의 구성을 완료한 상태로 그림1과 같은 상태입니다.
[그림1]
이제 소스 인스턴스(Master)의 장애를 발생시켜서 Failover를 진행하고 그 후 복제 구성원으로 다시 추가하는 후속 작업을 진행하겠습니다. 진행 과정에서 Writer 및 Reader VIP 2개 모두 접속이 어떻게 되는지 확인해보겠습니다.
소스 인스턴스 종료
인스턴스를 종료하도록 하겠습니다.
• 인스턴스 종료
[root]# systemctl stop mysqld or [mysql]# /../../mysql.server stop
Failover 진행간 로그내역
• 서버 1 Keepalived 로그
2개 스크립트 모두 1을 리턴하였습니다.
Keepalived_vrrp[255227]: Script `check_mysql_health_rw` now returning 1 Keepalived_vrrp[255227]: Script `check_mysql_health_ro` now returning 1 Keepalived_vrrp[255227]: A thread timer expired 2.478483 seconds ago Keepalived_vrrp[255227]: VRRP_Script(check_mysql_health_rw) failed (exited with status 1) Keepalived_vrrp[255227]: (mysql_source) Entering FAULT STATE Keepalived_vrrp[255227]: (mysql_source) sent 0 priority Keepalived_vrrp[255227]: (mysql_source) removing VIPs. Keepalived_vrrp[255227]: VRRP_Script(check_mysql_health_ro) failed (exited with status 1) Keepalived_vrrp[255227]: (mysql_replica) Entering FAULT STATE
• 서버 2 Keepalived 로그
rw 스크립트체크에서 0(정상) 리턴 된 것을 확인할 수 있습니다.
Keepalived_vrrp[29514]: Script `check_mysql_health_rw` now returning 0 Keepalived_vrrp[29514]: VRRP_Script(check_mysql_health_rw) succeeded Keepalived_vrrp[29514]: (mysql_source) Entering BACKUP STATE Keepalived_vrrp[29514]: A thread timer expired 2.936710 seconds ago Keepalived_vrrp[29514]: (mysql_source) Receive advertisement timeout Keepalived_vrrp[29514]: (mysql_source) Entering MASTER STATE Keepalived_vrrp[29514]: (mysql_source) setting VIPs. Keepalived_vrrp[29514]: (mysql_source) Sending/queueing gratuitous ARPs on enp0s8 for 192.168.56.67 Keepalived_vrrp[29514]: Sending gratuitous ARP on enp0s8 for 192.168.56.67 Keepalived_vrrp[29514]: Sending gratuitous ARP on enp0s8 for 192.168.56.67 Keepalived_vrrp[29514]: A thread timer expired 6.332331 seconds ago Keepalived_vrrp[29514]: (mysql_source) Sending/queueing gratuitous ARPs on enp0s8 for 192.168.56.67 Keepalived_vrrp[29514]: Sending gratuitous ARP on enp0s8 for 192.168.56.67 Keepalived_vrrp[29514]: A thread timer expired 6.340226 seconds ago Keepalived_vrrp[29514]: Sending gratuitous ARP on enp0s8 for 192.168.56.67
• MHA Failover 수행 결과
mha2 서버로 정상적으로 Failover 되어 새로운 Source 인스턴스가 된 것을 확인할 수 있습니다.
Started automated(non-interactive) failover. The latest slave mha2(192.168.56.64:3306) has all relay logs for recovery. Selected mha2(192.168.56.64:3306) as a new master. mha2(192.168.56.64:3306): OK: Applying all logs succeeded. Generating relay diff files from the latest slave succeeded. mha2(192.168.56.64:3306): Resetting slave info succeeded. Master failover to mha2(192.168.56.64:3306) completed successfully. <!!-- mha2 서버로 정상적으로 Failover
• VIP 확인
소스 인스턴스(Writer) VIP 67번이 서버 2로 Failover 되어 할당된 것 확인할 수 있으며, 서버1에는 VIP가 없는 것이 확인됩니다.
### 서버 1 $ ip addr show <...중략...> 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:e1:7e:04 brd ff:ff:ff:ff:ff:ff inet 192.168.56.63/24 brd 192.168.56.255 scope global noprefixroute enp0s8 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fee1:7e04/64 scope link noprefixroute valid_lft forever preferred_lft forever ### 서버 2 $ ip addr show <...중략...> 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:f4:a3:86 brd ff:ff:ff:ff:ff:ff inet 192.168.56.64/24 brd 192.168.56.255 scope global noprefixroute enp0s8 valid_lft forever preferred_lft forever inet 192.168.56.68/24 scope global secondary enp0s8 valid_lft forever preferred_lft forever inet 192.168.56.67/24 scope global secondary enp0s8 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fef4:a386/64 scope link noprefixroute valid_lft forever preferred_lft forever
• VIP로 접속 및 조회
다시 VIP로 접속 및 조회를 해보겠습니다. VIP 2개 모두 동일한 인스턴스에 접속되어 쿼리가 수행된 것을 확인할 수 있습니다.
[mysql]$ mysql -uroot -proot -h 192.168.56.67 -P 3306 \ > --connect-timeout=1 -se "select @@hostname,@@read_only" @@hostname @@read_only mha2 0 [mysql]$ mysql -uroot -proot -h 192.168.56.68 -P 3306 \ > --connect-timeout=1 -se "select @@hostname,@@read_only" @@hostname @@read_only mha2 0
[그림2]
시스템은 현재 그림2와 같이 장애 처리(Failover)가 수행된 상태입니다.
복제 구성
중지된(장애가 발생한) 소스 인스턴스는 이제 복제 구성원으로 리플리카 인스턴스로 설정해야 합니다.
먼저 중지된 MySQL 인스턴스를 시작하겠습니다.
• MySQL 인스턴스 시작
[root]# systemctl start mysqld or [mysql]# /../../mysql.server start
• vip 확인
MySQL을 시작했지만 스크립트에서 설정한 정책에 따라 복제 설정이 되어 있지 않기 때문에 리플리카(Reader) VIP는 Failover가 되지 않고 여전히 서버 2에서 2개의 VIP가 모두 존재하는 것을 확인할 수 있습니다.
### 서버 2 $ ip addr show <...중략...> 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:f4:a3:86 brd ff:ff:ff:ff:ff:ff inet 192.168.56.64/24 brd 192.168.56.255 scope global noprefixroute enp0s8 valid_lft forever preferred_lft forever inet 192.168.56.68/24 scope global secondary enp0s8 valid_lft forever preferred_lft forever inet 192.168.56.67/24 scope global secondary enp0s8 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fef4:a386/64 scope link noprefixroute valid_lft forever preferred_lft forever
• 복제 설정 및 시작
복제 멤버로 구성하기 위해 1번 서버의 인스턴스에서 복제 설정 및 복제 시작을 하도록 하겠습니다.
-- 복제 설정 mysql> CHANGE REPLICATION SOURCE TO SOURCE_HOST='mha2', SOURCE_PORT=3306, SOURCE_LOG_FILE='binlog.000008', SOURCE_LOG_POS=157, SOURCE_USER='repl', SOURCE_PASSWORD='repl'; -- 복제 시작 mysql> start replica; -- 복제 상태 확인 mysql> show replica status\G
• Keepalived 로그 확인
서버 1에서는 check_mysql_health_ro 가 정상(0)으로 체크되고 서버 2에서 오류(1)로 체크되는 것을 확인할 수 있습니다.
## 서버 1의 keepalived 로그 Keepalived_vrrp[659647]: Script `check_mysql_health_ro` now returning 0 Keepalived_vrrp[659647]: VRRP_Script(check_mysql_health_ro) succeeded Keepalived_vrrp[659647]: (mysql_replica) Entering BACKUP STATE Keepalived_vrrp[659647]: (mysql_replica) Receive advertisement timeout Keepalived_vrrp[659647]: (mysql_replica) Entering MASTER STATE Keepalived_vrrp[659647]: (mysql_replica) setting VIPs. Keepalived_vrrp[659647]: (mysql_replica) Sending/queueing gratuitous ARPs on enp0s8 for 192.168.56.68 Keepalived_vrrp[659647]: Sending gratuitous ARP on enp0s8 for 192.168.56.68 Keepalived_vrrp[659647]: (mysql_replica) Master received advert from 192.168.56.64 with higher priority 101, ours 100 Keepalived_vrrp[659647]: (mysql_replica) Entering BACKUP STATE Keepalived_vrrp[659647]: (mysql_replica) removing VIPs. ## 서버 2의 keepalived 로그 Keepalived_vrrp[29514]: Script `check_mysql_health_ro` now returning 1 Keepalived_vrrp[29514]: A thread timer expired 2.950823 seconds ago Keepalived_vrrp[29514]: A thread timer expired 2.755446 seconds ago Keepalived_vrrp[29514]: (mysql_replica) Received advert from 192.168.56.63 with lower priority 100, ours 101 Keepalived_vrrp[29514]: A thread timer expired 2.757521 seconds ago Keepalived_vrrp[29514]: VRRP_Script(check_mysql_health_ro) failed (exited with status 1) Keepalived_vrrp[29514]: (mysql_replica) Entering FAULT STATE Keepalived_vrrp[29514]: (mysql_replica) sent 0 priority Keepalived_vrrp[29514]: (mysql_replica) removing VIPs.
• VIP 확인
서버 1에서 VIP를 확인하면 Reader VIP인 68번이 Failover 되어 할당된 것을 확인할 수 있습니다.
[mysql]$ ip addr show <...중략...> 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:e1:7e:04 brd ff:ff:ff:ff:ff:ff inet 192.168.56.63/24 brd 192.168.56.255 scope global noprefixroute enp0s8 valid_lft forever preferred_lft forever inet 192.168.56.68/24 scope global secondary enp0s8 <!!-- valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fee1:7e04/64 scope link noprefixroute valid_lft forever preferred_lft forever
• VIP로 접속 및 조회
다시 VIP로 접속 및 조회를 해보겠습니다. VIP 2개 모두 접속이 되며 처음과 반대의 서버로 접속된 것을 확인할 수 있습니다.
- 67번 IP : 서버2, read_only=0(off)
- 68번 IP : 서버1, read_only=1(on)
[mysql]$ mysql -uroot -proot -h 192.168.56.67 -P 3306 \ --connect-timeout=1 -se "select @@hostname,@@read_only" @@hostname @@read_only srv2 0 [mysql]$ mysql -uroot -proot -h 192.168.56.68 -P 3306 \ --connect-timeout=1 -se "select @@hostname,@@read_only" @@hostname @@read_only srv1 1
[그림3]
최종적으로 시스템은 현재 그림3과 같은 상태로 Failover 와 후속 작업이 모두 완료된 상태입니다.
이번 포스팅에서는 MySQL MHA 2 node(서버) 환경에서 클라이언트 접속의 고가용성 Keepalived를 사용하여 구현 및 내용 확인해보았습니다.
1:N 구조와 마찬가지로 Proxy를 사용해도 가능하지만 별도의 추가 서버나 솔루션 없이 MySQL 서버내에서 간단하게 클라이언트 접속 고가용성 구성을 하고자 Keepalived를 사용하였습니다.
이번 글은 여기에서 마무리하도록 하겠습니다.
긴 글 읽어주셔서 감사합니다.
Reference
Reference URL
• wikipedia.org/Virtual_Router_Redundancy_Protocol
• keepalived.org
관련된 다른 글
Principal DBA(MySQL, AWS Aurora, Oracle)
핀테크 서비스인 핀다에서 데이터베이스를 운영하고 있어요(at finda.co.kr)
Previous - 당근마켓, 위메프, Oracle Korea ACS / Fedora Kor UserGroup 운영중
Database 외에도 NoSQL , Linux , Python, Cloud, Http/PHP CGI 등에도 관심이 있습니다
purityboy83@gmail.com / admin@hoing.io