MySQL 스터디에서 공유했던 MySQL 8과 5.7 간 replication 기능의 차이점 위주로 정리한 내용입니다.

복제관련해서 무언가 기존엔 없던 새로운 기능이 생겨난 게 아니라 기존 기능에서 좀 더 개선된 사항들이 나왔다.

  • MSR replicate_rewrite_db 필터 적용 범위 개선 (global -> channel)
  • crash safe replication을 위한 파라미터의 변경
  • semi-sync의 동작방식에 대한 변경
  • binary log 트랜잭션 압축 기능 추가
  • multi threaded replication에서 writeset 기능 추가

multi source replication

변경사항 : multi source replication에서 replication filter 중 REPLICATE_REWRITE_DB가 global이 아닌 channel 별로 적용됨 mysql 5.7 버전부터 multi-source replication 기능이 생기면서 유용하게 사용되고 있지만 두대 이상의 Master 에서 같은 이름의 database를 구분 지어 다른 db명으로 변경해서 replication 설정은 불가능했음 MySQL 8.0부터 MSR 구성에서 REPLICATE_REWRITE_DB 설정이 global 이 아닌, channel 별로 가능해짐

mysql 5.7

Master 1: kimdubi_db => Slave : kimdubi_db
Master 2: kimdubi_db => Slave : kimdubi_db
  • Master server들의 논리DB명이 같으면 Slave 서버에서는 이를 구분해서 각각 받아올 수가 없음
  • change replication filter replicate_do_db=(master1,master2), replicate_rewrite_db=((kimdubi_test,master1),(kimdubi_test,master2));
    • 이렇게 해도 replicate_rewrite_db 설정이 channel 별이 아닌 global로 적용되어서 master1로 데이터를 받게됨
    • 만약 Master 1번 서버에서 delete 를 했다? binlog format=ROW 가 아니면 복제가 깨질 수 있음

mysql 8.0

Master 1: kimdubi_db => Slave : kimdubi_db1
Master 2: kimdubi_db => Slave : kimdubi_db2
  • MySQL 5.7과 달리 Master서버들의 논리DB가 같아도 채널별로 논리DB를 rewrite해서 받아올 수 있음
mysql> CHANGE REPLICATION FILTER REPLICATE_DO_DB = (kimdubi_db1), REPLICATE_REWRITE_DB = (kimdubi_db, kimdubi_db1)) FOR CHANNEL 'master_1';
mysql> CHANGE REPLICATION FILTER REPLICATE_DO_DB = (kimdubi_db2), REPLICATE_REWRITE_DB = (kimdubi_db, kimdubi_db2)) FOR CHANNEL 'master_2';
  • REPLICATE_REWRITE_DB = kimdubi_db,kimdubi_db2
    • 앞의 kimdubi_db는 source DB의 논리DB, 뒤의 kimdubi_db2는 앞의 kimdubi_db를 rewrite 치환해서 slave에서 replication 받는 DB
    • relay log에서 kimdubi_db로 들어오고 sql_thread가 relaylog를 읽고 DB에 반영하면서 kimdubi_db2로 바꾸어 읽게 됨

구성방법

mysql> show variables like '%repository%';
+---------------------------+-------+
| Variable_name             | Value |
+---------------------------+-------+
| master_info_repository    | TABLE |
| relay_log_info_repository | TABLE |
+---------------------------+-------+
  • MSR 설정을 위해서는 replication 관련 정보 repository 를 TABLE 에 저장해야함
  • master_info_repository=TABLE 의미는 Slave가 복제하는 MASTER DB의 status와 connection inforamtion 정보를 mysql.slave_master_info 에 저장하겠다는 의미
  • relay_log_info_repository=TABLE => 복제 관련 파일 및 포지션 정보를 mysql.slave_relay_log_info 에 저장
  • 8.0부터 default TABLE

replication channel 구성

mysql> change master to
    -> master_host='172.17.0.6',
    -> master_port=3306,
    -> master_user='replUser',
    -> master_password='!dlatl00',
    -> master_log_file='mysql-bin.000011',
    -> master_log_pos=789
    -> for channel 'master_1';      <============= 채널
Query OK, 0 rows affected, 2 warnings (0.05 sec)

mysql> change master to
    -> master_host='172.17.0.7',
    -> master_port=3306,
    -> master_user='replUser',
    -> master_password='!dlatl00',
    -> master_log_file='mysql-bin.000010',
    -> master_log_pos=1099
    -> for channel 'master_2';     <============= 채널
