테마
그룹 복제와 InnoDB 클러스터 3
그룹 복제와 InnoDB 클러스터·2에서 본 그룹 복제(Group Replication)는 서버끼리 합의하는 엔진이고, 실제 서비스에는 그 위에 "누가 설치·관리하고, 애플리케이션은 어디로 접속하는가"가 더 필요하다. InnoDB 클러스터(InnoDB Cluster)는 그룹 복제에 관리 도구 MySQL Shell과 연결 중계기 MySQL Router를 묶은 MySQL의 공식 HA(High Availability, 고가용성) 구성이다. 이 문서는 구성 요소와 도입에 필요한 요구사항·제약을 다룬다.
InnoDB 클러스터의 구성
InnoDB 클러스터는 최소 3대의 MySQL 서버와 세 가지 구성 요소로 이루어진다. 3대여야 한 대가 죽어도 남은 두 대가 과반수, 곧 정족수(quorum)를 유지한다.
- 그룹 복제: 멤버끼리 트랜잭션(transaction) 순서에 합의하고, 장애 난 멤버를 빼고, 쓰기를 받는 멤버인 프라이머리(primary)를 자동으로 다시 뽑는다. 보통 싱글 프라이머리 모드(single-primary mode)로 쓴다.
- MySQL Shell: 관리자가 쓰는 클라이언트다. 안에 든 AdminAPI(JavaScript·Python)로 클러스터를 만들고, 멤버를 넣고 빼고, 상태를 본다. 새 멤버를 넣을 때는 MySQL 클론(clone) 기능으로 기존 멤버의 데이터를 통째로 복사해 채워 주므로, 백업을 떠서 옮기는 수작업이 없다.
- MySQL Router: 애플리케이션과 DB 사이의 가벼운 중계기다. 애플리케이션은 DB 서버가 아니라 Router에 접속한다. Router는 클러스터 정보를 읽어 두고 연결을 알맞은 멤버로 넘기며, 프라이머리가 바뀌면 새 프라이머리로 보낸다.
다이어그램 로딩…
js
// MySQL Shell (JavaScript 모드), 첫 서버에 접속한 상태에서
var cluster = dba.createCluster('prod')
cluster.addInstance('admin@db2:3306') // 클론으로 데이터 자동 복사
cluster.addInstance('admin@db3:3306')
cluster.status()Router는 부트스트랩(bootstrap) 과정에서 클러스터에 접속해 멤버 구성을 읽고 자기 설정 파일을 스스로 만든다. 기본 설정에서 6446 포트는 프라이머리로 가는 읽기·쓰기 연결, 6447 포트는 세컨더리(secondary)로 번갈아 보내는 읽기 전용 연결이다. 애플리케이션은 쓰기와 읽기를 두 포트로 나눠 보내기만 하면, 장애 조치(failover) 뒤에도 접속 주소를 바꿀 필요가 없다.
요구사항
그룹 복제에 참여하는 모든 멤버는 다음을 지켜야 한다.
| 요구사항 | 이유 |
|---|---|
| 데이터는 InnoDB에만 | 충돌 검사(certification)에서 진 트랜잭션을 롤백(rollback)해야 한다 |
| 모든 테이블에 PK(Primary Key, 기본 키) | 충돌을 행 단위로 판단할 식별자가 필요 |
gtid_mode=ON 등 GTID(Global Transaction Identifier, 전역 트랜잭션 식별자) 설정 | 멤버마다 실행한 트랜잭션을 GTID로 추적 |
| 바이너리 로그(binary log) ROW 포맷 (8.4 기본) | 바뀐 행 정보로 충돌을 찾는다 |
log_replica_updates (8.4 기본 ON) | 받은 트랜잭션도 자기 바이너리 로그에 남겨 새 멤버에 넘긴다 |
서로 다른 server_id, 가까운 네트워크 | 모든 멤버가 양방향으로 계속 통신해야 한다 |
InnoDB만 허용하는 이유는 그룹 복제가 트랜잭션을 먼저 실행해 두고 커밋(commit) 때 충돌을 검사하는 낙관적 방식이기 때문이다. 충돌하면 롤백해야 하므로 롤백할 수 없는 엔진은 쓸 수 없다. PK는 NULL을 허용하지 않는 유니크 키로 대신할 수 있다. GTID 관련 두 설정 gtid_mode와, GTID로 안전하게 기록할 수 없는 문장을 거부하는 enforce_gtid_consistency는 8.4에서도 기본값이 OFF라 직접 켜야 한다. AdminAPI의 dba.configureInstance()가 이런 설정을 점검하고 맞춰 준다.
제약
- 멤버는 최대 9대다.
- 큰 트랜잭션은 거부된다.
group_replication_transaction_size_limit(기본 150000000바이트, 약 143MB)를 넘는 트랜잭션은 그룹에 보내지 않고 롤백한다. 대량 작업은 나눠서 커밋해야 한다. - 전역 복제 필터를 쓸 수 없다. 복제 필터는 특정 DB·테이블만 골라 복제하는 설정인데, 멤버마다 받는 데이터가 다르면 같은 상태에 합의할 수 없기 때문이다.
- 충돌 검사는 행만 본다. 갭 락(gap lock)·
LOCK TABLES·GET_LOCK()같은 잠금은 충돌 검사에 반영되지 않는다(InnoDB 잠금). 그래서 멀티 프라이머리 모드(multi-primary mode)에서는 갭 락을 쓰지 않는READ COMMITTED격리 수준(isolation level)을 권장한다.
멀티 프라이머리 모드에는 제약이 더 붙는다. SERIALIZABLE 격리 수준 트랜잭션은 커밋이 거부된다. ON DELETE CASCADE 같은 연쇄 동작이 있는 외래 키(foreign key)는 감지되지 않는 충돌을 만들 수 있어 쓰지 않는다. 같은 테이블에 대해 한 멤버에서 DDL(Data Definition Language, 데이터 정의어)을, 다른 멤버에서 DML(Data Manipulation Language, 데이터 조작어)을 동시에 실행하면 안 된다. SELECT ... FOR UPDATE의 잠금도 다른 멤버와 공유되지 않아 기대한 대로 막아 주지 않는다. 이런 이유로 운영에서는 대부분 싱글 프라이머리 모드를 쓴다.
이어지는 내용은 그룹 복제와 InnoDB 클러스터 4에서 다룬다.
면접 포인트
- "InnoDB 클러스터는 무엇으로 구성되나요?" → 그룹 복제(합의·자동 장애 조치) + MySQL Shell AdminAPI(구성·관리, 클론으로 멤버 추가) + MySQL Router(연결 중계, 6446 쓰기·6447 읽기).
- "그룹 복제의 요구사항?" → InnoDB만, 모든 테이블 PK, GTID ON, ROW 포맷. 이유는 행 단위 충돌 검사와 롤백.
- "그룹 복제의 제약?" → 최대 9대, 트랜잭션 크기 한도(기본 약 143MB), 전역 복제 필터 불가, 멀티 프라이머리에는 제약이 더 붙는다.
