현재 회사에서 운용하고 있는 Galera Cluster 관련 이슈를 해결하기 위해 학습했던 내용을 공유하는 글입니다. 개인의 이해도 부족으로 인하여 잘못된 내용이 포함되어 있을 수 있으며 트러블 슈팅이 아닌 원론적인 이야기만 나열하더라도 감안해주시고 피드백 부탁드립니다.

 

 

 

Galera Cluster?

Galera Cluster는 Mutl Master Cluster 구조를 지원하는 MySQL, MariaDB 등의 계열에 호환되는 Open Source입니다.

 

복제 구성시 Origin node와 Replica node 사이의 Eventual consistency로 일정 시간 동안의 데이터 부정합 문제를 해결하기 위해 적용할 수 있는 방법인 Synchronous replication에는 몇 가지 문제점이 존재합니다.

  • 네트워크 문제로 인한 영구적인 Node 간의 Blocking 상태 발생 가능성
  • Node 가 확장될수록 증가하는 복제 지연 시간에 의한 서비스 중단 발생 등

Galera Cluster는 이를 우회적으로 해결하는 Wsrep API 기반의 Semi-synchronous replication과 Asynchronous replication 방식을 제공함으로써 데이터 부정합 문제를 해결하고 복제 시 서비스 중단 시간을 최소화할 수 있도록 지원합니다. (실제로는... 음..)

Galera Cluster 또한 rsync라고 불리는 Synchronous replication 방식도 존재합니다.

 

 

 

 

Galera Cluster Multi Master 구성의 확장성?

경험 상 Galera Cluster의 Multi Master 구조는 Scale-out 기반 확장과 어울리지는 않습니다.

 

첫 번째로는 Multi Master 구성 시 네트워크 문제로 인해 발생하는 Split Brain 문제가 발생할 수 있다는 점입니다.

  • 해당 문제를 해결하기 위해서는 클러스터 내의 네트워크 분할 시에도 최소한 분단된 한쪽의 Cluster Group이 Node가 많을 수 있도록(결정할 수 있도록) 홀수로 구성하여야 합니다.
  • 하나 이상의 Node가 죽고, 네트워크 분단 현상으로 인해 Cluster가 짝수로 분할되어 Split Brain 문제가 발생하지 않도록 Galera arbitrator를 구성하여 합의 알고리즘에서 항상 홀수를 만족하게 구성할 수도 있습니다.

두 번째로는 Multi Master 구성 시 Write Node가 많아짐으로써 Replica Node(Joiner)들의 recv queue에 쌓이는 Transaction의 량이 많아지기 때문에 처리 부하, Flow Control 발생 빈도와 지연 시간이 비례해서 증가합니다. 

 

세 번째로는 여러 Originnode가 하나의 레코드를 수정하는 경우를 해결하기 위해 X lock과 First commit one 전략을 사용하는데 이 전략의 경우 반영하지 못한 Node는 Dead lock이 발생한다는 점입니다.

 

다른 이유 또한 존재하나 이정도로 정리하겠습니다. 이러한 문제들은 현재 Galera Cluster의 구조적 한계로 보입니다.

 

 

 

 

Galera Cluster의 Master Node는 최소한으로 유지하자.

서비스의 데이터와 관련하여서 부하를 측정하고 Write가 가능한 Node가 더 필요한 상황이라면 개별 Cluster Group으로 나누는 것이 현명한 선택인 것 같습니다. 이는 앞서 언급한 상황이 발생하기 때문입니다.

  • 현재 경험 상 관리하는 서비스 데이터를 기준으로 클러스터를 분리하고 각 클러스터마다 총 3개~5개의 node (하나의 Write node, 나머지는 Read node)를 두어 Query Off 하는 것이 좋다고 생각합니다.
  • ex) 채팅 Group: Read/Write 1 : Read 2 | 인증, 계정 Group: Read/Write 1 : Read 2

 

 

 

Gcache를 잘 설정하여 최대한 IST(증분 상태 복제) 방식의 복제를 사용하게 하자.

IST, 즉 증분 상태 전송을 유지하는 방법은 Gcache size를 적절하게 잡는 것으로 수행할 수 있으나, 해결 방법이 그렇게 단순한 것은 아닙니다. Size를 결정할 때 유의해야 하는 점은 Gcache size를 IST 발생 이전에만 넘지 않도록 하면 되는 것이 아니라, IST 중에서도 발생하는 Transaction 양 또한 고려해야 한다는 점입니다. 또한 서비스 트래픽이 급증하여 기존에 계산했던 용량을 넘어갈 수 있습니다.

 

IST를 통해 처리되는 Transaction 양이 Write로 인해 쌓이는 Transcation 양을 넘어서지 못하고 Gcache size를 넘어서게 되어 IST가 SST 방식로 변경되는 경우는 빈번하게 일어납니다.

 

