Split Brain 은 Clustering 또는 다중 노드/스토리지 구성의 각종 솔루션들(주로 고가용성과 부하분산, 즉 HA 용도), 예를 들어 Redis-Sentinel, MariaDB Galera Cluster, GlusterFS 파일 분산복제 설정, Oracle RAC, vSphere HA 구성 등에서 중요한 장애 유발 요인이며, Production 환경에서 점검해야 할 중요한 아키텍처적 회피 대상 항목에 해당한다.




1. Split Brain 이 도대체 무엇일까?


문자 그대로 "뇌가 양쪽으로 분단 된" 모양 또는 상황 그자체를 표현한다. IT와 무관한 비유를 해 보자면, 머리 둘 달린 용이 왼쪽으로 갈지 오른쪽으로 갈지 몰라서 갈팡질팡하는 형국이라고 할 수도 있겠다. 실제로 인간의 뇌는 좌뇌와 우뇌로 구성되는데, 양쪽 뇌를 연결해주는 '뇌량'을 절단해 버리면 왼쪽 뇌와 오른쪽 뇌의 인지 부조화와 같은 심각한 부작용이 나타난다고 알려져 있다.


이번 글에서는 MySQL 호환 데이터베이스 클러스터링 솔루션인 MariaDB Galera Cluster 의 기본 3대 구성에서 장애/점검 등을 이유로 1 대가 빠진 상태를 구체적인 예를 들어 설명해 보도록 한다. 3대 구성이 기본인 이유는, Leader 의 선출(투표에 의한)시 과반수 이상의 득표가 가능한 구조여야 하기 때문이다. 즉 3명(Quorom[각주:1]=3)이 투표에 참여하여 2 이상의 득표자가 Leader가 되는 경우를 생각해 보면 되겠다.   



위의 첫 번 째 그림은 전형적인 Split Brain 의 가능성이 내재된 상황을 표현하고 있다. 그렇다면 이 상황에서 100% Split Brain 이 발생한다고 단정할 수 있는가 하면 그건 아니다. 즉 물리적인 연결 구성과 함께 Network Topology를 보고 판단해야 하기 때문이다. 다음 그림을 보자.



만약 처음에 보았던 논리적 Diagram의 실제 네트워크 구성이 이 그림과 같이 단일 네트워크로 이루어져 있고 DB Client(또는 WAS)에서 Load Balancer를 거쳐서 Galera-1, Galera-2 로 접속이 되는 방식이라면, Split Brain은 발생하지 않는다. 따라서 Galera-1 서버가 다운되거나 네트워크 접속이 끊기면, DB Client는 정상적으로 Galera-2 로 접속되고 Galera-2는 자신을 DB Master로 인식하여 정상 작동을 하게 된다. 위의 구성도를 Topology로 표현하면 아래의 그림과 유사한 모양이 된다.




그렇다면 도대체 어떤 상황에서 Split Brain 이 발생할 수 있다는 말일까? 다음의 2개의 그림이 바로 그에 대한 답이 된다.



위의 네트워크 구성도에서, Galera-1과 Galera-2 사이의 데이터 복제 및 Alive-check는 Switch-2의 DB망을 통해서 이루어 지며, 실제 Production 환경에서의 전형적 네트워크 구성도의 예시를 들어 보자면 개략적으로 다음 그림과 같은 모습이 될 것이다.




위의 2가지 네트워크 구성도의 Topology를 그려 보면, 공통적으로 아래의 그림과 같이 나타난다. 이 상황에서 Galera-1, Galera-2 사이의 경로가 끊어지면, 바로 Split Brain 상황이 발생하게 되는데, DB Client 입장에서는 2개 DB 모두로의 접속 자체는 가능하지만, 데이터베이스 관련 각종 쿼리(use database, select, insert 문 등)가 실패 되는 현상이 발생하게 된다. 다시 전문용어를 써서 상세히 표현하자면, "네트워크의 부분적인 장애로 DB접속자(Client, WAS)에게는 2개의 DB 서버 모두 정상적으로 보이지만, 각 DB 서버는 상대방이 비정상이라고 판단하여 데이터 동기화 및 읽기 쓰기가 비정상 상태에 빠지는 것" 이라고 할 수 있으며, 다른 말로 Network Partition 또는 Cluster Partition 이라고도 한다.


위의 구성도를 Topology로 표현하면 아래의 그림과 유사한 모양이 된다.




2. 정상적 Cluster 구성상태의 점검/확인 방법


* MariaDB Galera Cluster 의 설치 과정은 다음 링크를 참고한다

☞ http://bryan.wiki/246


위의 섹션 1에서 Split-Brain 상황이 발생한 구조와 같이 2대의 MariaDB를 사용하는 경우(3대 중 1대의 동작이 중지되어 2대가 남은 상태)와 동일한 구성을 갖추기 위해 다음의 2개 VM을 준비하고 /etc/my.cnf.d/server.cnf 내용을 각각 설정하여 정상적인 2대 구성의 Cluster 환경을 갖춘다. 



[maria1]

  • CentOS 7.3, MariaDB-server
  • NIC1(ens160): 192.168.30.105 - DB Client와 DB간 연결 네트워크
  • NIC2(ens192): 10.199.30.105 - DB간 연결 네트워크

#

# * Galera-related settings

#

[galera]

# Mandatory settings

wsrep_on=ON

wsrep_provider=/usr/lib64/galera/libgalera_smm.so

wsrep_cluster_address='gcomm://'

#wsrep_cluster_address='gcomm://10.199.30.105,10.199.30.106'

wsrep_cluster_name='galera'

wsrep_node_address='10.199.30.105'