Query OK, 0 rows affected, 2 warnings (0.04 sec)

mysql> CHANGE REPLICATION FILTER REPLICATE_DO_DB = (kimdubi_db1), REPLICATE_REWRITE_DB = (kimdubi_db, kimdubi_db1)) FOR CHANNEL 'master_1';
Query OK, 0 rows affected (0.01 sec)

mysql> CHANGE REPLICATION FILTER REPLICATE_DO_DB = (kimdubi_db2), REPLICATE_REWRITE_DB = (kimdubi_db, kimdubi_db2)) FOR CHANNEL 'master_2';
Query OK, 0 rows affected (0.01 sec)



mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.17.0.6
                  Master_User: replUser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000011
          Read_Master_Log_Pos: 992
               Relay_Log_File: relay-bin-master_1.000003
                Relay_Log_Pos: 322
        Relay_Master_Log_File: mysql-bin.000011
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes

              Replicate_Do_DB: kimdubi_db1

          Exec_Master_Log_Pos: 992
              Relay_Log_Space: 903
              Until_Condition: None

             Master_Server_Id: 64
                  Master_UUID: ba315763-e7e8-11e9-9c29-0242ac110002
             Master_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400

         Replicate_Rewrite_DB: (kimdubi_db,kimdubi_db1)
                 Channel_Name: master_1

*************************** 2. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.17.0.7
                  Master_User: replUser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000010
          Read_Master_Log_Pos: 1302
               Relay_Log_File: relay-bin-master_2.000004
                Relay_Log_Pos: 322
        Relay_Master_Log_File: mysql-bin.000010
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: kimdubi_db2

          Exec_Master_Log_Pos: 1302
              Relay_Log_Space: 903

             Master_Server_Id: 2
                  Master_UUID: ba315763-e7e8-11e9-9c29-0242ac110002
             Master_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400

         Replicate_Rewrite_DB: (kimdubi_db,kimdubi_db2)
                 Channel_Name: master_2

2 rows in set (0.00 sec)

복제 테스트

  • MySQL 8.0
### MASTER_1 에서 수행
mysql> use kimdubi_db;
Database changed

mysql> create table test (t int);
Query OK, 0 rows affected (0.09 sec)

mysql> insert into test values(1);
Query OK, 1 row affected (0.05 sec)


### MASTER_2 에서 수행
mysql> use kimdubi_db;
Database changed
mysql> create table test (t int);
Query OK, 0 rows affected (0.07 sec)

mysql> insert into test values(2);
Query OK, 1 row affected (0.03 sec)


### SLAVE에서 데이터 확인
mysql> select * from kimdubi_db1.test;
+------+
| t    |
+------+
|    1 |
+------+
1 row in set (0.01 sec)

mysql> select * from kimdubi_db2.test;
+------+
| t    |
+------+
|    2 |
+------+
1 row in set (0.00 sec)
  • MySQL 5.7
### MASTER_1 에서 수행
mysql> use kimdubi_db;
Database changed

mysql> create table test (t int);
Query OK, 0 rows affected (0.09 sec)

mysql> insert into test values(1111111);
Query OK, 1 row affected (0.05 sec)


### MASTER_2 에서 수행
mysql> use kimdubi_db;
Database changed
mysql> create table test (t int);
Query OK, 0 rows affected (0.07 sec)

mysql> insert into test values(222222);
Query OK, 1 row affected (0.03 sec)


### slave에서 조회
mysql> select * from kimdubi_db2.tb_test;
Empty set (0.01 sec)

mysql> select * from kimdubi_db1.tb_test;
+---------+
| a       |
+---------+
|  222222 |
| 1111111 |
+---------+
2 rows in set (0.01 sec)


### 데이터 깨짐 현상

### master_1
mysql> select * from tb_test;
+---------+
| a       |
+---------+
| 1111111 |
+---------+
1 row in set (0.00 sec)

### 복제DB
mysql> select * from tb_test;
+---------+
| a       |
+---------+
|   22222 |
| 1111111 |
+---------+
2 rows in set (0.00 sec)

### master_1
mysql> set session binlog_format='STATEMENT';
Query OK, 0 rows affected (0.00 sec)

mysql> delete from tb_test where a < 11111111;
Query OK, 1 row affected (0.01 sec)

### 복제DB
mysql> select * from tb_test;
Empty set (0.00 sec)

