MySQL高可用实践
上QQ阅读APP看书,第一时间看更新

1.3 配置异步复制

在本实验中分别针对空库、脱机、联机三种场景,配置“一主两从”的MySQL标准异步复制。只进行实例级别的全复制,不考虑对个别库表或使用过滤复制的情况。

1.3.1 空库

初始安装后,MySQL中还没有任何应用数据。此时事先配置好复制再投入使用,这是最理想也是最简单的一种情况,具体配置步骤如下:

步骤01 修改server_id系统变量。

要求在复制中所有MySQL实例的server_id都不相同,这里将三个实例的server_id分别配置为1125、1126、1127。server_id系统变量可以动态修改,这样做的好处是不需要重启实例,配置即可在新连接中生效。但是为了避免MySQL重启后配置信息丢失,还需要同时在/etc/my.cnf配置文件中设置server_id参数。

步骤02 查看主库二进制日志信息。

     -- 主库
     show master status;

因为是一个静态的空库,二进制信息此时不会发生变化,可以作为复制的起始点。本例中重启过MySQL实例,输出的信息为:

步骤03 在主库上建立复制专属用户。

     -- 主库
     create user 'repl'@'%' identified with mysql_native_password by '123456';
     grant replication client,replication slave on *.* to 'repl'@'%';

前面介绍过MySQL 8的用户认证机制,这里仍然使用mysql_native_password方式。

步骤04 在从库创建主库信息。

连接主库时,需要使用change master to提供到主库的连接选项,包括主机地址、端口、用户名、密码、二进制文件名、复制起始事件位置等信息。执行change master to语句后,在mysql.slave_master_info表中就会生成一条记录,此行为由master_info_repository系统变量控制。MySQL 8中,该变量的默认值为TABLE,即把与复制相关的主库信息记录到mysql.slave_master_info表中。随着复制的进行,表中的数据会随之更新。change master to只是为I/O线程连接主库时提供连接参数,这条语句本身不会连接主库。以后启动I/O线程时,I/O线程都会自动读取这条记录连接主库,不需要再执行change master to语句。

类似地,MySQL 8默认会将中继日志的重放信息存到mysql.slave_relay_log_info表中。该行为由系统变量relay_log_info_repository控制。中继日志信息在首次启动复制时生成,并随着复制过程即时改变,这样SQL线程再次启动时就能从中获取到从中继日志的何处继续读取和执行。

步骤05 在从库启动复制并查看复制信息。

     start slave;
     show slave status\G
     select * from mysql.user where user='repl'\G

刚才我们并没有在从库上创建repl用户,由于create user语句是在起始位置后执行的,因此可以正常复制到从库,查询mysql.user表即可确认。

start slave语句会启动I/O线程和SQL线程,并创建一个到主库的普通客户端连接,此连接会伴随复制一直存在。该命令执行后,在主库的processlist中会看到类似如下的线程,它们是从库上的I/O线程所建立的,Binlog Dump表示由I/O线程在主库上启动了Binlog Dump线程,每个连接到主库的从库对应一个线程,如Id 32和56是两个从库的连接线程:

从库上的processlist中会看到类似如下的线程,Id 325和326分别对应I/O线程与SQL线程:

从show slave status输出中可以查看复制的状态信息:

在从库上执行show slave status可以查看从库的状态,输出的信息非常多,其中除了那些描述I/O线程、SQL线程状态的行,还有几个log_file和pos相关的行。理解这几行的意义至关重要,所以这里完整地描述它们:

  • Master_Log_File:I/O线程正在读取的master binlog。
  • Read_Master_Log_Pos:I/O线程已经读取到master binlog的哪个位置。
  • Relay_Log_File:SQL线程正在读取和执行的relay log。
  • Relay_Log_Pos:SQL线程已经读取和执行到relay log的哪个位置。
  • Relay_Master_Log_File:SQL线程最近执行的操作对应的是哪个master binlog。
  • Exec_Master_Log_Pos:SQL线程最近执行的操作对应的是master binlog的哪个位置。

