본문 바로가기
MySQL

MySQL 8.0 Clone

by 돌프홍 2019. 12. 9.

이 문서는 다음 link 를 번역한 내용과 + 테스트 중 확인한 내용을 추가하였다.

https://mysqlserverteam.com/clone-create-mysql-instance-replica/

 

Cloning MySQL instance

 

복제를 위해서 MySQL replica 를 만드는 것은 너무 많은 과정이 포함되어있어서 번거롭다.

(백업/복구/binlog file, position 맞추기 등 - 이 post 에서는 해당 내용을 설명하지는 않겠다.)

 

Clone plugin 을 사용하면 replica 생성을 간단하게 해결할 수 있다.

 

MySQL 8.0.17 부터 CLONE SQL 구문이 소개되었다.

현재 MySQL 서버에서 clone 하여 다른 MySQL 서버에 구성한다.

 

Doner : source server (백업 대상 서버)

Recipient : target server  (replica)

 

InnoDB 스토리지 엔진에 저장된 data 와 meta data 모두를 일관성있게 snapshot 하여 target 으로 옮긴다.

 

Recipient 서버에서 CLONE SQL 구문 실행 시 서버는 자동으로 재시작 된다. (운영 중인 slave 에서 명령을 실행하면 안된다)

 

restart 는 과거 방식으로 데이터가 복사되어 전달하는 것과 같이 clone 된 snapshot 데이터의 recovery 를 포함된다.

 

recovery 단계가 완료되면 Donor 의 clone 인 Recipient (replica) 는 사용할 준비가 된다.

 

 

cloning process 에 대해 몇 가지 중요한 부분은 다음과 같다.

 

  • MySQL 설정 parameter 는 clone 되지 않으며 Recipient 는 clone 되기 전의 configuration 파라미터를 유지한다.

    그러나  Donor 와 Recipient 사이에 일치해야 하는 스토리지 configuration 에 대해서는 CLONE 이  parameter 가 일치하지 않는다는 error 를 발생시킨다. ( innodb_page_size 와 같은 )

  • Clone 플러그인은 binary log 는 clone 하지 않는다. HA 클러스터에 노드 추가를 위해서 donor 의 binary log 복제는 필요하지 않음.

  • Clone 플러그인은 InnoDB storage engine 만 지원한다. MyISAM 과 CSV 는 비어있는 테이블로 생성된다. 

  • Clone 은 Donor 에서 수행되는 모든 동시 DDL 을 block 한다.

  • Recipient 는 donner 의 instance 가 복제 시작되는 시점에 binary log 를 포함한 모든 데이터를 삭제한다. 
    ( 이미 운영중인 서버에서 실행하면 데이터가 모두 삭제되니 주의해야 한다 !! )

  • CLONE 하기 전에 반드시 recipient 의 데이터 백업이 필요하다.

 

Step-1 : Donor 선택 및 설정

 

mysql> INSTALL PLUGIN CLONE SONAME "mysql_clone.so";

Query OK, 0 rows affected (0.60 sec)

 

mysql> CREATE USER clone_user IDENTIFIED BY "clone_password";

Query OK, 0 rows affected (0.02 sec)

 

mysql> GRANT BACKUP_ADMIN ON *.* TO clone_user ;

Query OK, 0 rows affected (0.02 sec)

 

-- 진행 과정을 확인하기 위해 performance_schema 와 execute 권한을 수행

 

mysql> GRANT SELECT ON performance_schema.* TO clone_user ;

Query OK, 0 rows affected (0.00 sec)

 

mysql> GRANT EXECUTE ON *.* to clone_user ;

Query OK, 0 rows affected (0.00 sec)

 

 

Step-2 : Recipient 선택 및 설정

 

Donor 의 clone 이 되기 위한 서버를 선택한다.

clone plugin 을 설치하고, 현재 인스턴스 데이터를 clone 된 data 로 교체할 user 에게  CLONE_ADMIN 권한을 부여한다. 

valid donor 들의 리스트를 설정한다. 

 

mysql> INSTALL PLUGIN CLONE SONAME "mysql_clone.so";

Query OK, 0 rows affected (0.37 sec)

 

mysql> SET GLOBAL clone_valid_donor_list = "donor.host.com:3306";

Query OK, 0 rows affected (0.00 sec)

 

mysql> CREATE USER clone_user IDENTIFIED BY "clone_password" ;

Query OK, 0 rows affected (0.04 sec)

 

mysql> GRANT CLONE_ADMIN ON *.* to clone_user ;

Query OK, 0 rows affected (0.01 sec)

 

-- 마찬가지로 상황을 확인하기 위한 권한을 부여한다.

 

mysql> GRANT SELECT ON performance_schema.* TO clone_user ;

Query OK, 0 rows affected (0.01 sec)

 