=> master_2 에서 받은 데이터도 모두 날아간 상태에서 master_2에서 해당 데이터에 대해 DML이 들어오면?

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.17.0.4
                  Master_User: root
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000001
          Read_Master_Log_Pos: 4046
               Relay_Log_File: 8bb84cc87d63-relay-bin-master_1.000005
                Relay_Log_Pos: 856
        Relay_Master_Log_File: mysql-bin.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: No
              Replicate_Do_DB: master1,master2
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 1032
                   Last_Error: Could not execute Delete_rows event on table master1.tb_test; Can't find record in 'tb_test', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log mysql-bin.000001, end_log_pos 4015

crash safe replication

변경사항 : crash_safe replication의 필수 설정 중 하나인 relay_log_info_repository 설정의 default 값이 FILE -> TABLE로 변경됨 MySQL 서버가 예기치 못한 장애로 인해 비정상 종료 되는 경우, SLAVE를 재기동 했을 때 복제가 원활하게 재개될수 있도록 하는 여러 설정 조합의 효과

  • I/O thread가 relay log에 복제할 event를 기록하고 sync_master_info 파일에 기록하기 전에 MySQL서버가 비정상 종료되면, MySQL을 재기동한 뒤 I/O thread가 위의 이벤트를 relay log에 또다시 기록해서 복제 duplicate 날 수 있음
  • SQL thread가 relay log에 기록된 트랜잭션을 커밋한 후 sync_relay_log_info 파일에 포지션 정보를 기록하기 전에 MySQL서버가 비정상 종료되면, MySQL을 재기동한 뒤 위의 동일한 트랜잭션을 또 replay할 수 있음

crash-safe Replicaion 설정

필수

  • relay_log_info_repository=TABLE
  • relay_log_recovery = on

그 외 상황별 필요 파라미터

variableMySQL 5.7 (default)MySQL 8.0 (default)comment
relay_log_recoveryOFFOFF필수 ON
relay_log_info_repositoryFILETABLEGTID 복제 시엔 필요없음 (mysql.gtid_executed가 대체)
sync_relay_log1000010000MTS + slave_preserve_commit_order=0 일 땐 sync_relay_log = 1 필요
slave_preserve_commit_orderOFFOFF / ON (MySQL 8.0.27이상부터는 ON)권장값 ON (트랜잭션 갭 메울 필요 없어짐)
sync_binlog11GTID 복제 시 sync_binlog = 1 필요 (replica서버에서)
innodb_flush_log_at_trx_commit11GTID 복제 시 innodb_flush_log_at_trx_commit =1 필요 (replica서버에서)

동작 방식

### relay_log_info_repository = TABLE
begin;
insert into tb_test values(1);
update mysql.slave_relay_log_info set Relay_log_name='./relay-bin.000006',replay_log_pos=1356;
commit;

### relay_log_recovery = ON
2020-05-03T12:19:21.402872Z 0 [Warning] [MY-010539] [Repl] Recovery from master pos 1142 and file mysql-bin.000003 for channel ''. Previous relay log pos and relay log file had been set to 322, ./relay-bin.000014 respectively.
  • relay_log_info_repository = TABLE 설정 시 위 처럼, SQL thread가 position 정보 업데이트와 실제 트랜잭션 처리를 원자적으로 수행함
  • 반면 I/O thread는 실제 relay log 파일에도 쓰고, mysql.slave_master_info 테이블에도 update하는 작업을 sql thread처럼 원자적으로 수행할 수 없음
    • relay_log_recovery = ON 설정 시 I/O thread의 포지션을 SQL thread가 마지막으로 실행했던 포지션으로 초기화 하고 새로운 relay log 파일을 생성해서 sql thread가 읽어야할 relay log position을 초기화하는 식으로 동작하게 하여 I/O thread의 문제를 해결할 수 있음

mysql.slave_master_info, mysql.slave_relay_log_info 테이블 내용

mysql> select * from slave_relay_log_info;
+-----------------+------------------------------------------+---------------+------------------+----------------+-----------+-------------------+----+--------------+
| Number_of_lines | Relay_log_name                           | Relay_log_pos | Master_log_name  | Master_log_pos | Sql_delay | Number_of_workers | Id | Channel_name |
+-----------------+------------------------------------------+---------------+------------------+----------------+-----------+-------------------+----+--------------+
|               7 | ./8bb84cc87d63-relay-bin-master_1.000005 |           856 | mysql-bin.000001 |           3763 |         0 |                 0 |  1 | master_1     |
|               7 | ./8bb84cc87d63-relay-bin-master_2.000004 |          1124 | mysql-bin.000001 |           3493 |         0 |                 0 |  1 | master_2     |
+-----------------+------------------------------------------+---------------+------------------+----------------+-----------+-------------------+----+--------------+
2 rows in set (0.00 sec)