그럼에도 이러한 점을 고려하여 굳이 IST를 유지해야하는 이유는 이렇습니다.

  • IST는 SST와 달리 wirte set에서 반영되지 않은 부분만 식별하여 복제하는 방식으로 최소한의 리소스만을 이용해 데이터 동기화를 진행할 수 있으며, non-blocking으로 진행되기 때문에 복제 대상(Read Node, Joiner)에게 성능 부하를 최대한 주지 않습니다.
  • IST 방식은 다른 xtrabackup, mariabackup 방식보다 50% 정도 빠르며 mysqldump 방식보다 5배 이상 빠르기 때문에 이를 지속적으로 유지하도록 하는 것은 Galera Cluster를 통한 서비스 운영 시 큰 최적화 요소가 됩니다. 

 

Gcache Size를 설정하는 기본적인 공식은 여기서 확인할 수 있습니다.

 

추가적으로 gcache.recover=yes 설정을 통해 생성하였던 Gcache file을 삭제하지 않고 재사용하도록 함으로써 누락된 Write set을 식별할 데이터가 없을 때 발생하는 SST을 방지함으로써 IST 방식을 유지할 수 있습니다.

이는 Gcache file이 지속적으로 유지되어야 Read Node의 Gcache와 비교가 가능하기 때문입니다. (반대의 경우도 포함)

 

 

 

 

Flow Control의 발생 빈도를 조절하자.

Flow Control이란 복제를 지속하던 Cluster node (Write -> Read node) 외에 아직 반영되지 않았거나 commit 되지 않은 Transaction을 write Set(Gcache)으로 저장하여 순서를 정렬하고 recv queue에 쌓아두었다가 queue가 일정 크기를 만족하면 기존 복제 작업을 중지하고 쌓여있는 Transaction을 반영하는 작업을 의미합니다.

 

 

Multi Master 인 경우의 Flow Control

Write node가 많다는 것은 결국 Write가 여러 node에서 동시 다발 적으로 일어나고 있다는 것을 뜻합니다. 이 경우 큰 Gcache(write set)과 긴 recv queue를 둔다면 한번 발생한 Flow Control의 지연 시간이 길어질 수 있습니다. 또한 recv queue가 길수록 API에서 인증 충돌이 발생할 수 있는 여지가 비례적으로 증가합니다.

  • 이때에는 recv queue를 낮은 값으로 설정하여 일으키도록 하는 것이 낫다고 합니다. (권장 사항)

 

Single Master 인 경우의 Flow Control

Single Master는 위와 같이 인증 충돌이 발생할 여지가 없습니다. 다른 Write node와 동일한 영역을 commit 했을 경우 수행하는 first committer win 전략을 사용할 필요가 없기 때문에 그 과정 중에 발생하는 Dead lock이 발생하지 않기 때문입니다.

  • 그렇기에 recv queue를 크게 잡아도 된다고 합니다.

 

 

 

 

Flow Control의 처리 속도를 향상 시키자.

wsrep_slave_threads 속성을 통해 Parallel Replica(Slave) threads를 지정하여 recv queue에 있는 wirte set을 병렬로 처리하도록 설정할 수 있습니다. 이를 사용하면 데이터의 유실이 발생하지 않는 상태에서 대량의 DML을 처리하여 복제 지연 시간을 최소화할 수 있으며, Write 부하가 급증하더라도 대응할 수 있는 기반이 됩니다.

  • SHOW STATUS LIKE 'wsrep_cert_deps_distance'; 를 통해 권장하는 thread 개수를 확인할 수 있습니다.
  • InnoDB를 엔진으로 사용하는 경우 innodb_autoinc_lock_mode를 2로 설정합니다. 자동 증가 잠금 모드
  • 이를 적용하더라도 노드 간의 통신 왕복 시간(RTT) and Gcache(write set) size에 의해 처리량이 제한될 수 있습니다.

 

하지만 그럼에도 데이터의 부정합 문제가 발생할 수 있습니다. ( Eventual consistency ) 이를 해결하기 위해 더 많은 thread를 지정할 수 있으나 권장 사항으로는 Core당 4개의 thread를 권장하고 있기에 그 이상을 넘기지 않는 것이 좋아 보입니다.

  • 최대 설정으로 처리를 하더라도 일관성 문제가 발생한다면 Parallel threads 설정을 1로 고정하고 다른 방법을 고려하여야 합니다. (클러스터 그룹의 단위를 적게 조정 등)

 

 

 

 

최적화된 설정을 위해 Galera Cluster의 작업 상태를 지속적으로 모니터링 하자.

  • 제일 기본적이자 필수적인 부분입니다. MariaDB, MySQL의 자체적인 메트릭 지표(connection, Slow query 등) 들을 제외하고도 Galera Cluster의 recv queue, send queue, Flow control 등의 지표들을 수집하여 지속적인 모니터링을 하여야 합니다.
    • 이는 Prometheus, Grafana 등의 opensource나 Galera Manager로 구성할 수 있습니다.
    • SHOW GLOBAL STATUS LIKE 'wsrep_%'; 를 지속적으로 Query 함으로써 (이는 기본적으로 그 상황의 Snapshot 정보이기 때문에 PromQL의 rate, irate를 통해 평균값이나 변동 폭을 나타내는 메트릭으로 변경하여야 합니다.)

 

 

 

참고 링크

+ Recent posts