wsrep_node_name='maria1'

wsrep_sst_method=rsync


binlog_format=row

default_storage_engine=InnoDB

innodb_autoinc_lock_mode=2

#

# Allow server to accept connections on all interfaces.

#

bind-address=0.0.0.0

#

# Optional setting

#wsrep_slave_threads=1

innodb_flush_log_at_trx_commit=2



[maria2]

  • CentOS 7.3, MariaDB-server
  • NIC1(ens160): 192.168.30.106 - DB Client와 DB간 연결 네트워크
  • NIC2(ens192): 10.199.30.106 - DB간 연결 네트워크

#

# * Galera-related settings

#

[galera]

# Mandatory settings

wsrep_on=ON

wsrep_provider=/usr/lib64/galera/libgalera_smm.so

wsrep_cluster_address='gcomm://10.199.30.105,10.199.30.106'

wsrep_cluster_name='galera'

wsrep_node_address='10.199.30.106'

wsrep_node_name='maria2'

wsrep_sst_method=rsync


binlog_format=row

default_storage_engine=InnoDB

innodb_autoinc_lock_mode=2

#

# Allow server to accept connections on all interfaces.

#

bind-address=0.0.0.0

#

# Optional setting

#wsrep_slave_threads=1

innodb_flush_log_at_trx_commit=2



Cluster의 정상적인 동작상황에서는 다음의 4가지 점검 사항을 확인해 보고, 필요 시 튜닝 또는 설정값 조정을 진행해야 한다.


1. Cluster Integrity Check

 Maria1

Maria2 

select * from information_schema.GLOBAL_STATUS where VARIABLE_NAME like 'wsrep_cluster_state_uuid' or VARIABLE_NAME like 'wsrep_cluster_conf_id' or VARIABLE_NAME like 'wsrep_cluster_size' or VARIABLE_NAME like 'wsrep_cluster_status';

+--------------------------+--------------------------------------+

| VARIABLE_NAME | VARIABLE_VALUE |

+--------------------------+--------------------------------------+

| WSREP_CLUSTER_CONF_ID | 2 |

| WSREP_CLUSTER_SIZE | 2 |

| WSREP_CLUSTER_STATE_UUID | b04a71b5-161b-11e7-b1e1-bbd969deabbb |

| WSREP_CLUSTER_STATUS | Primary |

+--------------------------+--------------------------------------+

select * from information_schema.GLOBAL_STATUS where VARIABLE_NAME like 'wsrep_cluster_state_uuid' or VARIABLE_NAME like 'wsrep_cluster_conf_id' or VARIABLE_NAME like 'wsrep_cluster_size' or VARIABLE_NAME like 'wsrep_cluster_status';

+--------------------------+--------------------------------------+

| VARIABLE_NAME | VARIABLE_VALUE |

+--------------------------+--------------------------------------+

| WSREP_CLUSTER_CONF_ID | 2 |

| WSREP_CLUSTER_SIZE | 2 |

| WSREP_CLUSTER_STATE_UUID | b04a71b5-161b-11e7-b1e1-bbd969deabbb |

| WSREP_CLUSTER_STATUS | Primary |

+--------------------------+--------------------------------------+

 수행결과 캡처

 


 항목별 점검/확인 포인트

  • WSREP_CLUSTER_STATE_UUID : 모든 노드에서 동일해야 함. 값이 다른 노드는 Cluster 에서 제외되었음을 의미
  • WSREP_CLUSTER_CONF_ID : 위와 같음. 단 Cluster가 단절되었다가 복구될 때마다 +1 씩 값이 증가함
  • WSREP_CLUSTER_SIZE : Cluster 내의 노드 갯수
  • WSREP_CLUSTER_STATUS : 모든 쓰기 가능한 노드는 Primary 이어야 함



2. Node Status Check

 Maria1

Maria2 

select * from information_schema.GLOBAL_STATUS where VARIABLE_NAME like 'wsrep_ready' or VARIABLE_NAME like 'wsrep_connected' or VARIABLE_NAME like 'wsrep_local_state_comment';

+---------------------------+----------------+

| VARIABLE_NAME | VARIABLE_VALUE |

+---------------------------+----------------+

| WSREP_CONNECTED | ON |

| WSREP_LOCAL_STATE_COMMENT | Synced |

| WSREP_READY | ON |

+---------------------------+----------------+

select * from information_schema.GLOBAL_STATUS where VARIABLE_NAME like 'wsrep_ready' or VARIABLE_NAME like 'wsrep_connected' or VARIABLE_NAME like 'wsrep_local_state_comment';

+---------------------------+----------------+

| VARIABLE_NAME | VARIABLE_VALUE |

+---------------------------+----------------+

| WSREP_CONNECTED | ON |

| WSREP_LOCAL_STATE_COMMENT | Synced |

| WSREP_READY | ON |

+---------------------------+----------------+

 수행결과 캡처

 


 항목별 점검/확인 포인트

  • WSREP_READY : true(ON) 이면 해당 노드는 SQL 처리가 가능한 상태
  • WSREP_CONNECTED : true(ON) 이면 정상, WSREP_LOCAL_STATE_COMMENT 값이 'Synced'.
  • false(OFF) 이면 해당 노드가 정상적으로 Cluster 에 참여하지 못한 상태로 WSREP_LOCAL_STATE_COMMENT 값을 참조해야 함
  • WSREP_LOCAL_STATE_COMMENT : 동기화 진행중이면 Joining/Waiting for SST/Joined 중 하나의 값




3. Replication Status  Check

 Maria1

Maria2 

select * from information_schema.GLOBAL_STATUS where VARIABLE_NAME like 'wsrep_flow_control_paused' or VARIABLE_NAME like 'wsrep_cert_deps_distance';