mysql> select * from slave_master_info;
+-----------------+------------------+----------------+------------+-----------+---------------+------+---------------+-------------+--------+------------+----------+------------+---------+------------------------+-----------+------+--------------------+--------------------------------------+-------------+---------+-------------+-----------------------+--------------+-------------+
| Number_of_lines | Master_log_name  | Master_log_pos | Host       | User_name | User_password | Port | Connect_retry | Enabled_ssl | Ssl_ca | Ssl_capath | Ssl_cert | Ssl_cipher | Ssl_key | Ssl_verify_server_cert | Heartbeat | Bind | Ignored_server_ids | Uuid                                 | Retry_count | Ssl_crl | Ssl_crlpath | Enabled_auto_position | Channel_name | Tls_version |
+-----------------+------------------+----------------+------------+-----------+---------------+------+---------------+-------------+--------+------------+----------+------------+---------+------------------------+-----------+------+--------------------+--------------------------------------+-------------+---------+-------------+-----------------------+--------------+-------------+
|              25 | mysql-bin.000001 |           3227 | 172.17.0.4 | root      | qhdks123      | 3306 |            60 |           0 |        |            |          |            |         |                      0 |        30 |      | 0                  | 6ee46ea8-753f-11ec-be3b-0242ac110004 |       86400 |         |             |                     0 | master_1     |             |
|              25 | mysql-bin.000001 |           2689 | 172.17.0.5 | root      | qhdks123      | 3306 |            60 |           0 |        |            |          |            |         |                      0 |        30 |      | 0                  | bfe2850b-753f-11ec-8148-0242ac110005 |       86400 |         |             |                     0 | master_2     |             |
+-----------------+------------------+----------------+------------+-----------+---------------+------+---------------+-------------+--------+------------+----------+------------+---------+------------------------+-----------+------+--------------------+--------------------------------------+-------------+---------+-------------+-----------------------+--------------+-------------+
2 rows in set (0.00 sec)

semi-sync

변경사항 : semi-sync의 동작방식이 after_commit -> after_sync로 변경됨

after_commit

  1. User transaction commit
  2. Engine prepare
  3. Binlog flush
  4. Binlog commit
  5. Engine commit
  6. Binlog dump thread send event with ACK Request
  7. semi-sync wait (AFTER_COMMIT)
  8. User Commit OK
  • 7번 Slave가 data를 받았다는 응답을 기다리는 도중 Master가 down 되면 Master에서는 이미 Engine commit 까지 된 상황이기 때문에 새로 승격될 Slave에는 데이터가 없지만 Old Master에는 데이터가 존재하여 정합성이 깨짐
  • 5번 engine commit 이 된 시점부터 다른 세션에서는 변경된 데이터를 읽을 수 있음 (phantom read) SLAVE로의 복제가 실패하면 이 트랜잭션은 Master에서 수동으로 rollback 처리해야함

after_sync

  1. User transaction commit
  2. Engine prepare
  3. Binlog flush
  4. Binlog commit
  5. Binlog dump thread send event with ACK Request
  6. loss-less semisync wait (AFTER_SYNC)
  7. Engine commit
  8. User Commit OK
  • after_sync에서는 레플리카 서버에 복제되지 않았다면, 소스 서버에서도 engine commit까지 될 수 없기 때문에 after_commit의 phantom read 같은 경우가 발생하지 않음
  • engine commit이 늦춰져서 semi-sync에 대한 부담감이 높아질 수 있음
    • 아래 파라미터를 적절하게 변경해보자
    • rpl_semi_sync_master_timeout (default 10초)
    • rpl_semi_sync_master_wait_for_slave_count (default 1)

binary log 트랜잭션 압축

