18.6.11 MySQL Cluster Replication 충돌 해결
여러 마스터가 참여하는 복제 설정을 사용하는 경우 (순환 복제를 포함합니다) 다른 마스터가 다른 데이터를 가진 슬레이브에서 동일한 행을 갱신하려고 할 수 있습니다. MySQL Cluster 복제 충돌 해결은 특정 마스터의 업데이트를 노예로 적용할지 여부를 결정하는 데 사용되는 사용자 정의의 해결 컬럼을 허용함으로써 이러한 충돌을 해결할 수 있습니다.
MySQL Cluster에서 지원되는 충돌 해결의 몇 가지 유형 ( NDB$OLD()
, NDB$MAX()
, NDB$MAX_DELETE_WIN()
)이 사용자 정의 컬럼을 "timestamp"컬럼으로 구현하고 있습니다 (단 이 섹션의 뒷부분에서 설명하는 바와 같이,이 유형은 TIMESTAMP
가 될 수 없습니다). 이 유형의 충돌 해결은 항상 트랜잭션 별이 아닌 행별로 적용됩니다. 신기원 기반 충돌 해결 함수 NDB$EPOCH()
및 NDB$EPOCH_TRANS()
은 시대가 복제 된 순서를 비교합니다 (따라서 이러한 함수는 트랜잭션 형입니다). 이 섹션의 뒷부분에서 설명하도록 충돌이 발생했을 때 슬레이브로 해결 컬럼 값을 비교하기 위해 다양한 방법을 사용할 수 있습니다. 사용하는 방법은 테이블마다 설정할 수 있습니다.
업데이트를 적용할지 여부를 판단 할 때 해결 함수에서 적절한 선택을 할 수 있도록 해결 컬럼에 적절한 값으로 제대로 이입되는 것을 확인하는 것은 응용 프로그램의 책임입니다.
요구 사항 충돌 해결의 준비는 마스터와 슬레이브 모두 할 필요가 있습니다. 이러한 작업은 다음 목록에서 설명합니다.
바이너리 로그를 기록 마스터에서 어느 컬럼 (모든 컬럼 또는 업데이트 된 열만) 쓰기를 지정해야합니다. MySQL Server에서 이렇게는 전체적으로는 mysqld 시작 옵션
--ndb-log-updated-only
(이 섹션의 뒷부분에서 설명합니다)를 적용하고 테이블 단위는mysql.ndb_replication
테이블의 항목으로 실행합니다 ( ndb_replication 시스템 테이블 을 참조하십시오).참고매우 큰 열 (
TEXT
와BLOB
컬럼 등)가있는 테이블을 복제하는 경우--ndb-log-updated-only
는 마스터와 슬레이브의 바이너리 로그의 크기를 줄이거 나max_allowed_packet
를 초과함으로써 발생할 수 있는 복제 오류를 방지 할 경우에도 도움이 될 수 있습니다.이 문제에 대한 자세한 내용은 섹션 17.4.1.20 "복제와 max_allowed_packet" 를 참조하십시오.
슬레이브에서는 어떤 유형의 충돌 해결 ( "마지막 타임 스탬프가 우선" "같은 타임 스탬프가 우선", "기본이 우선", "기본이 우선 트랜잭션을 완결"또는 아무것도)를 적용할지 여부를 지정해야합니다. 이것은
mysql.ndb_replication
시스템 테이블을 사용하여 테이블마다 이루어집니다 ( ndb_replication 시스템 테이블 을 참조하십시오).MySQL Cluster NDB 7.4.1 이후는 읽기 충돌 감지를 지원하고 있습니다. 즉, 클러스터의 특정 행을 읽고 다른 클러스터의 같은 행을 갱신 또는 h 사이의 충돌을 감지합니다. 여기에는 노예
ndb_log_exclusive_reads
을 1로 설정하여 취득되는 배타적 읽기 잠금이 필요합니다. 충돌하는 읽기에서 읽은 모든 행의 로그가 예외 테이블에 기록됩니다. 자세한 내용은 읽기 충돌 감지 및 해결 을 참조하십시오.
타임 스탬프 기반의 충돌 해결에 함수 NDB$OLD()
, NDB$MAX()
및 NDB$MAX_DELETE_WIN()
를 사용하는 경우 업데이트를 "타임 스탬프"컬럼으로 지정하는 데 사용되는 컬럼을 참조하는 것이 일반적입니다. 그러나이 컬럼의 데이터 유형은 TIMESTAMP
하지 마십시오. 이 데이터 형식은 INT
( INTEGER
) 또는 BIGINT
합니다. 또한 "timestamp"컬럼은 UNSIGNED
및 NOT NULL
로합니다.
이 섹션의 뒷부분 NDB$EPOCH()
및 NDB$EPOCH_TRANS()
함수는 기본 및 보조 MySQL Cluster에 적용되는 복제 시대의 상대적인 순서를 비교하는 방식으로 작동하고 타임 스탬프를 사용하지 않습니다.
마스터 열 제어 "전"의 이미지와 "후"의 이미지 (즉, 업데이트가 적용되기 전과 후의 테이블 상태)에 대해 업데이트 작업을 확인할 수 있습니다. 일반적으로 기본 키 테이블을 업데이트 할 때 "이전"의 이미지는 그다지 문제가되지 않습니다. 그러나 업데이트마다 리플리케이션에서 업데이트 된 값을 사용할지 여부를 지정할 필요가있는 경우 두 이미지가 마스터의 바이너리 로그에 기록되는지 확인해야합니다. 이 섹션의 뒷부분에서 설명하는 것처럼, 이것은 mysqld의 --ndb-log-update-as-write
옵션으로 실행됩니다.
행 전체 로깅을 수행하거나 업데이트 된 컬럼 만 로깅을 수행하거나, MySQL 서버가 시작되었을 때 결정, 온라인으로는 변경할 수 없습니다. 다른 로깅 옵션을 사용하여 mysqld를 다시 시작하거나 새로운 mysqld 인스턴스를 시작해야합니다.
전체 또는 일부 라인의 로깅 (--ndb-log-updated-only 옵션)
명령 줄 형식 | --ndb-log-updated-only | ||
시스템 변수 | 이름 | ndb_log_updated_only | |
변수 범위 | Global | ||
동적 변수 | 예 | ||
허용되는 값 | 유형 | boolean | |
기본 | ON |
충돌 해결을 위해 행의 로그를 취하는 기본적인 방법은 두 가지가 그 방법은 mysqld의 --ndb-log-updated-only
옵션을 설정하면 지정됩니다.
행 전체 로그를 가져옵니다
업데이트 된 컬럼 데이터 (즉, 값이 설정된 컬럼 데이터) 만 기록합니다. 이 값이 실제로 변경된 여부에 상관하지 않습니다. 이것은 기본 동작입니다.
일반적으로 업데이트 된 컬럼 만의 로그를 취하는 것만으로 충분 (게다가 효율적인)입니다. 그러나 모든 행의 로그를 취할 필요가있는 경우 --ndb-log-updated-only
를 0
또는 OFF
로 설정하면이 작업을 수행 할 수 있습니다.
--ndb-log-update-as-write 옵션 : 변경된 데이터를 업데이트로 로그를 검색
명령 줄 형식 | --ndb-log-update-as-write | ||
시스템 변수 | 이름 | ndb_log_update_as_write | |
변수 범위 | Global | ||
동적 변수 | 예 | ||
허용되는 값 | 유형 | boolean | |
기본 | ON |
MySQL Server의 --ndb-log-update-as-write
옵션의 설정은 로깅이 "전"의 이미지가있는 상태에서 실행되거나없는 상태에서 실행되는지를 지정합니다. 충돌 해결 MySQL Server의 업데이트 핸들러에서 이루어지기 때문에 업데이트는 업데이트이며 쓰기는 않도록 마스터의 로깅을 제어해야합니다. 즉 업데이트는 새로운 행의 기록이 아니라 (업데이트가 기존 행을 대체하더라도) 기존 행의 변경으로 처리됩니다. 이 옵션은 기본적으로 선택되어 있습니다. 즉, 업데이트는 쓰기로 처리됩니다. (즉 기본적으로 업데이트는 update_row
이벤트로서가 아니라 write_row
이벤트로 바이너리 로그에 기록됩니다.)
옵션을 해제하려면 마스터 mysqld를 --ndb-log-update-as-write=0
또는 --ndb-log-update-as-write=OFF
로 시작합니다. NDB 테이블에서 다른 스토리지 엔진을 사용하는 테이블에 복제하려면 이렇게해야합니다. 자세한 내용은 NDB에서 다른 스토리지 엔진에 복제 및 NDB에서 비 트랜잭션 스토리지 엔진에 대한 복제 를 참조하십시오.
충돌 해결 제어 일반적으로 충돌 해결은 충돌이 발생할 수있는 서버에서 활성화되어 있습니다. 로깅 방법의 선택뿐만 아니라 mysql.ndb_replication
테이블의 항목에 의해 활성화됩니다.
ndb_replication 시스템 테이블 충돌 해결을 활성화하려면 충돌 해결의 종류 및 사용 방법에 따라 마스터, 슬레이브 또는 두 mysql
시스템 데이터베이스에 ndb_replication
테이블을 작성해야합니다. 이 테이블은 로깅과 충돌 해결 함수를 테이블 단위로 제어하는 데 사용되며 복제에 참여하는 하나의 행 단위 테이블이 있습니다. ndb_replication
가 작성되어 충돌을 해결해야 서버에서 제어 정보가 저장됩니다. 슬레이브에서 로컬로 데이터를 변경할 수있는 간단한 마스터 슬레이브 설정은 일반적으로 이것은 슬레이브됩니다. 더 복잡한 마스터 마스터 (2 방향) 복제 스키마는 이것은 관련된 모든 마스터입니다. mysql.ndb_replication
의 각 행은 복제 된 테이블에 대응하고 대상 테이블에 대한 로그의 취득 방법과 갈등 해결 방법 (즉, 만약 충돌이 발생했을 경우에 어떤 충돌 해결 함수를 사용하거나)을 지정합니다 . mysql.ndb_replication
테이블의 정의는 다음과 같습니다.
CREATE TABLE mysql.ndb_replication ( db VARBINARY(63), table_name VARBINARY(63), server_id INT UNSIGNED, binlog_type INT UNSIGNED, conflict_fn VARBINARY(128), PRIMARY KEY USING HASH (db, table_name, server_id) ) ENGINE=NDB PARTITION BY KEY(db,table_name);
이 테이블의 컬럼은 다음 몇 단락에서 설명합니다.
db 복제되는 테이블을 포함하는 데이터베이스의 이름입니다. 와일드 카드 _
및 %
중 하나 또는 둘 모두를 데이터베이스 이름의 일부로 사용할 수 있습니다. 매칭은 LIKE
연산자에 구현 된 매칭과 비슷합니다.
table_name 복제되는 테이블의 이름입니다. 테이블 이름에 와일드 카드 _
및 %
중 하나 또는 둘 모두를 포함 할 수 있습니다. 매칭은 LIKE
연산자에 구현 된 매칭과 비슷합니다.
server_id 테이블이 존재하는 MySQL 인스턴스 (SQL 노드)의 고유 서버 ID입니다.
binlog_type 사용되는 바이너리 로깅 유형입니다. 이것은 다음의 표와 같이 지정됩니다.
값 | 내부 값 | 설명 |
---|---|---|
0 | NBT_DEFAULT | 서버의 기본값을 사용합니다 |
1 | NBT_NO_LOGGING | 바이너리 로그에이 테이블의 기록을하지 않습니다 |
2 | NBT_UPDATED_ONLY | 업데이트 된 속성 만 기록됩니다 |
3 | NBT_FULL | 업데이트되지 않은 경우에도 전체 행을 기록합니다 (MySQL 서버의 기본 동작) |
4 | NBT_USE_UPDATE | ( NBT_UPDATED_ONLY_USE_UPDATE 및 NBT_FULL_USE_UPDATE 값 만 생성하고, 단독으로는 사용하지 않습니다) |
5 | [Not used] | --- |
6 | NBT_UPDATED_ONLY_USE_UPDATE ( NBT_UPDATED_ONLY | NBT_USE_UPDATE 에 해당) | 값이 변경되지 않은 경우에도 업데이트 된 속성을 사용합니다 |
7 | NBT_FULL_USE_UPDATE ( NBT_FULL | NBT_USE_UPDATE 에 해당) | 값이 변경되지 않은 경우에도 전체 행을 사용합니다 |
conflict_fn 적용되는 충돌 해결 함수입니다. 이 함수는 다음 목록에 나타난 하나의 함수로 지정해야합니다.
NDB $ OLD (column_name)
NDB $ MAX (column_name)
NDB $ MAX_DELETE_WIN (column_name)
NDB $ EPOCH () 및 NDB $ EPOCH_TRANS ()
NDB $ EPOCH_TRANS ()
NULL
이 함수는 다음 몇 절에서 설명합니다.
NDB $ OLD (column_name) column_name
값은 마스터와 슬레이브로 동일한 경우 업데이트가 적용됩니다. 동일하지 않으면 업데이트는 슬레이브에 적용되지 않고 예외가 로그에 기록됩니다. 이것은 다음 의사 코드로 설명합니다.
if (master_old_column_value
==slave_current_column_value
) apply_update(); else log_exception();
이 함수는 "같은 값이 우선"충돌 해결에 사용됩니다. 이 유형의 충돌 해결은 잘못된 마스터에서 업데이트가 슬레이브에 적용되지 않습니다.
마스터 "전"이미지의 컬럼 값이 함수에서 사용됩니다.
NDB $ MAX (column_name) 마스터에서 특정 행의 "타임 스탬프"열 값이 노예의 값보다 높은 경우 적용됩니다. 높지 않은 경우에는 슬레이브로 적용되지 않습니다. 이것은 다음 의사 코드로 설명합니다.
if (master_new_column_value
>slave_current_column_value
) apply_update();
이 함수는 "가장 큰 타임 스탬프가 우선"충돌 해결에 사용할 수 있습니다. 이 유형의 충돌 해결은 충돌이 발생한 경우 마지막으로 업데이트 된 행 버전이 존속하는 버전입니다.
마스터 "후"의 이미지에서 컬럼 값이 함수에서 사용됩니다.
NDB $ MAX_DELETE_WIN (column_name) 이것은 NDB$MAX()
의 변형입니다. 타임 스탬프는 삭제 작업에 사용할 수 없기 때문에 NDB$MAX()
를 사용하는 제거는 실제로는 NDB$OLD
로 처리됩니다. 그러나 유스 케이스에 따라이 최적이 없습니다. NDB$MAX_DELETE_WIN()
의 경우 마스터에서 기존 행을 추가 또는 업데이트하는 특정 행의 "타임 스탬프"열 값이 노예의 값보다 큰 경우에 적용됩니다. 그러나 삭제 작업은 항상 값이 높은 것으로 간주됩니다. 이것은 다음 의사 코드로 설명합니다.
if ( (master_new_column_value
>slave_current_column_value
) ||operation.type
== "delete") apply_update();
이 함수는 "가장 큰 타임 스탬프 제거가 우선"충돌 해결에 사용할 수 있습니다. 이 유형의 충돌 해결은 충돌이 발생한 경우, 삭제 된 행 버전 또는 (그렇지 않으면) 마지막으로 업데이트 된 행 버전이 존속하는 버전입니다.
NDB$MAX()
와 마찬가지로 마스터 "후"의 이미지에서 컬럼 값이이 함수에서 사용되는 값입니다.
NDB $ EPOCH () 및 NDB $ EPOCH_TRANS () NDB$EPOCH()
함수는 복제 된 신기원이 슬레이브에서 발생한 변경과 관련하여 슬레이브의 MySQL Cluster에 적용되는 순서를 추적합니다. 이 상대적인 순서는 슬레이브에서 발생하는 변경 사항이 로컬에 발생한 변경과 동시에 일어난 것인지 그 때문에 충돌이 발생할 가능성이 있는지 여부를 판단하는 데 사용됩니다.
NDB$EPOCH()
의 설명에 따라 내용의 대부분은 NDB$EPOCH_TRANS()
에도 적용됩니다. 예외는 본문에 기재되어 있습니다.
NDB$EPOCH()
는 비 대상이며, 2 개의 클러스터 순환 복제 구성의 한쪽 MySQL Cluster에서 작동합니다 ( 「활성 활성 "복제라고 부르기도합니다). 여기에서 기본 역할을하는 클러스터와 보조 역할을하는 다른 클러스터에 대해 언급합니다. 기본 노예 충돌 감지 및 처리를 담당합니다. 한편, 보조 슬레이브는 충돌 감지 또는 처리에 관여하지 않습니다.
기본 슬레이브가 충돌을 감지하면 충돌을 상쇄하기 위해 슬레이브 자신의 바이너리 로그에 이벤트를 삽입합니다. 그러면 결국 보조 MySQL Cluster는 기본에 맞게 재조정되어 기본 및 보조 불일치가 해결됩니다. 이 보정과 재조정 메커니즘은 기본 MySQL Cluster 보조 및 충돌에 항상 능가해야합니다. 즉, 충돌이 발생한 경우 보조의 변경이 아니라 기본 변경이 항상 사용되어야합니다. 이 "기본이 항상 이긴다"규칙에는 다음과 같은 의미가 담겨 있습니다.
기본으로 일단 커밋되면 데이터를 수정하는 작업이 유지 충돌 감지 및 해결에 의해 취소되거나 롤백되거나하지 않습니다.
기본에서 읽은 데이터는 일관성이 있습니다. 기본에서 커밋 된 변경 (로컬 또는 슬레이브)은 나중에 취소 할 수 없습니다.
보조 데이터를 변경하는 작업은 충돌이 발생하고 기본이 판단한 경우 나중에 취소 될 수 있습니다.
보조 읽어 들인 행은 항상 자기 모순이없고, 각 행은 보조 커밋 된 상태 또는 기본에서 커밋 된 상태 중 하나를 항상 반영하고 있습니다.
보조 읽어 들인 일련의 행은 언제든지 반드시 일관하고있는 것은 아닙니다.
NDB$EPOCH_TRANS()
의 경우 이것은 일시적인 상태이며,NDB$EPOCH()
의 경우는 영구적 인 상태가 될 수 있습니다.충분한 기간 충돌이 발생하지 않으면 보조 MySQL Cluster의 모든 데이터는 (결국) 기본 데이터와 일치합니다.
NDB$EPOCH()
및 NDB$EPOCH_TRANS()
는 충돌을 감지하기 위해 사용자 스키마를 수정하거나 응용 프로그램을 변경할 필요가 없습니다. 그러나 전체 시스템이 지정된 한계 내에서 작동하는지 확인하기 위해 사용하는 스키마 및 사용하는 액세스 패턴을 고려해야합니다.
NDB$EPOCH()
및 NDB$EPOCH_TRANS()
함수는 선택적 매개 변수를 취할 수 있습니다. 이것은 시대의 하위 32 비트를 나타내는 데 사용되는 비트 수이며 다음 값 이상으로 설정하십시오.
CEIL( LOG2(TimeBetweenGlobalCheckpoints
/TimeBetweenEpochs
), 1)
이러한 구성 매개 변수가 기본값 (각각 2000 및 100 밀리 초) 인 경우, 값은 5 바이트가 기본값 (6) 충분합니다. 그러나 다른 값이 TimeBetweenGlobalCheckpoints
, TimeBetweenEpochs
또는 둘 다에 사용되는 경우를 제외합니다. 값이 너무 작 으면 오판이 될 가능성이 있습니다. 한편, 값이 너무 크면 데이터베이스에 불필요한 공간이 늘어날 수 있습니다.
이 섹션의 다른 곳에서 설명하도록 예외 테이블이 같은 예외 테이블의 스키마 규칙에 따라 정의 된 경우 NDB$EPOCH()
과 NDB$EPOCH_TRANS()
모두는 충돌하는 행의 항목을 관련 예외 테이블에 삽입합니다 ( NDB $ OLD (column_name) 를 참조하십시오). 예외 테이블을 사용하는 테이블을 작성하기 전에 예외 테이블을 작성해야합니다.
NDB$EPOCH()
및 NDB$EPOCH_TRANS()
는이 섹션에서 설명했으며 충돌 감지 기능뿐만 아니라 mysql.ndb_replication
테이블에서 관련 항목을 포함하는 것으로 시작됩니다 ( ndb_replication 시스템 테이블 을 참조 하십시오). 이 시나리오에서 기본 및 보조 MySQL Cluster의 역할은 mysql.ndb_replication
테이블의 항목에 따라 모든 결정됩니다.
NDB$EPOCH()
및 NDB$EPOCH_TRANS()
에서 사용되는 충돌 감지 알고리즘은 비동기이기 때문에 프라이 머리 슬레이브와 보조 슬레이브 server_id
항목에서 다른 값을 사용해야합니다.
MySQL Cluster NDB 7.3.6 이전에서는 DELETE
작업 간의 충돌은 UPDATE
조작 충돌로 취급되어 같은 시대의 경쟁은 경쟁하는 것으로 간주되어있었습니다. MySQL Cluster NDB 7.3.6 이상에서 DELETE
작업 간의 경쟁뿐만 NDB$EPOCH()
또는 NDB$EPOCH_TRANS()
를 사용하여 경쟁을 시작하기에 충분하지 않고, 시대의 상대적인 배치는 중요 하지 않습니다. (Bug "18454499)
NDB $ EPOCH () 및 NDB $ EPOCH_TRANS () 상태 변수 NDB$EPOCH()
및 NDB$EPOCH_TRANS()
충돌 감지를 모니터하기 위해 몇 가지 상태 변수를 사용할 수 있습니다. 슬레이브가 Ndb_conflict_fn_epoch
시스템 상태 변수의 현재 값에서 마지막으로 재부팅 된 후에 NDB$EPOCH()
에 의해 경합중인 것으로 감지 된 행 수를 알 수 있습니다.
Ndb_conflict_fn_epoch_trans
는 NDB$EPOCH_TRANS()
에 의해 경합중인 것으로 직접 검출 된 행 수를 나타냅니다. 실제로 재구성 된 행수 (행의 구성원이나 다른 경합하는 행과 동일한 트랜잭션의 종속성에 의해 영향을받는 행을 포함)은 Ndb_conflict_trans_row_reject_count
의해 취득됩니다.
자세한 내용은 섹션 18.3.4.4 "MySQL Cluster의 상태 변수" 를 참조하십시오.
NDB $ EPOCH () 제약 NDB$EPOCH()
를 사용하여 충돌 감지를 수행 할 경우 현재 다음과 같은 제한이 적용됩니다.
TimeBetweenEpochs
(기본 : 100 밀리 초)에 비례하는 정도에서 충돌이 MySQL Cluster의 신기원 경계를 사용하여 감지됩니다. 최소 경쟁 창은 두 클러스터의 동일한 데이터에 대한 병렬 업데이트가 항상 충돌을보고하는 최소 시간입니다. 이것은 항상 0이 아닌 시간이며,2 * (latency + queueing + TimeBetweenEpochs)
에 거의 비례합니다. 이것은TimeBetweenEpochs
에 기본을 가정하고 또한 클러스터 사이의 대기 시간 (및 큐잉 지연)을 무시하고 최소 경합 윈도우가 약 200 밀리 초임을 의미합니다. 이 작은 창은 예상 된 응용 프로그램 '경쟁'패턴을 조사 할 때 고려하십시오.NDB$EPOCH()
및NDB$EPOCH_TRANS()
함수를 사용하는 테이블에는 추가 스토리지가 필요합니다. 함수에 전달되는 값은 행당 1 비트에서 32 비트로의 공간이 필요합니다.삭제 작업의 경쟁은 기본 및 보조 사이의 차이로 이어질 수 있습니다. 행이 두 클러스터에서 동시에 삭제되는 경우 충돌이 감지 할 수 있지만 행이 삭제되기 때문에 경쟁은 기록되지 않습니다. 즉 후속 재구성 조작의 전파 중에 새로운 경쟁은 감지되지 않고 불일치가 발생할 수 있습니다.
삭제는 외부 직렬화하거나 하나의 클러스터에만 라우팅하십시오. 또한 행 삭제 사이의 충돌을 추적 할 수 있도록 이러한 삭제 및 삭제에 계속되는 삽입 트랜잭션마다 개별 행을 업데이트하십시오. 여기에는 응용 프로그램의 변경이 필요한 경우가 있습니다.
충돌 감지에
NDB$EPOCH()
또는NDB$EPOCH_TRANS()
를 사용하는 경우, 순환 "Active-Active"구성의 MySQL Cluster가 2 개의 경우 만 지원되고 있습니다.BLOB
또는TEXT
컬럼을 가진 테이블은 현재NDB$EPOCH()
또는NDB$EPOCH_TRANS()
는 지원되지 않습니다.
NDB $ EPOCH_TRANS () NDB$EPOCH_TRANS()
는 NDB$EPOCH()
함수를 확장 한 것입니다. "기본이 모든 우선"규칙 ( NDB $ EPOCH () 및 NDB $ EPOCH_TRANS () 를 참조하십시오)를 사용하는 것과 동일한 방법으로 충돌이 감지되고 처리되지만 충돌이 발생한 동일한 거래에서 업데이트 된 기타 줄도 경쟁하고 있다고 간주한다는 조건이 추가됩니다. 즉, NDB$EPOCH()
이 보조 충돌하는 행을 재구성하는데 대해, NDB$EPOCH_TRANS()
은 충돌하는 트랜잭션을 재구성합니다.
또한 충돌하는 트랜잭션에 대한 의존도가 감지 된 트랜잭션도 충돌하는 것으로 간주되며, 이러한 종속성은 보조 클러스터의 바이너리 로그의 내용에 의해 결정됩니다. 바이너리 로그는 데이터 변경 작업 만 (삽입, 업데이트 및 삭제)이 포함되어 있으므로 중복 데이터의 변경 만이 트랜잭션 간의 종속성을 결정하는 데 사용됩니다.
NDB$EPOCH_TRANS()
는 NDB$EPOCH()
와 같은 조건과 규정에 따라 또한 버전 2의 바이너리 로그 행 이벤트가 사용됩니다 ( --log-bin-use-v1-row-events
는 0과 같다). 따라서 바이너리 로그의 이벤트 당 2 바이트의 스토리지 오버 헤드가 추가됩니다. 또한 모든 트랜잭션 ID를 보조 바이너리 로그에 기록해야 ( --ndb-log-transaction-id
옵션)이 때문에 가변 오버 헤드 (행당 최대 13 바이트)가 더 추가됩니다.
NDB $ EPOCH () 및 NDB $ EPOCH_TRANS () 를 참조하십시오.
NULL 해당 테이블에 충돌 해결을 사용하지 않는 것을 나타냅니다.
상태 정보 서버 상태 변수 Ndb_conflict_fn_max
은 mysqld가 마지막으로 시작된 후 "가장 큰 타임 스탬프가 우선"충돌 해결을 통해 현재 SQL 노드에 행이 적용되지 않은 횟수의 카운트를 나타냅니다.
지정된 mysqld가 마지막으로 재부팅 된 후에 "같은 타임 스탬프가 우선"충돌 해결의 결과로 행이 삽입되지 않은 횟수는 글로벌 상태 변수 Ndb_conflict_fn_old
의해 취득됩니다. Ndb_conflict_fn_old
를 증가시키는 것 외에이 섹션 뒷부분의 설명처럼, 사용되지 않은 행의 기본 키는 예외 테이블에 삽입됩니다.
충돌 해결 예외 테이블 NDB$OLD()
충돌 해결 기능을 사용하려면이 유형의 충돌 문제를 해결하는 각 NDB
테이블에 해당하는 예외 테이블도 작성해야합니다. 이것은 NDB$EPOCH()
또는 NDB$EPOCH_TRANS()
를 사용하는 경우에도 적용됩니다. 이 테이블의 이름 충돌 해결이 적용되는 테이블의 이름 문자열 $EX
를 부가 한 이름입니다. (예를 들어, 원래 테이블의 이름이 mytable
인 경우 해당 예외 테이블의 이름은 mytable$EX
됩니다.) MySQL Cluster NDB 7.4.1 이전에는이 테이블은 다음과 같이 작성됩니다.
CREATE TABLEoriginal_table
$EX ( server_id INT UNSIGNED, master_server_id INT UNSIGNED, master_epoch BIGINT UNSIGNED, count INT UNSIGNED,original_table_pk_columns
, [additional_columns
,] PRIMARY KEY(server_id, master_server_id, master_epoch, count) ) ENGINE=NDB;
MySQL Cluster NDB 7.4.1 이상에서는 예외 유형, 원인 및 원래 트랜잭션에 대한 정보를 제공하는 옵션 컬럼을 포함한 확장 된 예외 테이블 정의를 지원합니다. 이 버전에서는 예외 테이블을 생성하는 구문은 다음과 같습니다.
CREATE TABLEoriginal_table
$EX ( [NDB$]server_id INT UNSIGNED, [NDB$]master_server_id INT UNSIGNED, [NDB$]master_epoch BIGINT UNSIGNED, [NDB$]count INT UNSIGNED, [NDB$OP_TYPE ENUM('WRITE_ROW','UPDATE_ROW', 'DELETE_ROW', 'REFRESH_ROW', 'READ_ROW') NOT NULL,] [NDB$CFT_CAUSE ENUM('ROW_DOES_NOT_EXIST', 'ROW_ALREADY_EXISTS', 'DATA_IN_CONFLICT', 'TRANS_IN_CONFLICT') NOT NULL,] [NDB$ORIG_TRANSID BIGINT UNSIGNED NOT NULL,]original_table_pk_columns
, [orig_table_column
|orig_table_column
$OLD|orig_table_column
$NEW,] [additional_columns
,] PRIMARY KEY([NDB$]server_id, [NDB$]master_server_id, [NDB$]master_epoch, [NDB$]count) ) ENGINE=NDB;
처음 4 개의 컬럼이 필요합니다. 처음 4 개의 컬럼의 이름 및 원래 테이블의 프라이 머리 키 컬럼과 일치하는 컬럼의 이름은 중요하지 않습니다. 그러나 알기과 일관성을 위해 server_id
, master_server_id
, master_epoch
및 count
컬럼은 여기에 나와있는 이름을 사용하여 원래 테이블의 기본 키의 컬럼과 일치하는 컬럼에 대해서는 원래 테이블과 동일한 이름 을 사용하는 것이 좋습니다.
MySQL Cluster NDB 7.4.1 이상에서는 예외 테이블이 섹션의 뒷부분에서 설명하는 여러 옵션 컬럼 NDB$OP_TYPE
, NDB$CFT_CAUSE
또는 NDB$ORIG_TRANSID
를 사용하는 경우 각 필수 컬럼도 프리픽스 NDB$
를 사용하여 이름을 붙일 필요가 있습니다. 필요에 따라 옵션 컬럼을 정의하지 않더라도 NDB$
접두어를 사용하여 필수 컬럼을 지정할 수 있습니다. 그러나이 경우 4 개의 모든 필수 열 접두어를 사용하여 이름을 붙일 필요가 있습니다.
이 컬럼에 이어 원래 테이블의 기본 키를 구성하는 컬럼은 원래 테이블의 기본 키 정의에 사용되는 순서로 복사를합니다. 원래의 테이블의 프라이 머리 키 컬럼을 복제하는 컬럼의 데이터 유형은 원래 컬럼과 동일한 (또는 큰) 데이터 형에하십시오. MySQL Cluster NDB 7.3 이전 버전에서는 예외 테이블의 기본 키 컬럼 대 컬럼에서 다시 작성해야합니다. MySQL Cluster NDB 7.4.1 이상에서 프라이 머리 키 컬럼의 서브 세트를 사용할 수 있습니다.
사용하는 MySQL Cluster 버전에 관계없이 예외 테이블은 NDB
스토리지 엔진을 사용해야합니다. (예외 테이블에 NDB $ OLD ()
를 사용하는 예는이 섹션의 뒷부분에서 설명합니다.)
옵션에서 복사되는 프라이 머리 키 컬럼의 뒤에 추가 컬럼을 정의 할 수 있지만 그 전에 추가 컬럼을 정의 할 수 없습니다. 이러한 추가 컬럼은 NOT NULL
은 없습니다. MySQL Cluster NDB 7.4.1 이상에서는 미리 정의 된 3 개의 추가 옵션 컬럼 NDB $ OP_TYPE
, NDB $ CFT_CAUSE
및 NDB $ ORIG_TRANSID
(다음 몇 절에서 설명합니다)를 지원합니다.
NDB $ OP_TYPE
:이 컬럼은 충돌의 원인이되는 조작 유형을 얻기 위해 사용할 수 있습니다. 이 컬럼을 사용하는 경우, 여기서 같이 정의합니다.
NDB$OP_TYPE ENUM('WRITE_ROW', 'UPDATE_ROW', 'DELETE_ROW', 'REFRESH_ROW', 'READ_ROW') NOT NULL
WRITE_ROW
, UPDATE_ROW
및 DELETE_ROW
작업 유형은 사용자 시작 작업을 나타냅니다. REFRESH_ROW
작업은 충돌을 감지 한 클러스터에서 원래 클러스터에 반환 된 트랜잭션을 상쇄 할 때 충돌 해결에 의해 생성되는 작업입니다. READ_ROW
작업은 배타적 행 잠금을 사용하여 정의 된 사용자 시동 읽기 추적 작업입니다.
NDB $ CFT_CAUSE
: 등록 된 충돌의 원인을 나타내는 옵션 컬럼 NDB $ CFT_CAUSE
을 정의 할 수 있습니다. 이 컬럼은 사용하는 경우 여기 같이 정의됩니다.
NDB$CFT_CAUSE ENUM('ROW_DOES_NOT_EXIST', 'ROW_ALREADY_EXISTS', 'DATA_IN_CONFLICT', 'TRANS_IN_CONFLICT') NOT NULL
ROW_DOES_NOT_EXIST
는 UPDATE_ROW
및 WRITE_ROW
조작의 원인으로보고 있습니다. ROW_ALREADY_EXISTS
는 WRITE_ROW
이벤트에 대해보고 할 수 있습니다. DATA_IN_CONFLICT
행 기반 충돌 함수가 충돌을 감지 한 경우에보고됩니다. TRANS_IN_CONFLICT
트랜잭션 충돌 함수가 전체 트랜잭션에 속하는 모든 작업을 거부하는 경우에보고됩니다.
NDB $ ORIG_TRANSID
: NDB $ ORIG_TRANSID
컬럼은 사용하면 원래의 트랜잭션 ID를 저장합니다. 이 열은 다음과 같이 정의됩니다.
NDB$ORIG_TRANSID BIGINT UNSIGNED NOT NULL
NDB $ ORIG_TRANSID
는 NDB
에 의해 생성되는 64 비트 값입니다. 이 값은 같은 또는 다른 예외 테이블에서 같은 경쟁 트랜잭션에 속하는 여러 예외 테이블의 항목을 상호 연결하는 데 사용됩니다.
MySQL Cluster NDB 7.4.1 이상에서 업데이트 및 삭제 작업 (즉, DELETE_ROW
이벤트를 포함한 작업입니다)에서 원래 테이블의 기본 키의 일부가 아닌 추가 참조 컬럼의 이름을
또는 colname
$ OLD
. colname
$ NEW
참조 이전 값으로 할 수 있습니다. colname
$ OLD
는 삽입 및 업데이트 작업 (즉, colname
$ NEWWRITE_ROW
이벤트 UPDATE_ROW
이벤트 또는 두 가지 유형의 이벤트를 사용하는 작업입니다)에서 새로운 값의 참조에 사용할 수 있습니다. 경합중인 작업은 특정 비 기본 키 참조 컬럼 값은 지정되지 않습니다 만, 예외 테이블의 행에 NULL
또는 그 컬럼에 정의 된 디폴트 값 중 하나가 포함됩니다.
mysql.ndb_replication
테이블은 데이터 테이블이 복제 용으로 설정된 경우 읽기 때문에 복제 된 테이블에 해당하는 행은 복제 된 테이블이 생성되는 이전 에 mysql.ndb_replication
에 삽입해야합니다 .
Examples
이 예제에서는 섹션 18.6.5 "복제를위한 MySQL Cluster 준비" 및 섹션 18.6.6 "MySQL Cluster 복제의 시작 (복제 채널이 하나)" 에서 설명한대로 이미 MySQL Cluster 복제 설치가 성공적으로 작동하는 것으로합니다.
NDB $ MAX ()의 예 " 타임 스탬프 " 로 컬럼 mycol
을 사용하여 테이블 test.t1
에서 " 가장 큰 타임 스탬프가 우선 " 충돌 해결을 활성화해야합니다. 이것은 다음 단계에서 실행할 수 있습니다.
--ndb-log-update-as-write = OFF
에서 마스터 mysqld 를 시작했는지 확인합니다.마스터에서
INSERT
문을 실행합니다.INSERT INTO mysql.ndb_replication VALUES ('test', 't1', 0, NULL, 'NDB$MAX(mycol)');
server_id
에 0을 삽입하면이 테이블에 액세스하는 모든 SQL 노드가 충돌 해결을 사용합니다. 특정 mysqld 만으로 충돌 해결을 사용할 경우 실제 서버 ID를 사용합니다.binlog_type
컬럼에NULL
를 삽입하면 0 (NBT_DEFAULT
)의 삽입과 같은 효과가 있으며, 서버의 기본값이 사용됩니다.test.t1
테이블을 만듭니다.CREATE TABLE test.t1 (
columns
mycol INT UNSIGNED,columns
) ENGINE=NDB;이제이 테이블에 업데이트가 이루어지면 충돌 해결이 적용되어
mycol
의 가장 큰 값을 가진 행 버전이 슬레이브에 기록됩니다.
다른 binlog_type
옵션 ( NBT_UPDATED_ONLY_USE_UPDATE
등)은 명령 행 옵션을 사용하는 것이 아니라 ndb_replication
테이블을 사용하여 마스터로 로깅을 제어하는 데 사용하십시오.
NDB $ OLD ()의 예 NDB
테이블 (여기에서 정의 된 테이블 등)가 복제 중이며,이 테이블에 업데이트 " 같은 타임 스탬프가 우선 " 충돌 해결을 활성화해야합니다.
CREATE TABLE test.t2 ( a INT UNSIGNED NOT NULL, b CHAR(25) NOT NULL,columns
, mycol INT UNSIGNED NOT NULL,columns
, PRIMARY KEY pk (a, b) ) ENGINE=NDB;
여기에 표시된 순서대로 다음 단계가 필요합니다.
우선 (
test.t2
을 만들 전에 ) 여기에서 같이mysql.ndb_replication
테이블에 행을 삽입해야합니다.INSERT INTO mysql.ndb_replication VALUES ('test', 't2', 0, NULL, 'NDB$OLD(mycol)');
binlog_type
열에 가능한 값은이 섹션의 앞부분에 보여줍니다. 값'NDB $ OLD (mycol)'
를conflict_fn
컬럼에 삽입하십시오.test.t2
에 대응하는 예외 테이블을 만듭니다. 여기에 표시된 테이블 생성 문은 모든 필수 열을 포함합니다. 이러한 필수 열 후와 테이블의 기본 키 정의 앞에 추가 컬럼을 선언해야합니다.CREATE TABLE test.t2$EX ( server_id SMALLINT UNSIGNED, master_server_id INT UNSIGNED, master_epoch BIGINT UNSIGNED, count BIGINT UNSIGNED, a INT UNSIGNED NOT NULL, b CHAR(25) NOT NULL, [
additional_columns
,] PRIMARY KEY(server_id, master_server_id, master_epoch, count) ) ENGINE=NDB;MySQL Cluster NDB 7.4.1 이상에서 특정 경쟁에 대한 유형, 원인 및 원래 트랜잭션 ID에 대한 정보의 컬럼을 추가 할 수 있습니다. 원래 테이블의 모든 프라이 머리 키 컬럼과 일치하는 컬럼을 제공 할 필요도 없습니다. 이 버전에서는 다음과 같이 예외 테이블을 만들 수 있습니다.
CREATE TABLE test.t2$EX ( NDB$server_id SMALLINT UNSIGNED, NDB$master_server_id INT UNSIGNED, NDB$master_epoch BIGINT UNSIGNED, NDB$count BIGINT UNSIGNED, a INT UNSIGNED NOT NULL, NDB$OP_TYPE ENUM('WRITE_ROW','UPDATE_ROW', 'DELETE_ROW', 'REFRESH_ROW', 'READ_ROW') NOT NULL, NDB$CFT_CAUSE ENUM('ROW_DOES_NOT_EXIST', 'ROW_ALREADY_EXISTS', 'DATA_IN_CONFLICT', 'TRANS_IN_CONFLICT') NOT NULL, NDB$ORIG_TRANSID BIGINT UNSIGNED NOT NULL, [
additional_columns
,] PRIMARY KEY(NDB$server_id, NDB$master_server_id, NDB$master_epoch, NDB$count) ) ENGINE=NDB;하나의 컬럼
NDB $ OP_TYPE
,NDB $ CFT_CAUSE
또는NDB $ ORIG_TRANSID
을 테이블 정의에 포함했기 때문에 4 개의 필수 컬럼에NDB $
접두어가 필요합니다.앞에서 언급 한 바와 같이, 테이블
test.t2
을 만듭니다.
NDB $ OLD ()
를 사용하여 충돌 해결을 수행하는 테이블에 대해 이러한 단계를 수행해야합니다. 이러한 테이블마다 mysql.ndb_replication
에 해당하는 행이 복제 된 테이블과 같은 데이터베이스에 예외 테이블이 있어야합니다.
읽기 충돌 감지 및 해결 MySQL Cluster NDB 7.4.1 이상에서는 읽기 작업의 추적을 지원하고 있습니다. 이렇게하면 클러스터의 특정 행을 읽고 다른 클러스터의 같은 행을 갱신 또는 h 사이에서 충돌을 관리 할 수 순환 복제 설정에서 가능합니다. 이 예제에서는 employee
및 department
테이블을 사용하여 시나리오를 모델링합니다. 이 시나리오에서는 직원이있는 부서에서 다른 부서에 마스터 클러스터 (이후 클러스터 A 라고 함)에 가서 한편, 슬레이브 클러스터 (이후 B 라고 함)는 직원의 전 부문 종업원 수를 인터리브 된 트랜잭션으로 업데이트합니다.
데이터 테이블은 다음 SQL 문으로 작성되었습니다.
# Employee table CREATE TABLE employee ( id INT PRIMARY KEY, name VARCHAR(2000), dept INT NOT NULL ) ENGINE=NDB; # Department table CREATE TABLE department ( id INT PRIMARY KEY, name VARCHAR(2000), members INT ) ENGINE=NDB;
두 테이블의 내용은 다음의 SELECT
문의 출력 (일부)에 나타나는 행을 포함합니다.
mysql>SELECT id, name, dept FROM employee;
+---------------+------+ | id | name | dept | +------+--------+------+ ... | 998 | Mike | 3 | | 999 | Joe | 3 | | 1000 | Mary | 3 | ... +------+--------+------+ mysql>SELECT id, name, members FROM department;
+-----+-------------+---------+ | id | name | members | +-----+-------------+---------+ ... | 3 | Old project | 24 | ... +-----+-------------+---------+
4 개의 필수 컬럼 (이들은이 테이블의 기본 키에 사용됩니다) 작업 유형과 원인에 대한 옵션 컬럼 및 원본 테이블의 프라이 머리 키 컬럼을 포함한 여기에 나와있는 SQL 문에서 생성 된 예외 테이블 이미 사용하고있는 것으로합니다.
CREATE TABLE employee$EX ( NDB$server_id INT UNSIGNED, NDB$master_server_id INT UNSIGNED, NDB$master_epoch BIGINT UNSIGNED, NDB$count INT UNSIGNED, NDB$OP_TYPE ENUM( 'WRITE_ROW','UPDATE_ROW', 'DELETE_ROW', 'REFRESH_ROW','READ_ROW') NOT NULL, NDB$CFT_CAUSE ENUM( 'ROW_DOES_NOT_EXIST', 'ROW_ALREADY_EXISTS', 'DATA_IN_CONFLICT', 'TRANS_IN_CONFLICT') NOT NULL, id INT NOT NULL, PRIMARY KEY(NDB$server_id, NDB$master_server_id, NDB$master_epoch, NDB$count) ) ENGINE=NDB;
두 클러스터에서 동시에 두 개의 트랜잭션이 발생하는 것으로합니다. 클러스터 A 에서 새로운 부를 창조하고 직원 번호 999를 해당 부서로 이동합니다. 다음 SQL 문을 사용합니다.
BEGIN
;INSERT
INTO department VALUES (4, "New project", 1);UPDATE
employee SET dept = 4 WHERE id = 999; COMMIT;
동시에 클러스터 B 는 다음과 같이 다른 트랜잭션이 employee
에서 읽습니다.
BEGIN;
SELECT name FROM employee WHERE id = 999;
UPDATE department SET members = members - 1 WHERE id = 3;
commit;
충돌하는 트랜잭션은 일반적으로 충돌 해결 메커니즘에서 감지되지 않습니다. 이것은 충돌이 읽기 ( SELECT
) 및 업데이트 작업 사이에서 발생하고 있기 때문입니다. MySQL Cluster NDB 7.4.1 이상에서 슬레이브 클러스터에서 SET
ndb_log_exclusive_reads
= 1
을 실행하여이 문제를 해결할 수 있습니다. 이 방법으로 독점 읽기 락을 취득하면 마스터에서 행 읽기 슬레이브 클러스터에서 충돌 해결이 필요함을 나타내는 플래그가 붙습니다. 이러한 트랜잭션 로깅 전에이 방법으로 독점 읽기를 사용하면 클러스터 B 에서 읽기가 추적되고 해결을 위해 클러스터 A 에 보내집니다. 직원의 행의 충돌이 감지되고 클러스터 B 에서 트랜잭션이 중단됩니다.
경쟁은 여기에서 볼 수 있듯이 (클러스터 A 의) 예외 테이블에 READ_ROW
작업으로 등록됩니다 (작업 유형에 대한 설명은 충돌 해결 예외 테이블 을 참조하십시오).
mysql> SELECT id, NDB$OP_TYPE, NDB$CFT_CAUSE FROM employee$EX;
+-------+-------------+-------------------+
| id | NDB$OP_TYPE | NDB$CFT_CAUSE |
+-------+-------------+-------------------+
...
| 999 | READ_ROW | TRANS_IN_CONFLICT |
+-------+-------------+-------------------+
읽기 작업에서 검출 된 존재하는 모든 행에 플래그가 지정됩니다. 즉, 여기서 같이 클러스터 A 에서 업데이트와 동시에 발생한 트랜잭션에서 같은 테이블에서 클러스터 B 에서 여러 행 읽기 사이에서 경쟁의 영향을 조사하는 것으로, 예외 테이블에 동일한 경쟁에 인해 여러 줄의 로그가 취해지는 경우가 있습니다. 여기에서 클러스터 A 에서 실행되는 트랜잭션을 나타냅니다.
BEGIN;
INSERT INTO department VALUES (4, "New project", 0);
UPDATE employee SET dept = 4 WHERE dept = 3;
SELECT COUNT(*) INTO @count FROM employee WHERE dept = 4;
UPDATE department SET members = @count WHERE id = 4;
COMMIT;
동시에 여기에 표시된 문을 포함하는 트랜잭션이 클러스터 B 에서 실행됩니다.
SET ndb_log_exclusive_reads = 1; # Must be set if not already enabled
...
BEGIN;
SELECT COUNT(*) INTO @count FROM employee WHERE dept = 3 FOR UPDATE;
UPDATE department SET members = @count WHERE id = 3;
COMMIT;
이 경우 지금과 같이 두 번째 트랜잭션 SELECT
중 WHERE
조건에 일치하는 3 개의 모든 행을 읽어 예외 테이블에서 플래그가 지정됩니다.
mysql> SELECT id, NDB$OP_TYPE, NDB$CFT_CAUSE FROM employee$EX;
+-------+-------------+-------------------+
| id | NDB$OP_TYPE | NDB$CFT_CAUSE |
+-------+-------------+-------------------+
...
| 998 | READ_ROW | TRANS_IN_CONFLICT |
| 999 | READ_ROW | TRANS_IN_CONFLICT |
| 1000 | READ_ROW | TRANS_IN_CONFLICT |
...
+-------+-------------+-------------------+
읽기의 추적은 존재하는 행만을 기준으로 이루어집니다. 특정 조건의 추적에 기반 읽기는 검출 된 행만와 충돌 인터리브 된 트랜잭션에 삽입 된 행과 충돌하지 않습니다. 이것은 MySQL Cluster의 하나의 인스턴스에서 배타적 행 잠금이 수행되는 방법과 유사합니다.