mysql> GRANT EXECUTE ON *.* to clone_user ;

Query OK, 0 rows affected (0.01 sec)

 

 

Step-3. Recipient 에 접속하고 CLONE SQL 구문을 실행 

 

data cloning 이 진행 되는 동안에 Recipient 의 performance_schema view 를 사용하여 clone 작업의 진행도를 확인할 수 있다.

 

mysql> CLONE INSTANCE

     FROM clone_user@donor.host.com:3306

     IDENTIFIED BY "clone_password" ;

 

Query OK, 0 rows affected (22.67 sec)

 

 

위 명령이 완료되는 동안 mysql error log 에는 다음과 같이 남게된다.

 

2019-11-25T06:59:38.741186Z 79 [Warning] [MY-013460] [InnoDB] Clone removing all user data for provisioning: Started
2019-11-25T06:59:38.913759Z 79 [Warning] [MY-013460] [InnoDB] Clone removing all user data for provisioning: Finished
100 200 300 400 500
100 200 300 400 500
2019-11-25T07:00:02.063035Z 0 [System] [MY-010910] [Server] /mysql/bin/mysqld: Shutdown complete (mysqld 8.0.18)  MySQL Community Server - GPL.
2019-11-25T07:00:02.152136Z mysqld_safe Number of processes running now: 0
2019-11-25T07:00:02.156140Z mysqld_safe mysqld restarted

...
2019-11-25T07:00:10.208253Z 0 [System] [MY-010931] [Server] /mysql/bin/mysqld: ready for connections. Version: '8.0.18'  socket: '/tmp/mysql.sock'  port: 3306  MySQL Community Server - GPL.
2019-11-25T07:00:10.218958Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Socket: '/tmp/mysqlx.sock' bind-address: '::' port: 33060

 

내부적으로 file 을 복사할 때, "#clone" 이라는 postfix 를 붙이고 copy 된다.

 

drwxr-x--- 2 mysql mysql     4096 Nov 25 06:51 sys
-rw-r----- 1 mysql mysql     4096 Nov 25 06:51 ib_buffer_pool.#clone
drwxr-x--- 2 mysql mysql     4096 Nov 25 06:51 hong
drwxr-x--- 2 mysql mysql     4096 Nov 25 06:51 #clone
-rw-r----- 1 mysql mysql 12582912 Nov 25 06:51 ibdata1.#clone
-rw-r----- 1 mysql mysql 12582912 Nov 25 06:51 undo_002
-rw-r----- 1 mysql mysql 46137344 Nov 25 06:51 undo_001
-rw-r----- 1 mysql mysql 12582912 Nov 25 06:51 ibdata1
-rw-r----- 1 mysql mysql 25165824 Nov 25 06:51 mysql.ibd
-rw-r----- 1 mysql mysql 25165824 Nov 25 06:51 mysql.ibd.#clone
-rw-r----- 1 mysql mysql 12582912 Nov 25 06:51 undo_002.#clone
-rw-r----- 1 mysql mysql 46137344 Nov 25 06:51 undo_001.#clone

$ ls -al "#clone"
total 28
drwxr-x--- 2 mysql mysql 4096 Nov 25 06:51 .
drwxr-xr-x 9 mysql mysql 4096 Nov 25 06:51 ..
-rw-r----- 1 mysql mysql   74 Nov 25 06:51 #new_files
-rw-r----- 1 mysql mysql   80 Nov 25 06:51 #old_files
-rw-r----- 1 mysql mysql  212 Nov 25 06:51 #replace_files
-rw-r----- 1 mysql mysql    0 Nov 25 06:51 #status_error
-rw-r----- 1 mysql mysql  270 Nov 25 06:51 #view_progress
-rw-r----- 1 mysql mysql   85 Nov 25 06:51 #view_status

 

CLONE 명령을 수행하는 중에 Donor 와 Recipient 에 어떤 쿼리가 수행되는지 확인했다.

의외로 Donor 에 특별한 명령이 수행되지 않았음. ( 로그에 안남을 수도 있겠지만 .. )

 

 

Recipient

2019-11-25T08:01:04.663511Z        67 Query     CLONE INSTANCE FROM 'clone_user'@'donor.host.com':3306 IDENTIFIED BY <secret>

2019-11-25T08:01:04.782376Z        67 Execute   SET SQL_LOG_BIN = OFF

2019-11-25T08:01:04.782565Z        67 Execute   SET FOREIGN_KEY_CHECKS=0

2019-11-25T08:01:04.809630Z        67 Execute   DROP TABLE `hong`.`item`

2019-11-25T08:01:04.819693Z        67 Execute   DROP TABLE `hong`.`country`

2019-11-25T08:01:04.829376Z        67 Execute   DROP TABLE `hong`.`sales`

2019-11-25T08:01:04.840812Z        67 Execute   SET SQL_LOG_BIN = OFF