+---------------------------+----------------+

| VARIABLE_NAME | VARIABLE_VALUE |

+---------------------------+----------------+

| WSREP_CERT_DEPS_DISTANCE | 0.000000 |

| WSREP_FLOW_CONTROL_PAUSED | 0.000000 |

+---------------------------+----------------+

select * from information_schema.GLOBAL_STATUS where VARIABLE_NAME like 'wsrep_flow_control_paused' or VARIABLE_NAME like 'wsrep_cert_deps_distance';

+---------------------------+----------------+

| VARIABLE_NAME | VARIABLE_VALUE |

+---------------------------+----------------+

| WSREP_CERT_DEPS_DISTANCE | 0.000000 |

| WSREP_FLOW_CONTROL_PAUSED | 0.000000 |

+---------------------------+----------------+

 수행결과 캡처

 


 항목별 점검/확인 포인트

  • WSREP_FLOW_CONTROL_PAUSED : 마지막 상태점검 시간부터 현재까지의 전체 시간 중 Replication이 중지된 시간의 비율. 0에 가까울수록 Lag이 적음을 의미하고 1이면 완전 중지. DB의 전체적 성능이 저하되었다고 판단될 경우 Cluster 전체 노드 중, 이 값이 가장 큰 노드(Slave Lag이 커서 전체 성능에 영향을 줌)을 제거해야 함
  • WSREP_CERT_DEPS_DISTANCE : 병렬처리 가능한 트랜잭션 수. 튜닝시는 이 값보다 적당히 크게 wsrep_slave_threads 정수값을 설정할 수 있음




4. Slow Cluster  Check

 Maria1

Maria2 

select * from information_schema.GLOBAL_STATUS where VARIABLE_NAME like 'wsrep_flow_control_sent' or VARIABLE_NAME like 'wsrep_local_recv_queue_avg' or VARIABLE_NAME like 'wsrep_local_send_queue_avg';

+----------------------------+----------------+

| VARIABLE_NAME | VARIABLE_VALUE |

+----------------------------+----------------+

| WSREP_FLOW_CONTROL_SENT | 0 |

| WSREP_LOCAL_RECV_QUEUE_AVG | 0.000000 |

| WSREP_LOCAL_SEND_QUEUE_AVG | 0.000000 |

+----------------------------+----------------+

select * from information_schema.GLOBAL_STATUS where VARIABLE_NAME like 'wsrep_flow_control_sent' or VARIABLE_NAME like 'wsrep_local_recv_queue_avg' or VARIABLE_NAME like 'wsrep_local_send_queue_avg';

+----------------------------+----------------+

| VARIABLE_NAME | VARIABLE_VALUE |

+----------------------------+----------------+

| WSREP_FLOW_CONTROL_SENT | 0 |

| WSREP_LOCAL_RECV_QUEUE_AVG | 0.000000 |

| WSREP_LOCAL_SEND_QUEUE_AVG | 0.000000 |

+----------------------------+----------------+

 수행결과 캡처



 항목별 점검/확인 포인트

  • WSREP_FLOW_CONTROL_SENT : 이 값이 클수록 처리 성능이 낮음
  • WSREP_LOCAL_RECV_QUEUE_AVG : 이 값이 클수록 처리 성능이 낮음
  • WSREP_LOCAL_SEND_QUEUE_AVG : 이 값이 클수록 네트워크 링크의 속도가 낮음(OS, 네트워크의 물리 구성 등 여러가지 영향 분석 필요)


위의 1, 2번 항목 점검에 의해 maria1, maria2 두개의 노드는 정상적 Cluster 상태를 유지하고 있음을 확인할 수 있다.



3. Split Brain 상태의 유발, 복구 및 쿼리 실행 결과 확인


maria1과 maria2 사이의 DB간 네트워크를 단절시키는 장애 상황을 시뮬레이션하기 위해 2대 중 1대에서 ifdown ens192(또는 iptables -A INPUT -d 10.199.30.106 -s 10.199.30.105 -j REJECT)를 실행하고, 양 DB서버간 복제/동기화를 위한 접속이 불가능함을 확인한다. 


아래 화면캡처 중간 부분의 DB client 측 터미널 화면에서 maria1, maria2 양쪽 DB 서버 모두에게 DB 접속은 가능하지만 실제 DB query는 실패 됨을 확인할 수 있다.




장애 요인(DB간 네트워크 단절)을 제거하여(원상 복구된 상황),  각 DB 서버의 상태를 점검, 데이터 복제 여부를 확인한 결과는 다음과 같이 나타나게 된다.





- Barracuda -


  1. 쿼럼; 정족수, 즉 투표=vote 에 의한 의사결정이 이루어 지기 위한 최소한의 구성원 수. 클러스터링 개념에서는 과반수=majority 득표를 위한 노드 또는 참여자 수로, 일반적으로는 최소 3개가 되어야 한다. [본문으로]
저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들


MySQL이 Oracle 에 인수될 즈음부터 MySQL을 기반으로 하면서 보다 향상된 개념으로 각자가 이름을 떨치며 꾸준히 진행되어 온 프로젝트가 바로 Percona와 MariaDB이다. 참고로 두 프로젝트의 연관성을 비교하는 내용은 이 곳의 포스팅을 보시면 되겠고, 이번 포스팅에서는 Codership이 만든 Synchronous Multimaster 방식의 Galera cluster 를 설치해 보고, 운영에 관련해서 고려할 점들을 정리해 두려 한다.


