백은빈, 이성욱 님의 "Real MySQL" 책을 정리한 포스팅 입니다.
1. 그룹 복제
바이너리 로그
- 내부적으로 Row 포맷의 바이너리 로그와 릴레이로그, GTID를 사용함
클러스터 형태
- 복제에 참여하는 MySQL 서버들이 하나의 복제그룹으로 묶인 클러스터 형태를 가짐
- 그룹 내 서버들은 서로 통신하면서 양방향으로도 복제를 처리할 수 있음
- 즉, 하나의 복제 그룹 내에서 쓰기를 처리하는 서버가 여러 대 존재할 수 있음
- 기존 복제의 경우 소스-레플리카 형태로 구성되어 단방향으로만 복제가 이루어졌음
- 프라이머리-세컨더리라는 용어로 그룹 멤버(서버)를 표현함
반동기 방식
- 한 서버에서 트랜잭션이 커밋 준비 완료
- 그룹 멤버 간 합의
- 트랜잭션 정보를 그룹의 다른 멤버들에게 전송
- 과반수 이상의 멤버로부터 응답을 전달받으면 통과
- 만약 과반수 이상의 멤버로부터 응답을 받지 못하면, 해당 트랜잭션은 그룹에 적용되지 않음
- 해당 트랜잭션을 인증 (충돌 검사)
- 해당 트랜잭션이 이미 인증 단계를 통과한 선행 트랜잭션과 동시점에 동일한 데이터를 변경했는지 확인
- 최종적으로 커밋 처리를 완료함
2. 아키텍처
- 별도의 플러그인으로 구현됨
- 그룹 복제 플러그인 설치 필요
그룹 복제 플러그인
- API를 통해 MySQL 서버로부터 이벤트를 전달받음 (서버 시작, 서버 복구, 트랜잭션 커밋 등)
- 처리 중인 트랜잭션에 대한 커밋 또는 중단, 릴레이 로그 기록을 위한 요청 등을 MySQL 서버에 전달
복제 채널
- group_replication_applier: 그룹에 실행된 모든 트랜잭션을 전달받아 적용함
- group_replication_recovery: 그룹 분산 복구 작업 (그룹 간의 최신 데이터를 가지도록 함)
3. 모드
- 프라이머리 서버 수에 따라 나뉨
- group_replication_single_primary_mode 시스템 변수로 모드를 설정함
- ON / OFF로 설정
- 그룹 복제에 참여하는 서버들은 같은 값으로 설정되어야 함
싱글 프라이머리 모드
- 그룹 내 프라이머리 서버가 단 한대만 존재
- 그룹 복제 구축을 진행한 서버가 프라이머리 서버가 됨
프라이머리 서버가 변경될 경우
- 그룹의 특정 멤버를 새로운 프라이머리로 지정한 경우 (group_replication_set_as_primary())
- 현재 프라이머리 서버가 그룹을 탈퇴하는 경우
프라이머리 서버 지정 우선순위
- MySQL 서버 버전
- 8.0.17 이상인 경우, 높은 버전이 우선순위 높음
- 8.0.17 미만인 경우, 제외됨
- 각 멤버의 가중치 값
- group_replication_member_weight 시스템 변수 값 비교
- UUID 값의 사전식 순서
프라이머리 서버 확인
select * from performance_schema.replication_group_members;
멀티 프라이머리 모드
- 그룹 내 모든 노드가 프라이머리 서버로 동작하는 형태
- 발생한 쓰기는 그룹의 다른 멤버들로 전파되어 각 멤버에서 다시 처리됨
- 멤버간의 버전 호환성이 중요
- 버전이 다르면 다른 멤버가 가지고 있지 않은 기능을 사용할 수 있으므로 동작이 안될수도 있음
- 새로운 멤버가 추가될 때, 새로운 멤버의 버전이 그룹과 호환되는지 체크함
3. 그룹 멤버 관리
- 그룹 멤버들에 대한 목록과 상태 정보를 내부적으로 관리함
그룹 멤버 확인
select * from performance_schema.replication_group_members;
그룹 멤버들의 정보 테이블
- 호스트명, 사용하는 포트, UUID 값, MySQL 버전, 역할
- View ID
- 특정 시점의 그룹 멤버 목록 및 상태 정보를 의미
- 그룹 멤버가 변경될 때마다 새로운 View ID가 생성됨
- [Prefix Value]:[Sequence Value]
- Prefix Value: 그룹 복제가 초기화될 때 생성됨 (타임스탬프 기반)
- Sequence Value: 그룹에서 멤버가 변경될 때마다 1씩 증가하는 정수값
- 상태
- ONLINE, OFFLINE, ERROR, UNREACHABLE
- RECOVERING: 그룹 복제에 참여하기 위해 복구 작업을 수행하는 중 (기존 그룹 멤버로부터 데이터를 전달받기)
자동 갱신
- 탈퇴하거나 추가되면, 자동으로 테이블에 그룹 멤버 정보를 갱신함
4. 트랜잭션 처리
1. 협의
- 그룹 멤버들에게 트랜잭션 적용을 제안하고 승낙을 받는 과정
과정
- 클라이언트가 한 그룹 멤버에게 트랜잭션 실행 및 커밋 요청을 보냄
- 트랜잭션 데이터를 다른 멤버들에게 전파함 (그룹 통신 엔진(XCom)을 통해 전파)
- 트랜잭션에서 변경한 데이터에 대한 WriteSet
- 트랜잭션이 커밋될 당시의 gtid_executed 스냅숏 정보
- 트랜잭션의 이벤트 로그 데이터
- 그룹 멤버들 간의 합의를 수행함 (Paxos 기반의 프로토콜을 바탕으로)
- 그룹의 과반수 이상에게 응답 메시지를 전달받으면, 해당 멤버는 다음 프로세스를 진행함
- 과반수 이상에게 응답을 받지 못하면 트랜잭션은 적용되지 않으며, 클라이언트에게 에러가 응답됨
목적
- 그룹 내 일관된 트랜잭션 적용이 목적
2. 인증
- 협의를 통해 올라온 트랜잭션이 반영되기 전, 트랜잭션 충돌 여부를 확인하는 과정
과정
- 합의 단계를 거친 후, 멤버들은 정렬됨
- 각 멤버들은 트랜잭션 충돌 여부를 확인함
- 해당 트랜잭션이 이미 인증 단계를 거친 선행 트랜잭션과 동시점에 동일한 데이터를 변경한 것인지를 검사
- 전달받은 트랜잭션 WriteSet 데이터와 내부 데이터인 WriteSet 히스토리 데이터를 대조함
특징
- 각 멤버들에서 모두 동일한 순서로 인증 단계를 거침
- 멀티 프라이머리 모드에서만 발생
- 그룹 멤버 전체가 쓰기를 처리할 수 있기 때문
3. 기록
요청 받은 멤버
- 바이너리 로그에 트랜잭션을 기록
- 트랜잭션 실행 (커밋)
- 클라이언트에 응답
그룹의 다른 멤버들
- 릴레이 로그에 기록 (어플라이어 스레드)
- 바이너리 로그에 기록
- 트랜잭션 실행
트랜잭션 일관성 수준
- 멤버 간 데이터 일관성을 보장하는 방법
목적
- 그룹 복제에서 각 멤버들은 모두 동일한 트랜잭션을 적용함
- 그러나 일관성이 깨질 가능성이 있음
- 실제 적용 시점까지 완전히 일치하지는 않음
- 한 멤버가 쓰기를 수행한 후 바로 다른 멤버에서 해당 데이터를 읽었을 때, 최신 변경 사항이 반영되지 않았을 수도 있음
- 트랜잭션 일관성 수준은 이 같은 상황을 방지할 수 있는 방법
group_replication_consistency
- 트랜잭션 일관성 수준을 지정할 수 있음
- EVENTUAL
- 트랜잭션이 커밋되면 복제 그룹 내에서 순차적으로 전파됨
- BEFORE_ON_PRIMARY_FAILOVER
- 싱글 프라이머리 모드에서 적용됨
- 프라이머리가 변경될 때, 새로운 Primary는 모든 트랜잭션을 적용한 후 승격됨
- BEFORE
- 요청받은 멤버가 커밋을 완료한 후에야, 다른 멤버에서 읽기가 가능함 (항상 최신 데이터만 읽음)
- wait_timeout 까지 대기
- AFTER
- 요청받은 멤버의 커밋은 모든 멤버가 트랜잭션을 확정된 후에야 완료됨
- BEFORE_AND_AFTER
- 모든 선행 트랜잭션이 적용될 때까지 기다린 후 트랜잭션이 실행됨
흐름 제어
- 그룹 멤버간의 트랜잭션 적용 불균형으로 인해 발생하는 문제를 방지
- 특정 멤버가 다른 멤버들보다 스펙이 더 낮거나 대역폭이 적을 경우 트랜잭션 지연이 일어날 수 있음
- 지연된 멤버가 트랜잭션을 실행할 때, 해당 트랜잭션은 최신 데이터가 아닌 오래된 데이터를 읽을 수 있음 (충돌 위험)
- 그룹 멤버들의 쓰기 처리량을 조절하는 매커니즘이 구현되어 있음
- 멤버 간 트랜잭션 갭을 적게 유지해서 멤버들의 처리량이 균등하도록 함
- 멤버들의 데이터가 최대한 동기화된 상태가 유지됨
시스템 변수
- group_replication_flow_control_mode
- 흐름 제어 기능의 사용 여부 결정
- QUOTA
- 쓰기 멤버가 정해진 할당량만큼만 쓰기를 하도록 제어
- 네트워크 및 성능이 낮은 멤버를 기준으로 조정하여 모든 멤버가 동기화된 상태를 유지함
- DISABLED
- 흐름제어 비활성화
- 느린 멤버가 뒤처지더라도 다른 멤버들의 흐름제어에 영향을 미치지 않음
- group_replication_flow_control_period
- 흐름 제어가 동작되는 주기 (ms)
- 지정된 시간마다 통계 정보가 수집됨
- group_replication_flow_certifier_threshold
- 인증 단계에서 인증 큐에 대기중인 트랜잭션 수가 지정된 수를 초과하면 흐름 제어 발동
- group_replication_flow_applier_threshold
- 적용 단계에서 어플라이어 큐에서 대기중인 트랜잭션 수가 지정된 수를 초과하면 흐름 제어 발동
- group_replication_flow_control_min_quota
- 모든 멤버에게 보장해야 할 최소 쓰기 처리량
- group_replication_flow_control_min_recovery_quota
- 복구 중인 멤버에게 보장해야 할 최소 쓰기 처리량
- group_replication_flow_control_member_quota_percent
- 할당된 쓰기 처리량 중 실제 사용 가능 비율
- group_replication_flow_control_hold_percent
- 할당량 중에서 사용하지 않고 남겨둘 비율
- group_replication_flow_control_release_percent
- 흐름 제어가 필요 없을 때, 주기당 증가시킬 할당량의 비율
- group_replication_flow_control_max_quota
- 멤버가 최대 사용할 수 있는 쓰기 처리량 설정
쓰기 처리량 계산 로직
- 통계 정보로 계산된 쓰기량과 group_replication_flow_control_min_quota 중 작은 값을 선택
- 복구중인 멤버는 group_replication_flow_control_min_recovery_quota 사용
- 1에서 계산된 값에서 group_replication_flow_control_member_quota_percent 값 적용
- group_replication_flow_control_max_quota 값이 설정되어 있을 경우 2와 비교하여 더 작은 값을 선택함
5. 자동 장애 감지 및 대응
장애 감지 및 멤버 추방
- 멤버 간 상태 확인
- 주기적으로 통신 메시지를 주고받으며 서로의 상태 확인
- 5초 내 응답이 ㅇ벗으면 문제 발생 가능성이 있다 판단함
- 의심 멤버 감지
- 응답이 없는 멤버를 의심 상태로 설정 (UNREACHABLE)
- 과반수의 멤버가 동의하면 해당 멤버는 그룹에서 추방됨
- 멤버 추방 및 새로운 VIEW ID 부여
- 추방된 멤버를 그룹에서 제외하고 새로운 VIEW ID 부여
- 멤버 간의 그룹 구성이 변경됨
시스템 변수
- group_replication_member_expel_timeout
- 추방 전 대기시간 (초)
- group_replication_unreachable_majority_timeout
- 소수의 멤버들이 과반수의 멤버들과 통신이 단절됐을 때, 일정 시간 동안 대기한 후 스스로 탈퇴하도록 설정 (네트워크 이슈)
자동 재가입 기능
- 추방된 멤버가 그룹에 다시 합류하려면 재가입 시도를 해야 함
- 재가입이 설정되지 않은 경우, 탈퇴된 서버는 종료 액션이 실행됨
재가입 시도 정보 확인
select * from performance_schema.events_stages_current;
시스템 변수
- group_replication_autorejoin_tries
- 추방된 멤버가 그룹에 재가입을 시도하는 횟수
- 5분 간격으로 시도
- group_replication_exist_state_action
- ABORT_SERVER: 탈퇴된 서버를 종료시킴 (기본값)
- READ_ONLY
- OFFLINE_MODE
6. 분산 복구
- 그룹 복제에서 탈퇴된 멤버가 다시 가입할 떄 기존 멤버와 데이터를 동기화하는 과정
필요성
- 탈퇴된 멤버가 다시 그룹에 합류할 때, 그룹에서 발생한 트랜잭션을 모두 적용해야 데이터 일관성이 유지됨
- 이전 탈퇴 시점 이후에 반영되지 않은 트랜잭션을 복구해야 정상적으로 동작이 가능함
- 이때, 기존 그룹 멤버 중 한 명을 기증자 멤버로 지정하여 복구를 수행함
분산 복구 방식
바이너리 로그 복제 방식
- 특징
- 비동기 복제 기반
- 가입 멤버는 group_replication_applier 복제 채널을 통해 기증자 멤버의 바이너리 로그를 복제
- 가입 멤버에 적용되지 않은 트랜잭션을 가져와 순차적으로 실행
- 작동 방식
- 가입 멤버가 기존 그룹 멤버의 바이너리 로그에서 미적용 트랜잭션을 찾음
- 발견된 트랜잭션을 가입 멤버에 적용하여 데이터 동기화
- 가입 완료 후, 그룹 복제에 정상적으로 참여
- 시스템 변수
- group_replication_recovery_retry_count
- 바이너리 로그 복제 방식으로 복구 작업 진행 시, 가입한 멤버가 기존 그룹 멤버에 연결을 시도하는 횟수
- group_replication_recovery_reconnect_interval
- 기존 그룹 멤버들에 대한 연결 시도 사이의 대기 시간 지정
- group_replication_recovery_retry_count
원격 클론 방식
- 특징
- 클론 플러그인 사용
- 모든 멤버에 클론 플러그인이 설치되어 있어야 함
- 작동 방식
- 기존 그룹 멤버의 InnoDB 스토리지 엔진 데이터를 일관된 스냅샷으로 가져와 복구
- 가입한 멤버의 기존 데이터는 모두 삭제되고, 기증자 멤버의 스냅샷 데이터로 대체됨
- 클론 후에도 바이너리 로그 복제 방식으로 추가 복구 진행
- 사용되는 경우
- 가입한 멤버와 기존 멤버 간의 트랜잭션 갭이 큰 경우
- 필요한 트랜잭션이 기존 그룹 멤버의 바이너리 로그에서 삭제된 경우
- 시스템 변수
- group_replication_clone_threshold
- 원격 클론 방식을 복구 방식으로 채택하게 되는 트랜잭션 갭의 임곗값
- group_replication_start_on_boot
- 원격 클론 방식에서 기증자 멤버의 스냅숏 데이터를 모두 전송받고 재부팅 후 바이너리 로그 복제를 자동으로 실행할 지 여부
- OFF일 경우, 수동으로 명령을 실행해야 함 (START GROUP_REPLICATION)
- group_replication_clone_threshold
프로세스
- 로컬 복구
- 뷰 변경 로그 이벤트 생성
- 새로운 멤버가 그룹에 가입할 경우 발생
- 그룹 뷰가 변경되어 VIEW ID가 새로 발급됨
- 멤버들의 바이너리 로그에 해당 이벤트가 기록됨
- 가입한 멤버가 이전에 가입한 적이 있는 경우 릴레이 로그에 미처 적용하지 못한 트랜잭션이 있을 수 있음
- 이 트랜잭션들을 먼저 적용한 후 본격적인 작업을 진행함
- 뷰 변경 로그 이벤트 생성
- 글로벌 복구
- 가입 멤버는 그룹의 기존 멤버들에서 기증자 역할을 할 멤버를 선택
- 기증자 멤버로부터 데이터 또는 누락된 트랜잭션들을 가져와 자신에게 적용함
- 복구 작업 동안, 현재 그룹에서 처리되는 트랜잭션들을 내부적으로 캐싱해둠
- 캐시 트랜잭션 적용
- 글로벅 복구 단계가 완료되면 캐싱에서 보관하고 있던 트랜잭션들을 적용해 최종적으로 그룹에 참여함
설정
group_replication_recovery_complete_at
- TRANSACTIONS_CERTIFIED: 누락된 트랜잭션들이 인증 단계까지 완료했을 때 ONLINE으로 변경
- TRANSACTIONS_APPLIED: 누락된 트랜잭션들이 모두 적용되어 기록됐을 때 ONLINE으로 변경
오류 처리
- 복구 작업 중 오류가 발생할 경우 자동으로 다시 작업을 시도함
- 새로운 그룹 멤버로 연결을 전환함
바이너리 로그 복제 분산 복구 에러 확인 테이블
- performance_schema.replication_connection_status
- performance_schema.replication_applier_status_by_worker
원격 클론 방식 분산 복구 에러 확인 테이블
- performance_schema.clone_progress
- performance_schema.clone_status
7. 요구 사항
InnoDB 스토리지 사용
- 충돌 감지 시 트랜잭션 롤백 지원이 필요함
- disabled_storage_engines에 트랜잭션 롤백을 지원하지 않는 스토리지 엔진을 기입하여 에러를 방지함
프라이머리 키 사용
- 그룹에서 복제될 모든 테이블들은 프라이머리 키를 가지고 있어야 함
- 이를 바탕으로 트랜잭션 간의 충돌을 감지함
원활한 네트워크 환경
- 그룹 멤버들 간의 양방향 통신을 통해 이루어짐
- 정상적으로 통신이 이루어져야 원활하게 사용 가능
바이너리 로그 활성화
ROW 포맷 형태의 바이너리 로그 사용
log_slave_updates 활성화
- 레플리카 서버에서 받은 트랜잭션을 다시 바이너리 로그에 기록할지 설정
- 기본적으로 레플리카 서버는 자신에게 들어온 트랜잭션을 바이너리 로그에 기록하지 않음
- 새로운 멤버가 그룹에 참여하면, 기존 멤버들과 동일한 데이터를 가질 수 있도록 분산 복구 작업 수행
- 기존 그룹 멤버의 바이너리 로그를 복제해서 자신에게 적용
- 그룹 멤버들은 그룹에서 발생한 트랜잭션들을 모두 각자의 바이너리 로그에 기록해야 함
GTID 사용
- 기본적으로 GTID를 사용함
고유한 server_id 사용
복제 메타데이터 저장소 설정
- 복제 관련 메타데이터는 파일이 아닌 테이블에 저장되어야 함
- master_info_repository 및 relay_log_info_repository 값이 TABLE로 되어있어야 함
WriteSet 설정
- 트랜잭션에서 변경한 데이터 정보
- transaction_write_set_extraction 변수가 XXHASH64로 설정되어야 함
테이블 스페이스 암호화 설정
- default_table_encryption 값이 모든 그룹 멤버에 동일하게 설정되어야 함
lower_case_table_names 설정
- lower_case_table_names 값이 모든 그룹 멤버에 동일하게 설정되어야 함
멀티 스레드 복제 설정
- 멀티 스레드를 사용하여 트랜잭션을 병렬 처리할 수 있음
- slave_preserve_commit_order
- 복제 트랜잭션이 멀티 스레드로 적용될 때 원본 서버에서 커밋된 순서와 동일한 순서로 커밋되도록 해야 함
- ON으로 설정하기
'Database > Mysql' 카테고리의 다른 글
[Real MySQL] 17-4. InnoDB 클러스터: 구축 (0) | 2024.09.07 |
---|---|
[Real MySQL] 17-3. InnoDB 클러스터: MySQL (0) | 2024.09.07 |
[Real MySQL] 17-1. InnoDB 클러스터: 아키텍처 (0) | 2024.09.07 |
[Real MySQL] 16-5. 복제: 복제 토폴로지 (0) | 2024.09.07 |
[Real MySQL] 16-4. 복제: 동기화 방식 (0) | 2024.09.07 |