(Relay_Master_Log_File, Exec_Master_log_Pos)构成一个坐标,这个坐标表示从库上已经将主库上的哪些数据重放到自己的实例中,它可以用于下一次执行change master to语句时指定的二进制日志坐标。与这个坐标相对应的是从库上SQL线程的中继日志坐标(Relay_Log_File,Relay_Log_Pos)。这两个坐标位置不同,但它们对应的数据是一致的。

还有一个延迟参数Seconds_Behind_Master需要说明一下,它的含义是SQL线程比I/O线程慢多少。如果主从之间的网络状况优良,那么从库的I/O线程读速度二进制日志和主库写二进制日志的速度基本一致,所以这个参数也用来描述“SQL线程比主库慢多少”,也就是说从库比主库少多少数据,只不过衡量的单位是秒。需要注意的是,该参数的描述并不标准,只是在网速很好的时候做个大概的估计,很多情况下它的值都是0,即使SQL线程比I/O线程慢了很多也是如此。

1.3.2 脱机

如果数据库已经存在应用数据,允许在一个可接受的脱机时间窗口进行复制,那么这种场景下常用的做法是先直接将主库的数据目录整体复制到从库,再启动从库复制操作,具体步骤如下:

步骤01 在主库上建立复制专属用户:

     -- 主库
     create user 'repl'@'%' identified with mysql_native_password by '123456';
     grant replication client,replication slave on *.* to 'repl'@'%';

步骤02 停掉复制涉及的实例(“一主两从”三个实例都停止):

     mysqladmin -uroot -p123456 shutdown

步骤03 将主库的数据目录整体复制到从库:

     scp -r /usr/local/mysql/data/ 172.16.1.126:/usr/local/mysql

步骤04 保证所有参与复制实例的server-uuid和server_id都不同。

这是非常重要的一步,相同的server-uuid或server_id会造成复制错误。从MySQL 5.6开始,用128位的server_uuid代替了原本的32位server_id的大部分功能。原因很简单,server_id依赖于my.cnf的手工配置,有可能发生冲突。而自动产生128位uuid的算法可以保证所有的MySQL uuid都不会发生冲突。首次启动时MySQL会调用generate_server_uuid()自动生成一个server_uuid,并且保存到数据目录下的auto.cnf文件中。这个文件目前存在的唯一目的就是保存server_uuid。在MySQL再次启动时会读取auto.cnf文件,继续使用上次生成的server_uuid。使用show global variables like 'server_uuid'命令可以查看MySQL实例当前使用的server_uuid,它是一个全局只读变量。全局唯一server_uuid的一个好处是,可以解决由server_id配置冲突导致的MySQL主从复制异常终止。从库向主库申请二进制日志时,会首先发送自己的server_uuid,主库用从库发送的server_uuid代替server_id作为kill_zombie_dump_threads的参数,以终止冲突或者僵死的BINLOG_DUMP线程。

删除data_dir/auto.cnf文件,实例启动时会自动生成server_uuid的值。本例中删除了从库的/usr/local/mysql/data/auto.cnf文件,并编辑/etc/my.cnf文件以修改server_id,保证三个实例的配置互不相同。

步骤01 重启实例(“一主两从”三个实例都启动):

     mysqld_safe --user=mysql &

步骤02 查看主库二进制日志信息:

     -- 主库
     show master status;

步骤03 使用上一步的输出在从库创建主库信息:

步骤04 在从库启动复制并查看复制信息:

     start slave;
     show slave status\G

此时在从库的err日志文件中可以看到复制正常启动的信息:

1.3.3 联机

脱机建立复制的需求太过理想化,大多数情况下,复制被要求在不影响线上业务的情况下联机创建,而且还要求对线上库的影响越小越好。例如,在复制过程中主库加锁会影响对主库的访问,因此通常不允许对主库加锁。这种场景下有两种备选的复制方案:使用mysqldump程序或使用如XtraBackup的第三方工具。这两种方案都有各自的适用场合。使用mysqldump联机建立复制的过程如下:

步骤01 在主库上建立复制专属用户:

     -- 主库
     create user 'repl'@'%' identified with mysql_native_password by '123456';
     grant replication client,replication slave on *.* to 'repl'@'%';

