본문 바로가기

Technical/OS, Infra

Split Brain - MariaDB Galera Cluster Case


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개가 되어야 한다. [본문으로]