Loading...
MySQL 9.5 Reference Manual 9.5의 25.7.11 NDB Cluster Replication Using the Multithreaded Applier의 한국어 번역본입니다.
아래의 경우에 피드백에서 신고해주신다면 반영하겠습니다.
감사합니다 :)
NDB 9.5의 NDB 복제는 일반적인 MySQL Server 멀티스레드 어플라이어 메커니즘(MTA)의 사용을 지원하며, 이를 통해 서로 독립적인 바이너리 로그 트랜잭션들을 레플리카에서 병렬로 적용할 수 있으므로, 복제 최고 처리량을 증가시킬 수 있습니다.
MySQL Server MTA 구현은 개별 바이너리 로그 트랜잭션의 처리를 워커 스레드 풀(풀의 크기는 설정 가능함)에 위임하고, 바이너리 로그에 인코딩된 트랜잭션 의존성이 보장되도록 워커 스레드들을 조정하며, 필요할 경우 커밋 순서가 유지되도록 합니다( Section 19.2.3, “Replication Threads” 참조). 이 기능을 NDB Cluster와 함께 사용하려면 레플리카가 여러 워커 스레드를 사용하도록 설정되어야 합니다. 이를 위해 레플리카에서 워커 스레드의 개수를 제어하는 replica_parallel_workers를 설정해야 합니다. 기본값은 4입니다.
추가로, 소스에서 바이너리 로그 트랜잭션 라이트셋을 추적하는 데 사용되는 메모리 양(binlog_transaction_dependency_history_size)을 E * P로 설정하는 것이 권장됩니다. 여기서 E 는 평균 에포크 크기(각 에포크당 연산 수)이고 P 는 기대되는 최대 병렬성입니다. 더 많은 정보는 Writeset Tracking Memory Usage를 참조하십시오.
NDB MTA에 대한 레플리카 mysqld 설정에서는 replica_parallel_workers가 1보다 커야 합니다. MTA를 처음 활성화할 때 권장되는 시작값은 기본값인 4입니다.
또한 replica_preserve_commit_order가 ON이어야 합니다. 이것 역시 기본값입니다.
트랜잭션 의존성은 각 트랜잭션의 라이트셋, 즉 트랜잭션이 기록한 행 집합(테이블, 키 값)을 분석하여 탐지합니다. 두 트랜잭션이 동일한 행을 수정하는 경우, 이들은 서로 의존적인 것으로 간주되어 데드락이나 잘못된 결과를 피하기 위해 순서대로(즉, 직렬로) 적용되어야 합니다. 테이블에 세컨더리 유니크 키가 있는 경우, 이 값들도 트랜잭션의 라이트셋에 추가되어, 서로 다른 트랜잭션이 동일한 유니크 키 값을 변경함으로써 암시적으로 트랜잭션 의존성이 생기는 경우를 탐지하고, 따라서 순서 보장이 필요하도록 합니다. 의존성을 효율적으로 결정할 수 없는 경우, mysqld는 안전을 위해 트랜잭션들을 서로 의존적인 것으로 간주하는 방식으로 되돌아갑니다.
트랜잭션 의존성은 소스 mysqld에 의해 바이너리 로그에 인코딩됩니다. 의존성은 'Logical clock'이라 불리는 방식으로 ANONYMOUS_GTID 이벤트에 인코딩됩니다( Section 19.1.4.1, “Replication Mode Concepts” 참조).
MySQL(및 NDB Cluster)에 의해 사용되는 라이트셋 구현은 관련된 테이블과 인덱스 값의 64비트 행 해시가 일치하는지에 기반해 해시 기반 충돌 감지를 사용합니다. 이는 동일한 키가 두 번 관측되는 경우를 신뢰성 있게 탐지하지만, 서로 다른 테이블 및 인덱스 값이 동일한 64비트 값으로 해시되는 경우 false positive를 만들어낼 수도 있습니다. 이는 인위적인 의존성을 유발하여 사용 가능한 병렬성을 감소시킬 수 있습니다.
트랜잭션 의존성은 다음 중 어느 하나에 의해서도 강제됩니다:
DDL 문
바이너리 로그 로테이션 또는 바이너리 로그 파일 경계에 도달하는 경우
라이트셋 히스토리 크기 제한
대상 테이블에서 부모 외래 키를 참조하는 쓰기
좀 더 구체적으로, 외래 키 parent 테이블에 대해 insert, update, delete를 수행하는 트랜잭션들은 앞뒤의 모든 트랜잭션에 대해 직렬화되며, 제약 관계에 연관된 테이블에 영향을 미치는 트랜잭션에만 한정되지 않습니다. 반대로, 외래 키 child 테이블(참조하는 쪽)에 대해 insert, update, delete를 수행하는 트랜잭션들은 서로 간에 특별히 직렬화되지 않습니다.
MySQL MTA 구현은 서로 독립적인 바이너리 로그 트랜잭션들을 병렬로 적용하려고 시도합니다. NDB는 하나의 에포크( TimeBetweenEpochs, 기본값 100밀리초) 내에서 커밋되는 모든 사용자 트랜잭션에서 발생한 모든 변경 사항을 하나의 바이너리 로그 트랜잭션에 기록하며, 이를 에포크 트랜잭션이라고 합니다. 따라서 두 개의 연속된 에포크 트랜잭션이 서로 독립적이고 병렬로 적용 가능하려면, 두 에포크 모두에서 수정된 행이 없어야 합니다. 어느 한 행이라도 두 에포크에서 모두 수정되었다면, 이들은 서로 의존적이며 직렬로 적용되므로, 활용 가능한 병렬성을 제한할 수 있습니다.
에포크 트랜잭션들은 에포크 내에서 소스 클러스터에서 수정된 행 집합을 기준으로 독립적인 것으로 간주되며, 에포크 메타데이터를 전달하는 mysql.ndb_apply_status``WRITE_ROW 이벤트는 포함하지 않습니다. 이렇게 하면 모든 에포크 트랜잭션이 바로 이전 에포크에 자명하게 의존적이 되는 것을 피할 수 있지만, 레플리카에서 바이너리 로그를 커밋 순서를 보존하면서 적용해야 합니다. 이는 또한 라이트셋 의존성이 포함된 NDB 바이너리 로그가 서로 다른 MySQL 스토리지 엔진을 사용하는 레플리카 데이터베이스에서는 사용하기 부적합함을 의미합니다.
짧은 시간 동안의 별도 트랜잭션에서 동일한 행을 반복적으로 수정하는 패턴을 피하도록 애플리케이션 트랜잭션 동작을 수정하는 것이 가능하거나 바람직할 수 있으며, 이를 통해 활용 가능한 어플라이 병렬성을 증가시킬 수 있습니다.
바이너리 로그 트랜잭션 라이트셋을 추적하는 데 사용되는 메모리 양은 서버 시스템 변수인 binlog_transaction_dependency_history_size를 사용해 설정할 수 있으며, 기본값은 25000 행 해시입니다.
평균 바이너리 로그 트랜잭션이 N 개의 행을 수정한다면, 병렬성 수준을 P 까지로 하여 독립적인(병렬화 가능한) 트랜잭션을 식별할 수 있으려면 binlog_transaction_dependency_history_size가 최소한 N * P 이상이어야 합니다(최대값은 1000000입니다).
히스토리의 크기가 유한하기 때문에, 신뢰성 있게 결정할 수 있는 최대 의존성 길이 역시 유한하며, 표현 가능한 병렬성도 유한합니다. 히스토리에서 발견되지 않는 어느 행이든 히스토리에서 마지막으로 제거된 트랜잭션에 의존적일 수 있습니다.
라이트셋 히스토리는 마지막 N 개 트랜잭션에 대한 슬라이딩 윈도처럼 동작하지 않고, 완전히 찼을 때 전체 내용이 한꺼번에 폐기되는 유한 버퍼로 동작합니다. 이는 히스토리 크기가 시간에 따라 톱니파(sawtooth) 패턴을 따르게 함으로써, 탐지 가능한 최대 의존성 길이 또한 시간에 따라 톱니파 패턴을 따르게 합니다. 그 결과, 서로 독립적인 트랜잭션이라도 라이트셋 히스토리 버퍼가 이들이 처리되는 사이에 리셋되었다면 의존적인 것으로 표시될 수 있습니다.
이 방식에서, 하나의 바이너리 로그 파일에 있는 각 트랜잭션은 sequence_number(1, 2, 3, ...)와, 자신이 의존하는 가장 최근 바이너리 로그 트랜잭션의 시퀀스 번호(이를 last_committed라 부름)로 주석이 달립니다.
주어진 바이너리 로그 파일에서 첫 번째 트랜잭션은 sequence_number가 1이고 last_committed는 0입니다.
어떤 바이너리 로그 트랜잭션이 즉시 이전 트랜잭션에 의존하는 경우, 그 적용은 직렬화됩니다. 더 이전의 트랜잭션에 의존하는 경우라면, 선행하는 독립적인 트랜잭션들과 병렬로 트랜잭션을 적용할 수 있을 수도 있습니다.
sequence_number와 last_committed(따라서 트랜잭션 의존성)를 포함하여 ANONYMOUS_GTID 이벤트의 내용은 mysqlbinlog를 사용해 확인할 수 있습니다.
소스에서 생성된 ANONYMOUS_GTID 이벤트는 벌크 BEGIN, TABLE_MAP*, WRITE_ROW*, UPDATE_ROW*, DELETE_ROW*, COMMIT 이벤트를 포함하는 압축된 트랜잭션 페이로드와는 별도로 처리되며, 이를 통해 의존성을 압축 해제 이전에 결정할 수 있습니다. 이는 레플리카 코디네이터 스레드가 트랜잭션 페이로드의 압축 해제를 워커 스레드에 위임할 수 있게 하여, 레플리카에서 서로 독립적인 트랜잭션에 대한 자동 병렬 압축 해제를 제공하게 합니다.
Secondary unique column. 세컨더리 유니크 컬럼(즉, primary key 이외의 유니크 키)을 가진 테이블은 유니크 키 관련 충돌을 탐지할 수 있도록 모든 컬럼이 소스로 전송됩니다.
현재 바이너리 로깅 모드가 모든 컬럼이 아니라 변경된 컬럼만 포함하는 경우( --ndb-log-updated-only=OFF, --ndb-log-update-minimal=ON, --ndb-log-update-as-write=OFF)라면, 이는 데이터 노드에서 SQL 노드로 전송되는 데이터 양을 증가시킬 수 있습니다.
영향도는 해당 테이블의 행에 대한 수정(update 또는 delete) 비율과 실제로 수정되지 않는 컬럼 내 데이터의 양에 모두 의존합니다.
Replicating NDB to InnoDB. NDB 바이너리 로그 인젝터 트랜잭션 의존성 추적은 의도적으로, 생성된 mysql.ndb_apply_status 메타데이터 이벤트가 만드는 트랜잭션 간 의존성을 무시하며, 이는 레플리카 어플라이어에서 에포크 트랜잭션 커밋의 일부로 따로 처리됩니다. InnoDB로의 복제의 경우에는 특별한 처리가 없으며, 이로 인해 InnoDB 멀티스레드 어플라이어가 NDB MTA 바이너리 로그를 소비할 때 성능 저하 또는 기타 문제가 발생할 수 있습니다.
25.7.10 NDB Cluster Replication: Bidirectional and Circular Replication
25.7.12 NDB Cluster Replication Conflict Resolution