변경사항 : binlog_format = ROW으로 기록되는 트랜잭션에 대해 트랜잭션에서 변경한 데이터를 압축해서 바이너리 로그에 기록하는 기능이 추가도미

  • 트랜잭션에서 변경한 데이터를 zstd 알고리즘으로 압축
  • transaction_payload_event라는 이벤트로 바이너리 로그에 기록
  • 압축된 상태로 레플리카 서버의 relay log에 기록됨
  • 압축 해제 후 레플리카 서버에 반영됨
  • 마스터 뿐만 아니라 리플리카도 압축 기능을 지원하는 MySQL 버전을 사용해야함
  • 효과는 압축률 50%정도, 네트워크 사용량은 1/3 정도, CPU는 조금 더 쓰는 정도

관련 파라미터

  • binlog_transaction_compression (default OFF )
  • binlog_transaction_compression_level_zstd (default 3)
  • performance-schema-instrument=“stage/sql/%compressing_transaction_changes.=ON”
  • protocol_compression_algorithms=‘zlib,zstd,uncompressed’;

limitation

  • GTID 설정 관련 이벤트
  • 복제 구성에서 heartbeat 관련 이벤트
  • 복제 실패 / 데이터 불일치를 발생시킬 수 있는 incident 타입의 이벤트(?)
  • 트랜잭션을 지원하지 않는 스토리지 엔진에 대한 이벤트
  • binlog_format = statement 로 기록되는 이벤트

구성 방법

mysql> change master to
    -> master_host='172.17.0.6',
    -> master_port=3306,
    -> master_user='replUser',
    -> master_password='!dlatl00',
    -> master_log_file='mysql-bin.000011',
    -> master_log_pos=789
    -> source_compression_algorithms='zstd',
    -> source_zstd_compression_level=7;

delayed replication

변경사항 : binary log에 OCT, ICT timestamp가 추가되었고 특히 ICT는 delayed replication의 기준으로 작용함

original_commit_timestamp (OCT)

  • 트랜잭션이 원본 소스 서버에서 커밋된 시각

immediate_commit_timestamp (ICT)

  • 트랜잭션이직계 소스 서버에서 커밋된 시각

어디에 쓰이는고

  • 체인 복제 구성 + delayed replication의 구조에서 의미가 있는 듯
  • 원본 소스 서버에서는 OCT == ICT
  • 레플리카 서버(log_slave_updates = ON)에서는 ICT 값이 복제된 트랜잭션이 커밋된 시점으로 기록되기 때문에 OCT != ICT MySQL 8.0 미만의 체인복제 구성에서 delayed replication의 지연 측정 기준이 원본 소스의 시각으로 측정되던 부분이 직계 소스 서버를 기준으로 할 수 있도록 개선되었음

multi-threaded replication

변경사항 : multi-thread-replication의 slave_parallel_type=‘logical_clock’ 방식 중 writeset 방식이 추가됨

관련 파라미터

variableMySQL 5.7 (default)MySQL 8.0 (default)comment
slave_parallel_typeDATABASE8.0.27 >= LOGICAL_CLOCK / 미만 DATABASE
slave_parallel_workers18.0.27 >= 4 / 미만 1
slave_pending_jobs_size_max16MB128MBmax_allowed_packet 보다 클 수 없음
binlog_transaction_dependency_trackingCOMMIT_ORDERCOMMIT_ORDER
slave_preserve_commit_orderOFF8.0.27 >= ON / 미만 OFFmysql 8.0.18 이하 버전에서 ON 하려면 log_slave_updates =ON 설정도 필요함
binlog_order_commitsONONreplication source 서버에 설정
binlog_formatROWROWwriteset을 사용하기 위해서는 ROW 포맷 필요
## slave_pending_jobs_size_max가 작을 때 발생 가능 에러

Cannot schedule event Update_rows, relay-log relay-bin.0000,position 0000 to Worker thread because its size 21206802 exceeds 16777216 of slave_pending_jobs_size_max

## slave_preserve_commit_order ON 꼬였을 때 발생 가능 에러

ER_SLAVE_WORKER_STOPPED_PREVIOUS_THD_ERROR
slave-preserve-commit-order가 활성화되었을 때 적어도 하나의 이전 작업자에 오류가 발생한 후 슬레이브 작업자가 중지되었습니다. 커밋 순서를 유지하기 위해 이 스레드에서 실행한 마지막 트랜잭션이 커밋되지 않았습니다. 실패한 스레드를 수정한 후 슬레이브를 다시 시작할 때 이 작업자도 수정해야 합니다.