Multimaster, Synchronous 한 특징을 가지는 이러한 MM 솔루션이 나오기 전에는(물론 완성도가 떨어지고 운영상 불편했던 MMM 같은 것도 있기는 했다), Master-Slave 구조의 비동기 Replication 방식이 많이 쓰였다. 한 편으로는 Semi-sync(Master는 변경 사항을 Slave 로 전달하는 것 까지만 책임을 진다)라는 장점을 가지기는 했지만 태생적으로 비동기식에서 벗어날 수 없기에, 만약의 상황에서 데이터 손실을 감수해야 하는 한계를 지녔었다고 볼 수 있겠다.


다뤄 나가고자 하는 내용을 간단히 요약하면 다음과 같다


* MariaDB Galera Cluster 설치 및 설정 과정

* 노드의 추가(확장)과 Maintenance를 위한 제거 등 운영 방법



1. MariaDB Galera Cluster 설치 및 설정 과정


설치 방법은 소스 빌드, 바이너리 다운로드&설치, rpm 설치 등 여러 가지가 있지만, 여기서는 mariadb.org 에서 권고하는 distro별 링크를 통해 단계를 밟아 나가는 내용을 그대로 따르면서 진행해 보자.


본 글에서 선택한 설치, 운영 환경: Ubuntu 14.04 Trusty, MariaDB 10, Kaist archive


* 설치 & 테스트를 진행할 3개의 Ubuntu 14.4 머신을 준비한다

 - ubuntu14-pv1, 10.0.10.1

 - ubuntu14-pv2, 10.0.10.2

 - ubuntu14-pv3, 10.0.10.3

* Local network이 아닌 외부 망을 통하여 노드간 원격 접속이 필요한 경우(AWS AZ 도 포함) 또는 서버 자체 방화벽(ufw 등) 이 설정되어 있을 때는, 방화벽 설정에서 TCP 3306/4568/4444 port와 TCP, UDP 4567 을 개방해야 한다(☞참조)



첫 번째 Cluster, Doner 노드의 설치와 기동


* 대다수 작업이 root 권한을 필요로 하므로 super user 로 로그인하여 진행한다

* 설치 과정에서 mysql 관리자 계정인 root 암호를 2번 입력(여기서는 편의상 maria 로 정한다)

* 첫 번째로 설정되어 기동되는 MariaDB 머신 도너(Doner) 노드라고 부르며, 다음과 같이 설정

* 여러 머신간의 데이터 동기화가 중요한 환경에서는, DB 데몬이 머신 부팅 후 자동 실행되는 방식을 피하는 것이 바람직

ubuntu@ubuntu14-pv1:~$ su -

root@ubuntu14-pv1:~# apt-get install software-properties-common

root@ubuntu14-pv1:~# apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xcbcb082a1bb943db

root@ubuntu14-pv1:~# add-apt-repository 'deb http://ftp.kaist.ac.kr/mariadb/repo/10.0/ubuntu trusty main'

root@ubuntu14-pv1:~# apt-get update

root@ubuntu14-pv1:~# apt-get install mariadb-galera-server

root@ubuntu14-pv1:~# mysql_secure_installation

root@ubuntu14-pv1:~# mysql -uroot -pmaria

MariaDB [(none)]> grant all on *.* to 'root'@'%' identified by 'maria';

MariaDB [(none)]> grant usage on *.* to sst_user@'%' identified by 'maria';

MariaDB [(none)]> grant all privileges on *.* to sst_user@'%';

MariaDB [(none)]> flush privileges;

MariaDB [(none)]> quit

root@ubuntu14-pv1:~# service mysql stop

root@ubuntu14-pv1:~# apt-get install sysv-rc-conf <== mysqld 의 자동 실행을 중지하기 위함

root@ubuntu14-pv1:~# sysv-rc-conf <== runlevel 2~5 에 대해 space 를 눌러서 해제


* 복제 방법으로 Percona 의 xtrabackup 을 사용하기 위함(rsync 를 선택할 경우 설치하지 않아도 됨)

* 이 경우 데이터스트림 전송을 위한 다용도 relay 솔루션인 socat은 꼭 설치해야 함

root@ubuntu14-pv1:~# apt-get install xtrabackup socat


* 중요 설정, 고유 입력 항목은 붉은 글씨로 표시

* wsrep_node_address 에는 머신 자체 ip 를 등록

* 초기 설정시에는 wsrep_cluster_address에 머신 자체 ip 만 등록

* wsrep_sst_receive_address 에는 자체 ip:4569 를 등록

root@ubuntu14-pv1:~# vi /etc/mysql/conf.d/mariadb.cnf

# MariaDB-specific config file.

# Read by /etc/mysql/my.cnf


[client]

default-character-set = utf8

 

[mysqld]

character-set-server = utf8

collation-server = utf8_general_ci

character_set_server = utf8

collation_server = utf8_general_ci

 

autocommit = 0


# Load Galera Cluster

wsrep_provider = /usr/lib/galera/libgalera_smm.so

wsrep_cluster_name='galera_cluster'

wsrep_retry_autocommit = 0

wsrep_sst_auth=sst_user:maria

#wsrep_sst_method = rsync

wsrep_sst_method = xtrabackup

wsrep_provider_options = "evs.keepalive_period = PT3S; evs.suspect_timeout = PT30S; evs.inactive_timeout = PT1M; evs.install_timeout = PT1M"

 

# Galera Node Option

wsrep_node_name='galera1'

wsrep_node_address='10.0.10.1'

wsrep_cluster_address = 'gcomm://10.0.10.1'

wsrep_sst_receive_address=10.0.10.1:4569

 

# Other mysqld options

default-storage-engine=innodb

binlog_format = ROW

innodb_autoinc_lock_mode = 2