步骤02 在从库上创建主库信息:

注意在上面这条命令中并没有指定主库二进制日志的文件名和位置。

步骤03 在从库用mysqldump建立复制:

     mysqldump --single-transaction --all-databases --master-data=1 --host=
     172.16.1.125 --default-character-set=utf8mb4 --user=wxy --password=123456
     --apply-slave-statements | mysql -uroot -p123456 -h127.0.0.1

说明:

  • --single-transaction参数可以对InnoDB表执行非锁定导出。此选项将事务隔离模式设置为REPEATABLE READ,并在转储数据之前向服务器发送START TRANSACTION SQL语句。它仅适用于InnoDB等事务表,因为它会在发出START TRANSACTION时转储数据库的一致状态,而不会阻塞任何应用程序。因此这里假定:①所有的应用数据表都使用InnoDB引擎;②所有非InnoDB表数据在备份过程中不会发生变化。
  • --master-data参数会导致转储输出包含类似CHANGE MASTER TO MASTER_LOG_FILE='binlog.000004', MASTER_LOG_POS=1480;的SQL语句,该语句指示主库的二进制日志坐标(文件名和偏移量)。如果选项值为2,则CHANGE MASTER TO语句将写为SQL注释,因此仅提供信息,不会执行。如果参数值为1,则该语句不会写为注释,并在重新加载转储文件时执行。如果未指定选项值,则默认值为1。
  • --apply-slave-statements参数会在CHANGE MASTER TO语句之前添加STOP SLAVE语句,并在输出结尾处添加START SLAVE语句,用来自动开启复制。
  • --default-character-set参数指定默认字符集,MySQL 8默认的字符集为utf8mb4。
  • 通过管道操作符,导出和导入一步进行,不需要中间落盘生成文件。

步骤04 确认复制状态:

     -- 从库
     show slave status\G

mysqldump方式的优点是可以进行部分复制,如在配置文件中定义replicate-do-table=db1.*,则用这种方法可以只复制db1库而忽略其他复制事件。缺点是由于mysqldump会生成主库转储数据的SQL语句,实际是一种逻辑备份方式,所以速度较慢,不适用于大库。

联机建立复制的另一种可选方案是使用XtraBackup。XtraBackup是Percona公司的开源项目,用以实现InnoDB官方的热备份工具InnoDB Hot Backup类似的功能,它支持在线热备份,备份时不影响数据读写。到目前为止,最新的版本为Percona XtraBackup 8.0.6,可以从https://www.percona.com/downloads/下载安装包。XtraBackup有很多功能和优点,例如支持全备份、增量备份;支持备份压缩;备份不影响数据读写、事务等。但是它也存在不足之处,例如不支持部分备份;不支持直接备份到磁带设备;不支持Cloud Back;MyISAM的备份也会阻塞等。不过瑕不掩瑜,这些小缺陷不影响XtraBackup成为一款流行的MySQL备份工具。另外,XtraBackup只支持Linux平台。下面演示用XtraBackup联机搭建主从复制的过程,主库已经建立了用于执行复制的用户repl。具体步骤如下:

步骤01 在主库和从库安装XtraBackup:

步骤02 配置主库到从库的SSH免密连接:

     # 主库执行
     ssh-keygen
     ... 一路按回车键 ...
     ssh-copy-id 172.16.1.126

步骤03 停止从库,并清空从库的数据目录:

步骤04 备份并传输:

这条命令用于连接主库,并行压缩流式备份,同时将备份通过管道操作符传输到从库,并直接解压缩到从库的数据目录。所有操作由一条命令来完成,不需要中间落盘生成文件。具体步骤如下:

步骤01 在从库恢复备份:

     # 应用日志
     xtrabackup --prepare --target-dir=/usr/local/mysql/data/

步骤02 查看二进制日志坐标:

     cat /usr/local/mysql/data/xtrabackup_binlog_info

步骤03 启动从库:

     mysqld_safe --user=mysql &

步骤04 登录从库启动复制:

XtraBackup是物理备份,性能比mysqldump高得多,而且对主库的影响极小,非常适用于从头联机创建高负载、大数据量、全实例从库的场景。