2019-11-25T08:01:04.840943Z        67 Execute   SET FOREIGN_KEY_CHECKS=0

2019-11-25T08:01:04.841032Z        67 Execute   DROP SCHEMA `mysqlslap`

2019-11-25T08:01:04.843783Z        67 Execute   DROP SCHEMA `hong`

2019-11-25T08:01:04.846438Z        67 Execute   DROP SCHEMA `ds0`

2019-11-25T08:01:04.849159Z        67 Execute   DROP SCHEMA `ds1`

2019-11-25T08:01:04.852039Z        67 Execute   SET SQL_LOG_BIN = OFF

2019-11-25T08:01:04.852159Z        67 Execute   SET FOREIGN_KEY_CHECKS=0

2019-11-25T08:01:04.852247Z        67 Execute   STOP SLAVE

2019-11-25T08:01:04.852329Z        67 Execute   RESET MASTER

2019-11-25T08:01:22.578730Z        67 Query     SELECT DATABASE()

Donor

2019-11-25T08:01:04.680779Z       941 Connect   clone_user@recipient.server.com on  using SSL/TLS

2019-11-25T08:01:04.690251Z       942 Connect   clone_user@recipient.server.com on  using SSL/TLS

2019-11-25T08:01:10.145412Z       944 Connect   clone_user@recipient.server.com on  using SSL/TLS

 

 

mysql> select STATE, CAST(BEGIN_TIME AS DATETIME) as "START TIME",

CASE WHEN END_TIME IS NULL THEN

LPAD(sys.format_time(POWER(10,12) * (UNIX_TIMESTAMP(now()) - UNIX_TIMESTAMP(BEGIN_TIME))), 10, ' ')

ELSE

LPAD(sys.format_time(POWER(10,12) * (UNIX_TIMESTAMP(END_TIME) - UNIX_TIMESTAMP(BEGIN_TIME))), 10, ' ')

END as DURATION

from performance_schema.clone_status;

 

 

+-----------+---------------------+------------+

| STATE     | START TIME          | DURATION   |

+-----------+---------------------+------------+

| Completed | 2019-11-25 07:08:23 |    32.45 s |

+-----------+---------------------+------------+

1 row in set (0.14 sec)

 

 

DURATION 컬럼 값으로 얼마나 소요 되었는지 확인할 수 있다. m 은 minute 이다.

 

select STAGE, STATE, CAST(BEGIN_TIME AS TIME) as "START TIME",

  CASE WHEN END_TIME IS NULL THEN

  LPAD(sys.format_time(POWER(10,12) * (UNIX_TIMESTAMP(now()) - UNIX_TIMESTAMP(BEGIN_TIME))), 10, ' ')

  ELSE

  LPAD(sys.format_time(POWER(10,12) * (UNIX_TIMESTAMP(END_TIME) - UNIX_TIMESTAMP(BEGIN_TIME))), 10, ' ')

  END as DURATION,

  LPAD(CONCAT(FORMAT(ROUND(ESTIMATE/1024/1024,0), 0), " MB"), 16, ' ') as "Estimate",

  CASE WHEN BEGIN_TIME IS NULL THEN LPAD('0%', 7, ' ')

  WHEN ESTIMATE > 0 THEN

  LPAD(CONCAT(CAST(ROUND(DATA*100/ESTIMATE, 0) AS BINARY), "%"), 7, ' ')

  WHEN END_TIME IS NULL THEN LPAD('0%', 7, ' ')

  ELSE LPAD('100%', 7, ' ') END as "Done(%)"

  from performance_schema.clone_progress;

 

+-----------+-----------+------------+------------+------------------+---------+

| STAGE     | STATE     | START TIME | DURATION   | Estimate         | Done(%) |

+-----------+-----------+------------+------------+------------------+---------+

| DROP DATA | Completed | 07:08:23   |     2.08 s |             0 MB |    100% |

| FILE COPY | Completed | 07:08:25   |     8.62 s |           184 MB |    100% |

| PAGE COPY | Completed | 07:08:33   |  304.76 ms |             0 MB |    100% |

| REDO COPY | Completed | 07:08:34   |  300.91 ms |             0 MB |    100% |

| FILE SYNC | Completed | 07:08:34   |    11.36 s |             0 MB |    100% |

| RESTART   | Completed | 07:08:45   |     4.86 s |             0 MB |    100% |

| RECOVERY  | Completed | 07:08:50   |     4.91 s |             0 MB |    100% |

+-----------+-----------+------------+------------+------------------+---------+

7 rows in set (0.00 sec)

 

 

Clone 은 FILE COPY 단계 안에 있다.

대부분의 Clone 단계가 완료되면 clone 은 FILE SYNC 단계가 된다. ( disk 로 data sync ) 