innodb_flush_log_at_trx_commit = 2

innodb_locks_unsafe_for_binlog = 1

innodb_log_file_size=100M

innodb_file_per_table

query_cache_size=0

query_cache_type=0

bind-address=0.0.0.0

datadir=/var/lib/mysql

tmpdir=/tmp

user=mysql

log-error=/var/log/mysql/mysql.err


* Cluster 내에서 최초로 기동되는 MariaDB doner 노드이기에 --wsrep-new-cluster 옵션으로 시작

* [주의] Checking for corrupt, not cleanly closed... 메시지는 DB가 정상 기동 되었음을 의미함

root@ubuntu14-pv1:~# service mysql start --wsrep-new_cluster

 * Starting MariaDB database server mysqld                               [ OK ] 

 * Checking for corrupt, not cleanly closed and upgrade needing tables.


여기까지가 Doner 노드 설정 과정이다.


* 데이터베이스가 정상 작동하는지 간단히 테스트해 보고, 다음 Cluster 확장 단계로 넘어가자

root@ubuntu14-pv1:~# mysql -uroot -pmaria

MariaDB [(none)]> create database cluster_test;

MariaDB [(none)]> use cluster_test;

Reading table information for completion of table and column names

You can turn off this feature to get a quicker startup with -A


Database changed

MariaDB [cluster_test]> create table tbl1 (id varchar(20));

Query OK, 0 rows affected (0.25 sec)

MariaDB [cluster_test]> insert into tbl1 values ('abcdefg');

Query OK, 1 row affected (0.00 sec)

MariaDB [cluster_test]> commit;

Query OK, 0 rows affected (0.00 sec)



2. 운영 요령: 노드의 추가(확장)과 머신 점검을 위한 제거 등


앞의 단계는 Cluster 에 1개의 머신만 등록한 상태이다. 이번에는 Cluster 내에 2개의 머신을 더 추가하여, Galera Cluster 에서 권장하는 최소 홀수 개인 3개를 완성하는 과정과 Failover 및 자동 복구, Cluster 내에서 노드의 제거(머신 점검 등의 상황일 때)와 재투입 과정에 대해서 정리해 보자.


Cluster 의 두 번째 노드, 첫 Joiner 노드의 추가


* 앞의 Doner 노드 설정 과정과 거의 동일하며, config(maria.cnf) 의 일부 내용과 기동 방법이 다르다


* wsrep_node_address 에는 머신 자체의 ip 를 등록

* wsrep_cluster_address 에 기존의 Doner 노드와 Joiner 노드 ip 를 등록

* wsrep_sst_receive_address 에는 자체 ip:4569 를 등록

root@ubuntu14-pv2:~# scp root@10.0.10.1:/etc/mysql/conf.d/mariadb.cnf /etc/mysql/conf.d/

root@ubuntu14-pv2:~# vi /etc/mysql/conf.d/mariadb.cnf

# MariaDB-specific config file.

...

# Galera Node Option

wsrep_node_name='galera2'

wsrep_node_address='10.0.10.2'

wsrep_cluster_address = 'gcomm://10.0.10.1,10.0.10.2'

wsrep_sst_receive_address=10.0.10.2:4569

...


* Debian, Ubuntu 계열의 경우 특별히 신경 써서 작업해 주어야 하는 부분(debian-sys-maint 계정을 동일하게)

* Doner 노드의 /etc/mysql/debian.cnf 를 복사(password 만 Doner 노드의 것을 가져와도 됨)

root@ubuntu14-pv2:~# scp root@10.0.10.1:/etc/mysql/debian.cnf /etc/mysql/


* Cluster 내에 추가 되는 Joiner 노드는 별도 옵션 없이 시작

root@ubuntu14-pv1:~# service mysql start

 * Starting MariaDB database server mysqld                                [ OK ] 

 * Checking for corrupt, not cleanly closed and upgrade needing tables.


* Doner 노드의 config 를 새로이 추가된 Joiner 를 반영하여 수정해 둔다.

root@ubuntu14-pv1:~# vi /etc/mysql/conf.d/mariadb.cnf

 # MariaDB-specific config file.

...

# Galera Node Option

wsrep_node_name='galera1'

wsrep_node_address='10.0.10.1'

wsrep_cluster_address = 'gcomm://10.0.10.1,10.0.10.2'

wsrep_sst_receive_address=10.0.10.1:4569

...


* Doner 노드의 Mariadb 를 재시작할 필요는 없다(일단 맞추어 놓기만 하고, 다음에 재시작할 때 읽어 들이면 될 것이다). Joiner 가 추가되면서 이미 내부적으로 서로의 존재가 인식되었기 때문인데, Doner 노드에서 아래의 방법으로 확인할 수 있다. 즉, wsrep_cluster_address 변수는 config 에서 읽어들인 값을 가지고 있지만, Cluster 의 현재 상태 값을 가진 wsrep_incoming_addresses 는 2개 노드 접속 주소를 모두 가지고 있다.

root@ubuntu14-pv1:~# mysql -uroot -pmaria

MariaDB [(none)]> show variables like 'wsrep_cluster_address';

+-----------------------+-------------------+

| Variable_name         | Value             |

+-----------------------+-------------------+

| wsrep_cluster_address | gcomm://10.0.10.1 |

+-----------------------+-------------------+

1 row in set (0.00 sec)


MariaDB [(none)]> show status like 'wsrep_incoming_addresses';

+--------------------------+-------------------------------+

| Variable_name            | Value                         |

+--------------------------+-------------------------------+

| wsrep_incoming_addresses | 10.0.10.2:3306,10.0.10.1:3306 |

+--------------------------+-------------------------------+