database

  • 처음 multi threaded replication이 도입되었을 때 지원하던 방식으로 논리DB 단위로 병렬처리를 수행함
  • MySQL 서버에 논리DB가 하나밖에 존재하지 않거나, 각 논리DB별 쓰기 부하가 일정하지 않으면 효과가 없거나 떨어짐
  • slave_parallel_type=‘DATABASE’

logical

  • 소스 서버에서 트랜잭션들이 binary log로 기록될 때 각 트랜잭션별로 논리적인 순번 값을 부여해 레플리카 서버에서 트랜잭션의 순번 값을 바탕으로 병렬 복제 수행하는 기능
  • database type과는 달리 동일 논리DB여도 병렬 복제 가능
    • group commit 단위로 할당하기 때문
  • commit-parent 기반 logical clock
    • MySQL 5.7.2 ~ 5.7.5버전에서 사용됨
    • 소스서버에서 커밋 시점이 같은 트랜잭션들을 병렬 복제 처리함
    • 커밋 시점이 같은 트랜잭션인지 식별은 commit_seq_no 값을 binary log에 같이 기록해서 식별함
  • lock 기반 logical clock
    • MySQL 5.7.6 버전 ~
    • commit_seq_no 값이 달라도 커밋 처리 시점이 겹친다면 레플리카 서버에서 병렬 복제처리 가능
    • 이를 위해 binary log에 sequence_number, last_committed라는 값을 함께 기록함
      • sequence_number : 커밋된 트랜잭션에 대한 논리적인 순번 값
      • last_committed : 현 트랜잭션 이전의 가장 최근의 트랜잭션의 sequence_number
      • 실행하려는 트랜잭션의 last_committed 값 < 현재 실행 중인 트랜잭션들이 가지는 가장 작은 sequence_number 를 만족하는 트랜잭션들을 병렬처리함
      • 예시에서는 txn+1의 C < txn 의 S 일때 병렬복제 가능
  • 커밋시점이 겹치는 트랜잭션들을 늘려 병렬 복제 트랜잭션을 늘리기 위해 binlog_group_commit_sync_delay / binlog_group_commit_sync_no_delay_count를 같은 파라미터를 적절히 설정하기도함
# at 4485
#220118 13:41:09 server id 1  end_log_pos 4550 CRC32 0x2ad8ee5f         Anonymous_GTID  last_committed=17       sequence_number=18
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;

writeset

logical_clock 의 방식 중 하나

  • binlog_transaction_dependency_tracking
    • commit_order : 기존 MySQL 5.7의 lock 기반 logical clock으로 동작
    • writeset : 서로 다른 데이터를 변경한 트랜잭션들은 모두 병렬로 처리할 수 있음 (base는 commit_order지만 last_committed 부분을 처리하는 부분이 다름 p.536 )
    • wrtieset_session : 동일한 세션에서 실행된 트랜잭션들을 제외한 트랜잭션만 병렬 처리
  • 소스 서버의 트랜잭션의 커밋 처리 시점이 아닌 트랜잭션이 변경한 데이터를 기준으로 병렬 처리 가능 여부를 결정함
    • 변경된 데이터를 hashing해서 writeset 으로 표현함
      • table에 존재하는 unique한 key의 개수 만큼 생성됨
writeset=hash(index_name,db_name,db_name_length,table_name,table_name_length,value,value_length)

mysql> use test;
mysql> show create table jj10 \G
*************************** 1. row ***************************
       Table: jj10
Create Table: CREATE TABLE `jj10` (
  `id1` int(11) DEFAULT NULL,
  `id2` int(11) DEFAULT NULL,
  `id3` int(11) NOT NULL,
  PRIMARY KEY (`id3`),
  UNIQUE KEY `id1` (`id1`),
  KEY `id2` (`id2`)

$ insert into jj10 values(36,36,36);


### pk
(gdb) p pke
$1 = "PRIMARY?test?4jj10?40

### UK
(gdb) p pke
$4 = "id1?test?4jj10?436?2"
=> 이거를 해싱하여 writeset으로 변환
  • 위에서 생성된 writeset과 해당 데이터를 변경한 트랜잭션의 sequence_number 값이 key-value 형태로 해시맵 테이블에 저장됨
  • writeset으로 구성된 새로운 트랜잭션이 실행되면 위의 writeset 히스토리 테이블과 비교하여 충돌되는 wirteset이 있는지 비교하고 last_committed 값을 보정함
  • writeset 변환을 위한 추가 리소스, writeset 히스토리 테이블 구성을 위한 추가 메모리가 필요