FILE SYNC 단계 이후에 clone 명령은 완료되고 server 로 부터 자동 재시작 될 것을 return 한다.

RESTART, RECOVERY 단계에서는 서버를 사용할 수 없다.

이는 clone 된 데이터로부터 전체 recovery 를 수행하기 때문이다.

 

redo logs 들이 적용되고 새로운 clone 이 snapshot GTID 로 sync 되면 

binlog 를 사용하여 upstream 서버를 따라잡을 수 있다.

이러한 과정이 종료되어야 상태를 확인할 수 있다.

 

 

Step-4. clone 이 성공적으로 완료되었는지 검증

 

CLONE SQL 은 완료 이후 서버 재시작이 필요하다.

CLONE SQL 이 성공적으로 return 되면 서버가 자동으로 shutdown 된다.

CLONE SQL 을 실행하는 client 는 connection 이 끊어진다.

: 만일 auto-reconnection 이 활성화 되어있다면 커넥션은 서버 재시작 이후에 재접속된다. 아니라면 수동으로 재접속 해야한다.

 

Recipient 는 서버 shutdown, restart 를 모니터링 과정에서 감지하는 환경에서 수행되어야 한다.

 

모니터링 과정이 없을 경우 다음과 같은 에러가 발생할 수 있다.

 

ERROR 3707 (HY000): Restart server failed (mysqld is not managed by supervisor process).

 

위 에러는 clone 실패를 의미하는 것이 아니라, 수동으로 restart 가 필요하고 client 가 server 로 재접속 해야 한다는 것을 의미한다. 

 

클라이언트가 재접속하면 clone 이 성공적으로 완료되었는지 확인한다.

select STATE, ERROR_NO, BINLOG_FILE, BINLOG_POSITION, GTID_EXECUTED,

CAST(BEGIN_TIME AS DATETIME) as "START TIME",

CAST(END_TIME AS DATETIME) as "FINISH TIME",

sys.format_time(POWER(10,12) * (UNIX_TIMESTAMP(END_TIME) - UNIX_TIMESTAMP(BEGIN_TIME)))

as DURATION

from performance_schema.clone_status \G

 

*************************** 1. row ***************************

          STATE: Completed

       ERROR_NO: 0

    BINLOG_FILE: mysql-bin.000006

BINLOG_POSITION: 1207

  GTID_EXECUTED: 245fe0b5-f088-11e9-a300-46de8e9f7ae5:1-288235

     START TIME: 2019-11-25 07:08:23

    FINISH TIME: 2019-11-25 07:08:55

       DURATION: 32.45 s    -- 소요시간

1 row in set (0.00 sec)

 

Clone 이 성공적으로 완료되되었음을 확인하였다. 다음 쿼리로 모든 단계가 성공적으로 완료되었음을 확인한다.

select STAGE, STATE, CAST(BEGIN_TIME AS DATETIME) as "START TIME",

CAST(END_TIME AS DATETIME) as "FINISH TIME",

LPAD(sys.format_time(POWER(10,12) * (UNIX_TIMESTAMP(END_TIME) - UNIX_TIMESTAMP(BEGIN_TIME))), 10, ' ')

as DURATION

from performance_schema.clone_progress;

select STAGE, STATE, CAST(BEGIN_TIME AS TIME) as "START TIME",

  CAST(END_TIME AS TIME) as "FINISH TIME",

  LPAD(sys.format_time(POWER(10,12) * (UNIX_TIMESTAMP(END_TIME) - UNIX_TIMESTAMP(BEGIN_TIME))), 10, ' ')

  as DURATION

  from performance_schema.clone_progress;

 

+-----------+-----------+------------+-------------+------------+

| STAGE     | STATE     | START TIME | FINISH TIME | DURATION   |

+-----------+-----------+------------+-------------+------------+

| DROP DATA | Completed | 07:08:23   | 07:08:25    |     2.08 s |

| FILE COPY | Completed | 07:08:25   | 07:08:33    |     8.62 s |

| PAGE COPY | Completed | 07:08:33   | 07:08:34    |  304.76 ms |

| REDO COPY | Completed | 07:08:34   | 07:08:34    |  300.91 ms |

| FILE SYNC | Completed | 07:08:34   | 07:08:45    |    11.36 s |

| RESTART   | Completed | 07:08:45   | 07:08:50    |     4.86 s |

| RECOVERY  | Completed | 07:08:50   | 07:08:55    |     4.91 s |

+-----------+-----------+------------+-------------+------------+

 

 

Recipient 는 정확한 GTID  값으로 Donor 의 clone 이 되었다.

이로써 GTID 또는 binary log position 을 기반으로  HA 클러스터에 조인할 준비가 되었다. 

MySQL HA 문서에서 slave 로 MySQL instance 설정 또는 group replication node 설정에 대한 더 많은 정보를 확인하기 바란다.