1 row in set (0.00 sec)



Cluster 의 세 번째 노드, 새로운 Joiner 노드의 추가


* wsrep_node_address 에는 머신 자체의 ip 를 등록

* wsrep_cluster_address 에 기존의 노드에 추가하여 새로운 Joiner 노드 ip 를 등록

* wsrep_sst_receive_address 에는 자체 ip:4569 를 등록

root@ubuntu14-pv3:~# scp root@10.0.10.2:/etc/mysql/conf.d/mariadb.cnf /etc/mysql/conf.d/

root@ubuntu14-pv3:~# vi /etc/mysql/conf.d/mariadb.cnf

# MariaDB-specific config file.

...

# Galera Node Option

wsrep_node_name='galera3'

wsrep_node_address='10.0.10.3'

wsrep_cluster_address = 'gcomm://10.0.10.1,10.0.10.2,10.0.10.3'

wsrep_sst_receive_address=10.0.10.3:4569

...


* Doner 노드의 /etc/mysql/debian.cnf 를 복사

root@ubuntu14-pv3:~# scp root@10.0.10.1:/etc/mysql/debian.cnf /etc/mysql/


* Cluster 내에 추가 되는 Joiner 노드이므로 별도 옵션 없이 시작

root@ubuntu14-pv3:~# service mysql start

 * Starting MariaDB database server mysqld                               [ OK ] 

 * Checking for corrupt, not cleanly closed and upgrade needing tables.


* 기존의 Doner 노드와 Joiner 노드의 config 를 새로이 추가된 Joiner 를 반영하여 수정해 둔다. 앞 선 과정과 같은 요령

* 위와 마찬가지로 기존 MaraiDB들을 재시작할 필요는 없다

root@ubuntu14-pv1:~# vi /etc/mysql/conf.d/mariadb.cnf

 # MariaDB-specific config file.

...

# Galera Node Option

wsrep_node_name='galera1'

wsrep_node_address='10.0.10.1'

wsrep_cluster_address = 'gcomm://10.0.10.1,10.0.10.2,10.0.10.3'

wsrep_sst_receive_address=10.0.10.1:4569

...

root@ubuntu14-pv2:~# vi /etc/mysql/conf.d/mariadb.cnf

 # MariaDB-specific config file.

...

# Galera Node Option

wsrep_node_name='galera2'

wsrep_node_address='10.0.10.2'

wsrep_cluster_address = 'gcomm://10.0.10.1,10.0.10.2,10.0.10.3'

wsrep_sst_receive_address=10.0.10.2:4569

...


여기까지가  두 번째 Joiner 노드 추가 과정이며, 목표로 했던 3대로 이루어진 Galera cluster 가 완성되었다.


* 3대로 구성된 Galera Cluster 가 정상 작동하는지 간단한 테스트를 해 보자

root@ubuntu14-pv1:~# mysql -uroot -pmaria

MariaDB [(none)]> show variables like 'wsrep_cluster_address';

+--------------------------+----------------------------------------------+

| Variable_name            | Value                                        |

+--------------------------+----------------------------------------------+

| wsrep_incoming_addresses | 10.0.10.3:3306,10.0.10.2:3306,10.0.10.1:3306 |

+--------------------------+----------------------------------------------+

1 row in set (0.01 sec)

MariaDB [(none)]> insert into cluster_test.tbl1 values ('xyz123');

1 row in set (0.01 sec)

MariaDB [(none)]> commit;

0 row in set (0.00 sec)


* 최초에 Doner 에서 insert 했던 데이터와 직전에 insert 했던 데이터가 모두 조회된다

root@ubuntu14-pv3:~# mysql -uroot -pmaria -e "select * from cluster_test.tbl1;"

+--------+

| id     |

+--------+

| abcdefg   |

| xyz123   |

+--------+


<여기서 퀴즈1> node1(doner), node2, node3 구성일 때, node1의 MySQL이 shutdown 되었다면 node2, node3 중 하나가 doner 가 될 것이다. 잠시 후 node1이 다시 Cluster에 참여하면 node은 원래대로 doner가 될까?정답은 아래로 Drag!
정답: node1은 원래의 Doner 지위를 자동으로 되찾게 됨


Cluster 내의 노드를 제거/복원(재투입)하려면?


서버 머신 점검을 위해 Doner 노드(ubuntu14-pv1)를 Cluster 에서 제거해야 하는 상황이다. 아래의 과정으로 밟도록 하자.


* config 에서 wsrep_cluster_address 설정을 gcomm:// 로 클리어하고 DB를 재시작하면 Cluster 에서 제거됨

root@ubuntu14-pv1:~# vi /etc/mysql/conf.d/mariadb.cnf

...

# Galera Node Option

wsrep_node_name='galera1'

wsrep_node_address='10.0.10.1'

#wsrep_cluster_address = 'gcomm://10.0.10.1,10.0.10.2,10.0.10.3' <== Comment out

wsrep_cluster_address = 'gcomm://' <== 추가

wsrep_sst_receive_address=10.0.10.1:4569

...

root@ubuntu14-pv1:~# service mysql restart

 * Stopping MariaDB database server mysqld                               [ OK ] 

 * Starting MariaDB database server mysqld                               [ OK ] 

 * Checking for corrupt, not cleanly closed and upgrade needing tables.


root@ubuntu14-pv2:~# mysql -uroot -pmaria -e "show status like  'wsrep_incoming_addresses';"

+--------------------------+-------------------------------+

| Variable_name            | Value                         |

+--------------------------+-------------------------------+

| wsrep_incoming_addresses | 10.0.10.3:3306,10.0.10.2:3306 |

