暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL 8 新特性之Clone Plugin

vivo互联网技术 2020-10-15
1192

Clone Plugin是MySQL 8.0.17引入的一个重大特性,为什么要实现这个特性呢?个人感觉,主要还是为Group Replication服务。在Group Replication中,添加一个新的节点,差异数据的补齐是通过分布式恢复(Distributed Recovery)来实现的。


在MySQL 8.0.17之前,只支持一种恢复方式-Binlog。但如果新节点需要的Binlog已经被Purge了,这个时候,只能先借助于备份工具(XtraBackup,mydumper,mysqldump)做个全量数据的同步,然后再通过分布式恢复同步增量数据。


这种方式,虽然也能实现添加节点的目的,但总归还是要借助于外部工具,需要一定的工作量和使用门槛。要知道,其竞争对手,PXC,默认集成了XtraBackup进行State Snapshot Transfer(类似于全量同步),而MongoDB则更进一步,原生就实现了Initial Sync同步全量数据。从易用性来看,单就集群添加节点这一项而言,MySQL确实不如其竞争对手。客户体验上,还有很大的提升空间。


好在MySQL官方也正视到这个差距,终于在MySQL 8.0.17实现了Clone Plugin。当然,对于官方来说,实现这个特性并不算难,毕竟有现成的物理备份工具(MySQL Enterprise Backup)可供借鉴。


本文将从以下几个方面展开:

  1. Clone Plugin的安装

  2. Clone Plugin的使用

  3. 如何查看克隆操作的进度

  4. 如何基于克隆数据搭建从库

  5. Clone Plugin的实现细节

  6. Clone Plugin的限制

  7. Clone Plugin与XtraBackup的对比

  8. Clone Plugin的参数解析


一、Clone Plugin的安装


Clone Plugin支持以下两种安装方式:


(1)配置文件指定

    [mysqld]
    plugin-load-add=mysql_clone.so
    clone=FORCE_PLUS_PERMANENT
    复制

    这里的clone,严格来说,不是参数名,而是插件名,可加可不加,FORCE_PLUS_PERMANENT 控制插件的行为。


    有四个取值:

    • ON开启插件)

    • OFF(禁用插件),

    • FORCE(强制开启。如果插件初始化失败,MySQL将不会启动)

    • FORCE_PLUS_PERMANENT(在FORCE的基础上,不允许通过UNINSTALL PLUGIN命令卸载插件)。


    (2)动态加载

      [mysqld]
      plugin-load-add=mysql_clone.so
      clone=FORCE_PLUS_PERMANENT
      复制


      查看插件是否安装成功

        mysql> show plugins;
        ...
        | clone | ACTIVE | CLONE | mysql_clone.so | GPL |
        ...
        复制

        (滑动可查看)


        clone状态显示为”ACTIVE“代表插件加载成功。


        二、Clone Plugin的使用


        Clone Plugin支持两种克隆方式:本地克隆和远程克隆。


        1、 本地克隆




        本地克隆是在实例本地发起的,其语法如下:

          CLONE LOCAL DATA DIRECTORY [=] 'clone_dir';
          复制

          其中,clone_dir是克隆目录。


          下面看个具体的Demo。


          创建克隆用户

            mysql> create user 'clone_user'@'%' identified by 'clone_pass';
            mysql> grant backup_admin on *.* to 'clone_user'@'%';
            复制


            创建克隆目录

              # mkdir data/mysql
              # chown -R mysql.mysql data/mysql
              复制


              创建本地克隆

                # mysql -uclone_user -pclone_pass
                mysql> clone local data directory='/data/mysql/3307';
                复制

                其中,“/data/mysql/3307” 是克隆目录,其需满足以下几点要求:

                1. 克隆目录必须是绝对路径。

                2. “/data/mysql”必须存在,且MySQL对其有可写权限。

                3. 3307不能存在。


                查看克隆目录的内容

                  # ll data/mysql/3307
                  total 172996
                  drwxr-x--- 2 mysql mysql 89 May 24 22:37 #clone
                  -rw-r----- 1 mysql mysql 3646 May 24 22:37 ib_buffer_pool
                  -rw-r----- 1 mysql mysql 12582912 May 24 22:37 ibdata1
                  -rw-r----- 1 mysql mysql 50331648 May 24 22:37 ib_logfile0
                  -rw-r----- 1 mysql mysql 50331648 May 24 22:37 ib_logfile1
                  drwxr-x--- 2 mysql mysql 6 May 24 22:37 mysql
                  -rw-r----- 1 mysql mysql 25165824 May 24 22:37 mysql.ibd
                  drwxr-x--- 2 mysql mysql 20 May 24 22:37 slowtech
                  drwxr-x--- 2 mysql mysql 28 May 24 22:37 sys
                  -rw-r----- 1 mysql mysql 10485760 May 24 22:37 undo_001
                  -rw-r----- 1 mysql mysql 11534336 May 24 22:37 undo_002
                  复制

                  相对于Xtrabackup,无需Prepare,直接即可启动使用。

                    # usr/local/mysql/bin/mysqld --no-defaults --datadir=/data/mysql/3307 --user mysql --port 3307 &
                    复制


                    2、远程克隆



                    远程克隆涉及两个实例,其中,待克隆的实例是Donor,接受克隆数据的实例是Recipient。克隆命令需在Recipient上发起,语法如下:

                      CLONE INSTANCE FROM 'user'@'host':port
                      IDENTIFIED BY 'password'
                      [DATA DIRECTORY [=] 'clone_dir']
                      [REQUIRE [NO] SSL];
                      复制

                      其中,

                      host,port 是待克隆实例的(Donor)的IP和端口,user,password是Donor上的克隆用户和密码,需要backup_admin权限,如上面创建的clone_user。


                      DATA DIRECTORY指定备份目录,不指定的话,则默认克隆到Recipient的数据目录下。


                      REQUIRE [NO] SSL,是否开启SSL通信。


                      下面,看个具体Demo。


                      首先,在Donor实例上创建克隆用户,加载Clone Plugin。

                        mysql> create user 'donor_user'@'%' identified by 'donor_pass';
                        mysql> grant backup_admin on *.* to 'donor_user'@'%';
                        mysql> install plugin clone soname 'mysql_clone.so';
                        复制

                        backup_admin是克隆操作必需权限。


                        接着,在Recipient实例上创建克隆用户,加载Clone Plugin。

                          mysql> create user 'recipient_user'@'%' identified by 'recipient_pass';
                          mysql> grant clone_admin on *.* to 'recipient_user'@'%';
                          mysql> install plugin clone soname 'mysql_clone.so';
                          复制

                          这里的clone_admin,隐式含有backup_admin(阻塞DDL)和shutdown(重启实例)权限。


                          设置Donor白名单。Recipient只能克隆白名单中的实例。

                            mysql> set global clone_valid_donor_list = '192.168.244.10:3306';
                            复制


                            设置该参数需要SYSTEM_VARIABLES_ADMIN权限。


                            在Recipient上发起克隆命令

                              # mysql -urecipient_user -precipient_pass
                              mysql> clone instance from 'donor_user'@'192.168.244.10':3306 identified by 'donor_pass';
                              Query OK, 0 rows affected (36.97 sec)
                              复制


                              远程克隆会依次进行以下操作:


                              (1)获取备份锁。备份锁和DDL互斥。注意,不仅仅是Recipient,Donor上的备份锁同样会获取。


                              (2)DROP用户表空间。注意,DROP的只是用户数据,不是数据目录,也不包括mysql,ibdata等系统表空间。


                              (3)从Donor实例拷贝数据。对于用户表空间,会直接拷贝,如果是系统表空间 ,则会重命名为xxx.#clone,不会直接替代原文件。

                                # ll data/mysql/3306/data/
                                ...
                                -rw-r----- 1 mysql mysql 3646 May 25 07:20 ib_buffer_pool
                                -rw-r----- 1 mysql mysql 3646 May 27 07:31 ib_buffer_pool.#clone
                                -rw-r----- 1 mysql mysql 12582912 May 27 07:31 ibdata1
                                -rw-r----- 1 mysql mysql 12582912 May 27 07:31 ibdata1.#clone
                                -rw-r----- 1 mysql mysql 50331648 May 27 07:32 ib_logfile0
                                -rw-r----- 1 mysql mysql 50331648 May 27 07:31 ib_logfile0.#clone
                                ...
                                -rw-r----- 1 mysql mysql 25165824 May 27 07:31 mysql.ibd
                                -rw-r----- 1 mysql mysql 25165824 May 27 07:31 mysql.ibd.#clone
                                ...
                                复制


                                (4)重启实例。在启动的过程中,会用xxx.#clone替换掉原来的系统表空间文件。


                                三、如何查看克隆操作的进度


                                查看克隆操作的进度主要依托于performance_schema.clone_status和performance_schema.clone_progress这两张表。


                                首先看看performance_schema.clone_status表。

                                  mysql> select * from performance_schema.clone_status\G
                                  *************************** 1. row ***************************
                                  ID: 1
                                  PID: 0
                                  STATE: Completed
                                  BEGIN_TIME: 2020-05-27 07:31:24.220
                                  END_TIME: 2020-05-27 07:33:08.185
                                  SOURCE: 192.168.244.10:3306
                                  DESTINATION: LOCAL INSTANCE
                                  ERROR_NO: 0
                                  ERROR_MESSAGE:
                                  BINLOG_FILE: mysql-bin.000009
                                  BINLOG_POSITION: 665197555
                                  GTID_EXECUTED: 59cd4f8f-8fa1-11ea-a0fe-000c29f66609:1-560
                                  1 row in set (0.06 sec)
                                  复制

                                  顾名思义,该表记录了克隆操作的当前状态。


                                  其中,

                                  • PID:Processlist ID。对应show processlist中的Id,如果要终止当前的克隆操作,执行kill processlist_id命令即可。


                                  • STATE:克隆操作的状态,Not Started(克隆尚未开始),In Progress(克隆中),Completed(克隆成功),Failed(克隆失败)。如果是Failed状态,ERROR_NO,ERROR_MESSAGE会给出具体的错误编码和错误信息。


                                  • BEGIN_TIME,END_TIME:克隆操作开始,结束时间。


                                  • SOURCE:Donor实例的地址。


                                  • DESTINATION:克隆目录。“LOCAL INSTANCE”代表当前实例的数据目录。


                                  • GTID_EXECUTED,BINLOG_FILE(BINLOG_POSITION):克隆操作结束时,主库已经执行的GTID集合,及一致性位置点。可利用这些信息来搭建从库。


                                  接下来看看performance_schema.clone_progress表。

                                    mysql> select * from performance_schema.clone_progress;
                                    +------+-----------+-----------+----------------------------+----------------------------+---------+-----------+-----------+-----------+------------+---------------+
                                    | ID | STAGE | STATE | BEGIN_TIME | END_TIME | THREADS | ESTIMATE | DATA | NETWORK | DATA_SPEED | NETWORK_SPEED |
                                    +------+-----------+-----------+----------------------------+----------------------------+---------+-----------+-----------+-----------+------------+---------------+
                                    | 1 | DROP DATA | Completed | 2020-05-27 07:31:28.581661 | 2020-05-27 07:31:35.855706 | 1 | 0 | 0 | 0 | 0 | 0 |
                                    | 1 | FILE COPY | Completed | 2020-05-27 07:31:35.855952 | 2020-05-27 07:31:58.270881 | 2 | 482463294 | 482463294 | 482497011 | 0 | 0 |
                                    | 1 | PAGE COPY | Completed | 2020-05-27 07:31:58.271250 | 2020-05-27 07:31:58.719085 | 2 | 10977280 | 10977280 | 11014997 | 0 | 0 |
                                    | 1 | REDO COPY | Completed | 2020-05-27 07:31:58.720128 | 2020-05-27 07:31:58.930804 | 2 | 465408 | 465408 | 465903 | 0 | 0 |
                                    | 1 | FILE SYNC | Completed | 2020-05-27 07:31:58.931094 | 2020-05-27 07:32:01.063325 | 2 | 0 | 0 | 0 | 0 | 0 |
                                    | 1 | RESTART | Completed | 2020-05-27 07:32:01.063325 | 2020-05-27 07:32:59.844119 | 0 | 0 | 0 | 0 | 0 | 0 |
                                    | 1 | RECOVERY | Completed | 2020-05-27 07:32:59.844119 | 2020-05-27 07:33:08.185367 | 0 | 0 | 0 | 0 | 0 | 0 |
                                    +------+-----------+-----------+----------------------------+----------------------------+---------+-----------+-----------+-----------+------------+---------------+
                                    7 rows in set (0.00 sec)
                                    复制

                                    该表记录了克隆操作的进度信息。

                                    • STAGE:一个克隆操作可依次细分为DROP DATA,FILE COPY,PAGE COPY,REDO COPY,FILE SYNC,RESTART,RECOVERY等7个阶段。当前阶段结束了才会开始下一个阶段。


                                    • STATE:当前阶段的状态。有三种状态:Not Started,In Progress,Completed。


                                    • BEGIN_TIME,END_TIME:当前阶段的开始时间和结束时间。


                                    • THREADS:当前阶段使用的并发线程数。


                                    • ESTIMATE:预估的数据量。


                                    • DATA:已经拷贝的数据量。


                                    • NETWORK:通过网络传输的数据量。如果是本地克隆,该列的值为0。


                                    • DATA_SPEED,NETWORK_SPEED:当前数据拷贝的速率和网络传输的速率。

                                      注意,是当前值。


                                    四、如何基于克隆数据搭建从库


                                    在前面,我们介绍过

                                    performance_schema.clone_status表,该表会记录Donor实例的一致性位置点信息。我们可以利用这些信息来搭建从库。

                                      mysql> select * from performance_schema.clone_status\G
                                      *************************** 1. row ***************************
                                      ...
                                      BINLOG_FILE: mysql-bin.000009
                                      BINLOG_POSITION: 665197555
                                      GTID_EXECUTED: 59cd4f8f-8fa1-11ea-a0fe-000c29f66609:1-560
                                      1 row in set (0.06 sec)
                                      复制

                                      这里,区分两种场景,GTID复制和基于位置点的复制。


                                      1、GTID复制

                                        mysql> CHANGE MASTER TO MASTER_HOST = 'master_host_name', MASTER_PORT = master_port_num,
                                        ...
                                        MASTER_AUTO_POSITION = 1;
                                        mysql> START SLAVE;
                                        复制

                                        需要注意的是,无需额外执行set global gtid_purged操作。通过克隆数据启动的实例,gtid_purged已经初始化完毕。

                                          mysql> show global variables like 'gtid_purged';
                                          +---------------+--------------------------------------------+
                                          | Variable_name | Value |
                                          +---------------+--------------------------------------------+
                                          | gtid_purged | 59cd4f8f-8fa1-11ea-a0fe-000c29f66609:1-560 |
                                          +---------------+--------------------------------------------+
                                          1 row in set (0.00 sec)
                                          复制


                                          2、基于位置点的复制


                                          这里,同样要区分两种场景。


                                          场景1,Recipient要作为Donor的从库。

                                            mysql> SELECT BINLOG_FILE, BINLOG_POSITION FROM performance_schema.clone_status; 
                                            mysql> CHANGE MASTER TO MASTER_HOST = 'master_host_name', MASTER_PORT = master_port_num,
                                            ...
                                            MASTER_LOG_FILE = 'master_log_name',
                                            MASTER_LOG_POS = master_log_pos;
                                            mysql> START SLAVE;
                                            复制

                                            其中,

                                            master_host_name,master_port_num:

                                            Donor实例的IP和端口。


                                            master_log_name,master_log_pos:

                                            performance_schema.clone_status 中的

                                            BINLOG_FILE, BINLOG_POSITION。


                                            场景2,Donor本身就是一个从库,Recipient要作为Donor主库的从库。

                                              mysql> SELECT MASTER_LOG_NAME, MASTER_LOG_POS FROM mysql.slave_relay_log_info;
                                              mysql> CHANGE MASTER TO MASTER_HOST = 'master_host_name', MASTER_PORT = master_port_num,
                                              ...
                                              MASTER_LOG_FILE = 'master_log_name',
                                              MASTER_LOG_POS = master_log_pos;
                                              mysql> START SLAVE;
                                              复制

                                              其中,

                                              master_host_name,master_port_num:

                                              Donor主库的IP和端口。


                                              master_log_name,master_log_pos:

                                              mysql.slave_relay_log_info中的

                                              Master_log_name,Master_log_pos(分别对应 SHOW SLAVE STATUS 中的 

                                              Relay_Master_Log_File,

                                              Exec_Master_Log_Pos)。


                                              在搭建从库时,建议设置--skip-slave-start。该参数默认为OFF,实例启动后,会自动执行START SLAVE操作。


                                              如果Donor是个从库,Recipient会基于mysql.slave_master_info,

                                              mysql.slave_relay_log_info中的信息自动建立复制,很多时候,这未必是我们的预期行为。


                                              五、Clone Plugin的实现细节


                                              克隆操作可细分为以下5个阶段。

                                                [INIT] ---> [FILE COPY] ---> [PAGE COPY] ---> [REDO COPY] -> [Done]
                                                复制


                                                1、INIT:初始化一个克隆对象。


                                                2、FILE COPY

                                                拷贝所有数据文件。在拷贝之前,会记录一个LSN,作为“CLONE START LSN”,这个LSN其实是当前CHECKPOINT的LSN,同时启动“Page Tracking”特性。


                                                “Page Tracking”会跟踪“CLONE START LSN”之后被修改的页,具体来说,会记录该页的Tablespace ID和page ID。数据文件拷贝结束后,会将当前CHECKPOINT的LSN记为“CLONE FILE END LSN”。


                                                3、PAGE COPY

                                                拷贝“CLONE START LSN”和“CLONE FILE END LSN”之间的页,在拷贝之前,会对这些页进行排序-基于Tablespace ID和page ID,尽量避免拷贝过程中出现随机读写。同时,开启“Redo Archiving”特性。


                                                “Redo Archiving”会在后台开启一个归档线程将Redo文件中的内容按Chunk拷贝到归档文件中。通常来说,归档线程的拷贝速度会快于Redo日志的生成速度。即使慢于,在写入新的Redo日志时,也会等待归档线程完成拷贝,不会出现还未拷贝的Redo日志被覆盖的情况。当所有修改的页拷贝完毕后,会获取实例的一致性位置点信息,此时的LSN记为“CLONE LSN”。


                                                4、REDO COPY

                                                拷贝归档文件中“CLONE FILE END LSN”与“CLONE LSN”之间的Redo日志。


                                                5、Done

                                                调用snapshot_end()销毁克隆对象。


                                                六、Clone Plugin的限制


                                                1、克隆期间,不允许执行DDL命令。同样,DDL会阻塞克隆命令的执行


                                                2、Clone Plugin不会拷贝Donor的配置参数。


                                                3、Clone Plugin不会拷贝Donor的二进制日志文件。


                                                4、Clone Plugin只会拷贝InnoDB表的数据,对于其它存储引擎的表,只会拷贝表结构。


                                                5、Donor实例中如果有表通过DATA DIRECTORY指定了绝对路径,在进行本地克隆时,会提示文件已存在。在进行远程克隆时,绝对路径必须存在且有可写权限。


                                                6、不允许通过MySQL Router连接Donor实例。


                                                7、执行CLONE INSTANCE操作时,指定的Donor端口不能为X Protocol端口。


                                                 除此之外,在进行远程克隆时,还会进行如下检查:


                                                • MySQL版本(包括小版本)必须一致,且支持Clone Plugin。

                                                  ERROR 3864 (HY000): Clone Donor MySQL version: 8.0.20 is different from Recipient MySQL version 8.0.19.
                                                  复制


                                                  • 主机的操作系统和位数(32位,64位)必须一致。两者可根据version_compile_os,version_compile_machine参数获取。


                                                  • Recipient必须有足够的磁盘空间存储克隆数据。


                                                  • 字符集(character_set_server),校验集(collation_server),character_set_filesystem必须一致。


                                                  • innodb_page_size必须一致。会检查innodb_data_file_path中ibdata的数量和大小。


                                                  • 目前Clone Plugin(8.0.20)的实现,无论是Donor,还是Recipient,同一时间,只能执行一个克隆操作。后续会支持多个克隆操作并发执行。

                                                    ERROR 3634 (HY000): Too many concurrent clone operations. Maximum allowed - 1.
                                                    复制


                                                    • Recipient需要重启,所以其必须通过mysqld_safe或systemd等进行管理。如果是通过mysqld进行启动,实例关闭后,需要手动启动。

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


                                                      • ACTIVE状态的Plugin必须一致。


                                                      七、Clone Plugin与XtraBackup的对比


                                                      1、在实现上,两者都有FILE COPY和REDO COPY阶段,但Clone Plugin比XtraBackup多了一个PAGE COPY,由此带来的好处是,Clone Plugin的恢复速度比XtraBackup更快。


                                                      2、XtraBackup没有Redo Archiving特性,有可能出现未拷贝的Redo日志被覆盖的情况。


                                                      3、GTID下建立复制,无需额外执行set global gtid_purged操作。


                                                      八、Clone Plugin的参数解析


                                                      clone_autotune_concurrency

                                                      是否自动调节克隆过程中并发线程数的数量,默认为ON,此时,最大线程数受clone_max_concurrency参数控制。若设置为OFF,则并发线程数的数量将是固定的,同clone_max_concurrency参数一致。该参数的默认值为16。


                                                      clone_buffer_size

                                                      本地克隆时,中转缓冲区的大小,默认4M。缓冲区越大,备份速度越快,相应的,对磁盘IO的压力越大。


                                                      clone_ddl_timeout

                                                      克隆操作需要获取备份锁(Backup Lock)。如果在执行CLONE命令时,有DDL在执行,则CLONE命令会被阻塞,等待获取备份锁(Waiting for backup lock)。等待的最大时长由clone_ddl_timeout参数决定,默认300(单位秒)。如果在这个时间内还没获取到锁,CLONE命令会失败,且提示“ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction”。


                                                      需要注意的是,如果在执行DDL时,有CLONE命令在执行,DDL同样会因获取不到备份锁被阻塞,只不过,DDL操作的等待时长由lock_wait_timeout参数决定,该参数的默认值为31536000s,即365天。


                                                      clone_enable_compression


                                                      远程克隆,在传输数据时,是否开启压缩。开启压缩能节省网络带宽,但相应的,会增加CPU消耗。


                                                      clone_max_data_bandwidth


                                                      远程克隆时,可允许的最大数据拷贝速率(单位MiB/s)。默认为0,不限制。注意,这里限制的只是单个线程的拷贝速率,如果存在多个线程并行拷贝,实际最大拷贝速率=clone_max_data_bandwidth*线程数。


                                                      clone_max_network_bandwidth


                                                      远程克隆时,可允许的最大网络传输速率(单位MiB/s)。默认为0,不限制。如果网络带宽存在瓶颈,可通过该参数进行限速。


                                                      clone_valid_donor_list

                                                      设置Donor白名单,只能克隆白名单中指定的实例。


                                                      clone_ssl_ca,clone_ssl_cert,clone_ssl_key

                                                      SSL相关。


                                                      九、参考资料


                                                      1. InnoDB: Clone local replica:

                                                        https://dev.mysql.com/worklog/task/?id=9209

                                                      2. InnoDB: Clone remote replica:

                                                        https://dev.mysql.com/worklog/task/?id=9210

                                                      3. InnoDB: Clone Replication Coordinates

                                                        https://dev.mysql.com/worklog/task/?id=9211

                                                      4. InnoDB: Clone Remote provisioning:

                                                        https://dev.mysql.com/worklog/task/?id=11636

                                                      5. MySQL/InnoDB数据克隆插件(clone plugin)实现剖析

                                                        https://zhuanlan.zhihu.com/p/79328512


                                                      END

                                                      猜你喜欢


                                                      vivo互联网技术


                                                      vivo移动互联网是基于vivo 智能手机所建立的完整移动互联网生态圈,围绕vivo大数据运营,打造包括应用、游戏、资讯、品牌、电商、内容、金融、搜索的全方位服务生态,满足海量用户的多样化需求。

                                                      点一下,代码无 Bug

                                                      文章转载自vivo互联网技术,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                                                      评论