+--------------------------+-------------------------------+

root@ubuntu14-pv3:~# mysql -uroot -pmaria -e "show status like  'wsrep_incoming_addresses';"

+--------------------------+-------------------------------+

| Variable_name            | Value                         |

+--------------------------+-------------------------------+

| wsrep_incoming_addresses | 10.0.10.3:3306,10.0.10.2:3306 |

+--------------------------+-------------------------------+



ubuntu14-pv1 머신의 점검/수리가 끝났다. 원래 대로 재투입하려면 다음 과정을 밟으면 된다.


* config 를 이전 상태로 되돌리고 단순히 restart 하면 끝(이미 Galera Cluster 내에 노드가 1개 이상 작동중일 때에는 --wsrep-new-cluster 옵션을 쓰지 않음)

root@ubuntu14-pv1:~# vi /etc/mysql/conf.d/mariadb.cnf

...

# Galera Node Option

wsrep_node_name='galera1'

wsrep_node_address='10.0.10.1'

wsrep_cluster_address = 'gcomm://10.0.10.1,10.0.10.2,10.0.10.3' <== Uncomment

# wsrep_cluster_address = 'gcomm://' <== Comment out

wsrep_sst_receive_address=10.0.10.1:4569

...

root@ubuntu14-pv1:~# service mysql restart

 * Stopping MariaDB database server mysqld                               [ OK ] 

 * Starting MariaDB database server mysqld                               [ OK ] 

 * Checking for corrupt, not cleanly closed and upgrade needing tables.


root@ubuntu14-pv2:~# mysql -uroot -pmaria -e "show status like  'wsrep_incoming_addresses';"

+--------------------------+----------------------------------------------+

| Variable_name            | Value                                        |

+--------------------------+----------------------------------------------+

| wsrep_incoming_addresses | 10.0.10.3:3306,10.0.10.2:3306,10.0.10.1:3306 |

+--------------------------+----------------------------------------------+

root@ubuntu14-pv3:~# mysql -uroot -pmaria -e "show status like  'wsrep_incoming_addresses';"

+--------------------------+----------------------------------------------+

| Variable_name            | Value                                        |

+--------------------------+----------------------------------------------+

| wsrep_incoming_addresses | 10.0.10.3:3306,10.0.10.2:3306,10.0.10.1:3306 |

+--------------------------+----------------------------------------------+




3. 노드간 데이터 복제가 잘 되지 않는 것 같다. 확인/조치 방법은?


Cluster 내의 모든 노드들은 자신이 Primary 노드라고 인식한다(참고). 그러나 특정한 상황, 즉 네트워크 일시적 단절(network glitch), 과반수 이상의 노드가 장애를 겪거나 또는 split-brain 상태에 빠질 수도 있다. 이렇게 되면 데이터의 동기화에 문제가 발생할 가능성이 커지게 된다.


[여기서 잠깐] split-brain 에 대해 정리해 둘 필요가 있다. 일반적인 split-brain 이란 Master-Slave 상황에서 각자가 Master(또는 primary) 라고 인식하게 되는 상황을 말한다. Galera Cluster 와 같은 Multimaster 의 경우에도 Doner와 Joiner 관계가 있는 것과 같이 Master라 하더라도 '급' 이 다른 구분이 필요하다(즉, "데이터의 오리지널 소스가 누구지?"에 대한 답이 필요하다). 잠시 후 2-node 구성일 때의 네트워크 단절 상황에 대해 테스트 해보기로 하자.


첫 번째 장애: 3-node 구성일 때 1대의 머신에 네트워크 장애 발생


* node2의 네트워크 단절(머신 자체는 동작하지만 node1, node3 과 네트워킹이 안되도록 iptables 로 장애를 흉내 냄)

* 일정 시간이 지나면 node2 는 '쓰기 불가' 상태에 빠지며 wsrep_local_index가 0으로 떨어짐

root@ubuntu14-pv2:~# iptables -A INPUT -d 10.0.10.2 -s 10.0.10.1 -j REJECT

root@ubuntu14-pv2:~# iptables -A INPUT -d 10.0.10.2 -s 10.0.10.3 -j REJECT

root@ubuntu14-pv2:~# mysql -uroot -pmaria

MariaDB [(none)]> show status like 'wsrep_local_index';

+-------------------+-------+

| Variable_name     | Value |

+-------------------+-------+

| wsrep_local_index | 1     |

+-------------------+-------+


MariaDB [(none)]> show status like 'wsrep_local_index';

+-------------------+-------+

| Variable_name     | Value |

+-------------------+-------+

| wsrep_local_index | 0     |   <== 값이 0인 노드는 Doner 또는 Standalone 노드

+-------------------+-------+


MariaDB [(none)]> show status like 'wsrep_incoming_addresses';

+--------------------------+----------------+

| Variable_name            | Value          |

+--------------------------+----------------+

| wsrep_incoming_addresses | 10.0.10.2:3306 |

+--------------------------+----------------+


MariaDB [(none)]> show status like 'wsrep_cluster_size';

+--------------------+-------+

| Variable_name      | Value |

+--------------------+-------+

| wsrep_cluster_size | 1     |

+--------------------+-------+


MariaDB [(none)]>  show status like 'wsrep_cluster_status';

+----------------------+-------------+

| Variable_name        | Value       |

+----------------------+-------------+

| wsrep_cluster_status | non-Primary |

+----------------------+-------------+


MariaDB [(none)]> insert into cluster_test.tbl1 values ('data1234');

ERROR 1047 (08S01): WSREP has not yet prepared node for application use


[주의사항] Cluster에서 제외된 노드(여기서는 node2)에서는 정상적인 쿼리가 수행되지 않는다

* 이 때 wsrep_provider_options 변수에 pc.bootstrap=1(YES) 값을 설정하면 자체가 Standalone 모드로 작동하게 할 수 있다. 단, 네트워크를 정상화한 이후에 다시 Cluster 내에 투입하려면 반드시 MySQL을 재시작해야 한다

* Cluster 내에서 하나의 노드에서만 수행해야 한다(galera Cluster 에서는 Automatic Bootstrap 이라고 함)

root@ubuntu14-pv2:~# mysql -uroot -pmaria

MariaDB [(none)]> SET GLOBAL wsrep_provider_options='pc.bootstrap=1';


* [주의사항] 또 다른 장애 발생 가능성: 이 상황에서 node2의 특정 테이블에 insert 후 PK 변경 DDL 수행시,  Cluster에 재투입하면 node1, node3 에서는 Deadlock 발생 가능성이 있음

* 따라서, Cluster 에서 제외된 노드에서는 더 이상의 DDL이나 insert/update 쿼리가 돌지 않도록 특별히 유의해야 함

root@ubuntu14-pv1:~# 

MariaDB [cluster_test]> select * from tbl1;

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

root@ubuntu14-pv3:~# 

MariaDB [cluster_test]> select * from tbl1;

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction


* [원상복귀] node1, node3 은 정상 작동 중인 상황, node2를 되살린다

* node2 의 네트워크를 되살리면 일정 시간이 지나 node1, node2가 있는 Cluster 로 자동 복귀

root@ubuntu14-pv2:~# iptables -F <== 네트워크 장애가 해결되었음을 시뮬레이션



[특정 노드의 전체 데이터 수동 동기화]

* node2 가 Cluster에서 분리된 이후에 Update되어 데이터가 node1, node3 에 비해 지나치게 상이한 경우의 조치(초기화)

* 아래 과정대로 하면 node1, node3로부터 전체 데이터에 대해 동기화(mysqldump, xtrabackup, rsync 등 방법도 있음)

root@ubuntu14-pv2:~# rm -rf /var/lib/mysql/*

root@ubuntu14-pv2:~# rm -rf /var/log/mysql/*

root@ubuntu14-pv2:~# mysql_install_db

root@ubuntu14-pv2:~# service mysql start --wsrep_cluster_address='gcomm://'

root@ubuntu14-pv2:~# mysql_secure_installation

root@ubuntu14-pv2:~# mysql -uroot -pmaria

MariaDB [(none)]> grant all on *.* to 'root'@'%' identified by 'maria';

MariaDB [(none)]> grant usage on *.* to sst_user@'%' identified by 'maria';

MariaDB [(none)]> grant all privileges on *.* to sst_user@'%';

MariaDB [(none)]> flush privileges;

MariaDB [(none)]> quit

root@ubuntu14-pv2:~# service mysql stop

root@ubuntu14-pv2:~# vi /etc/mysql/conf.d/mariadb.cnf

...

# Galera Node Option

wsrep_node_name='galera2'

wsrep_node_address='10.0.10.2'

wsrep_cluster_address = 'gcomm://10.0.10.1,10.0.10.2,10.0.10.3' <== Uncomment

# wsrep_cluster_address = 'gcomm://' <== Comment out

wsrep_sst_receive_address=10.0.10.2:4569

...

root@ubuntu14-pv1:~# service mysql start

 * Stopping MariaDB database server mysqld                               [ OK ] 

 * Starting MariaDB database server mysqld                               [ OK ] 

 * Checking for corrupt, not cleanly closed and upgrade needing tables.


두 번째 장애: 2-node 구성일 때 1대의 머신에 네트워크 장애 발생(split-brain 발생 위험성 존재)


* Cluster내에 2개의 노드(node1, node2) 만 남아 있는 상황

* node1-2 사이에 네트워크 장애 발생, 2개의 노드에서 동일하게 데이터베이스가 정상작동하지 않음(접속은 되나 use, select 등 기본 동작 불가)

* Cluster 내의 Master 노드 정족수가 부족(과반수를 초과해야 하나, quorom=1/2)하게 되기 때문(이러한 한계를 무시하는 설정도 있고, 노드를 흉내내 주는 대안적 방법으로 garbd(Galera Arbiter로 2개 노드일 때 quorom 값을 +1 증가시켜 줌, ☞참고) 를 쓰는 방법도 있으나, 썩 바람직하지 않으므로 Skip)

root@ubuntu14-pv2:~# iptables -A INPUT -d 10.0.10.2 -s 10.0.10.1 -j REJECT


root@ubuntu14-pv1:~# mysql -uroot -pmaria

MariaDB [(none)]> select * from cluster_test.tbl1;

ERROR 1047 (08S01): WSREP has not yet prepared node for application use


root@ubuntu14-pv2:~# mysql -uroot -pmaria

MariaDB [(none)]> use cluster_test;

ERROR 1047 (08S01): WSREP has not yet prepared node for application use


* [원상복귀] node2 의 네트워크를 되살리면 일정 시간이 지나 node1이 있는 Cluster 로 자동 복귀

root@ubuntu14-pv2:~# iptables -F


root@ubuntu14-pv1:~# mysql -uroot -pmaria
MariaDB [(none)]> show status like 'wsrep_local_index';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| wsrep_local_index | 0     |
+-------------------+-------+


root@ubuntu14-pv2:~# mysql -uroot -pmaria

MariaDB [(none)]> show status like 'wsrep_local_index';

+-------------------+-------+

| Variable_name     | Value |

+-------------------+-------+

| wsrep_local_index | 1     |

+-------------------+-------+



- Barracuda -


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들