数据库备份恢复的原理实践

目前在互联网的实际应用中,各个企业都会比较关注自身网站的数据信息,既要保证数据信息的安全性,同时也要保证数据存储读取效率

并且在特殊的场景下,还要对存储的数据信息进行检索和分析;因此数据库服务业务已经在各行各业应用非常的广泛

对于互联网领域的技术人员,对于数据库服务知识的掌握,也将是在求职时必备的技能,有些时候还会绝对入职的定级和薪资水平。

数据库服务克隆应用

数据库克隆概念介绍

在数据库MySQL 8.0(8.0.17+)版本中,引入了数据库的克隆功能,主要是借助clone-plugin实现的,是对数据页底层克隆;

克隆的数据是InnoDB存储引擎中的物理快照信息,包括schemas, tables, tablespaces, and data dictionary metadata;

在数据库中出现克隆功能,主要是为了满足目前云原生的技术应用场景,同时也是为了海量数据备份而诞生的;

在数据库中实现克隆功能应用有两种方式:

本地克隆(Local Cloning):

启动克隆操作的MySQL数据库服务器实例中的数据,将会克隆到同服务器或同节点上的一个目录里;

远程克隆(Remote Cloning)

默认情况下,远程克隆操作会删除接受者(recipient)数据目录中的数据,并将其替换为捐赠者(donor)的克隆数据;

也可以将数据克隆到接受者的其他目录中,以避免删除现有数据;(属于可选操作);

主要用于实现数据远程的快速热迁移操作,在迁移过程中,除了DDL操作情况,其他操作都不会出现阻塞情况;

还可以利用远程克隆技术,实现快速构建数据库的主从架构环境,实现主从数据信息快速复制同步;

数据库克隆原理说明

在进行数据库克隆操作时,会经历几个重要的过程或步骤:

01 Page copy:

在进行数据页复制操作时,会涉及到两个操作动作:

++开启redo archiving功能,从当前点开始存储新增的redo_log,这样从当前位置点开始所有的增量修改都不会丢失;++

同时上一步在page track的page被发送到目标端,确保当前位置点之前所有做的变更一定发送到目标端;

关于redo archiving实际上这是官方早就存在的功能,主要用于官方的企业级备份工具,clone利用了该特性来维持记录增量产生的redo

在开始克隆前会做一次checkpoint;

对于redo archiving功能应用,会开启一个后台线程log_archiver_thread()来做日志归档;

当有新的写入时(notify_about_advanced_write_lsn),也会通知线程去进行归档,当arch_log_sys处于活跃状态时,

线程会控制日志写入以避免未归档的日志被覆盖(log_write_wait_on_archiver),注意如果log_write等待时间过长的话,

archive任务会被中断掉;

02 Redo copy:

停止redo archiving功能,所有归档的日志被发送到目标端,这些日志包含了从page copy阶段开始到现在的所有日志;

++另外可能还需要记下当前的复制点,例如:最后一个事务提交时的binlog位置点或者gtid信息,在系统页中可以找到;++

03 Done:

目标端重启实例,通过crash recovery将redo log应用上去;

克隆原理过程分析参考链接:https://zhuanlan.zhihu.com/p/437760913

说明:整个克隆过程都会以事件信息记录,可以很清晰的看到克隆的流程,如果克隆过程中断,也会以追加方式进行继续克隆;

在进行克隆功能应用时,也是存在一些限制性操作的:(结合官方列出的限制)

  • 对于MySQL 8.0.27之前版本,在进行克隆操作期间,是不允许在捐赠者和接受者上进行DDL操作,包括:truncate table操作;

    对于MySQL 8.0.27之后版本,在捐赠者上默认允许并发DDL操作,对于捐赠者上并发DDL的支持由clone_block_DDL变量控制;

  • 对于不同版本的MySQL数据库实例之间,是不能进行克隆操作的。对于捐赠者和接受者必须是确切相同数据库服务版本;

    例如:你不能克隆数据在between MySQL 5.7 and MySQL 8.0, or between MySQL 8.0.19 and MySQL 8.0.20;

    这个克隆功能只支持在数据库8.0.17版本或之后的版本

参考官方链接说明:https://dev.mysql.com/doc/refman/8.0/en/clone-plugin-limitations.html

数据库克隆功能实践

实现本地克隆操作过程:

克隆需求:实现快速创建和源数据库服务一模一样的多实例服务程序;

克隆操作步骤01:加载克隆插件信息

sql 复制代码
# 进行克隆插件加载配置
mysql> INSTALL PLUGIN clone SONAME 'mysql_clone.so';
或者
[mysqld]
plugin-load-add=mysql_clone.so
clone=FORCE_PLUS_PERMANENT

# 查看克隆插件加载情况
mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = 'clone';
+------------------+----------------------+
| PLUGIN_NAME | PLUGIN_STATUS |
+------------------+----------------------+
| clone                | ACTIVE                 |
+------------------+----------------------+
1 row in set (0.00 sec)

克隆操作步骤02:创建克隆专用用户

sql 复制代码
mysql> create user clone_user@'%' identified by 'password';
mysql> grant backup_admin on *.* to 'clone_user';
-- backup_admin权限是mysql 8.0才有的备份导出的权限;

克隆操作步骤03:进行本地克隆操作

bash 复制代码
[root@cheng-01 ~]# mkdir -p /data/test
[root@cheng-01 ~]# chown -R mysql.mysql /data/
[root@cheng-01 ~]# mysql -uclone_user -ppassword
mysql> clone local data directory = '/data/test/clonedir';
-- 完成本地数据库目录的克隆操作,如果出现异常需要删除克隆目录,在进行重新克隆操作

克隆操作步骤04:观测本地克隆状态(另开窗口使用管理员用户查看)

sql 复制代码
mysql>  select stage,state,end_time from performance_schema.clone_progress;
+---------------+----------------+-----------------------------------+
| stage            | state             | end_time                                |
+---------------+----------------+-----------------------------------+
| DROP DATA  | Completed   | 2022-11-28 01:11:17.715901 |
| FILE COPY    | Completed   | 2022-11-28 01:11:17.752819 |
| PAGE COPY  | Completed   | 2022-11-28 01:11:17.756830 |
| REDO COPY | Completed   | 2022-11-28 01:11:17.757802 |
| FILE SYNC   | Completed   | 2022-11-28 01:11:17.912679 |
| RESTART     | Not Started  | NULL                                        |
| RECOVERY   | Not Started  | NULL                                        |
+---------------+----------------+-----------------------------------+
7 rows in set (0.00 sec)
-- 当克隆数据量比较大的时候,可以使用此SQL语句进行克隆状态查看

克隆操作步骤05:实现克隆日志观测

sql 复制代码
mysql>  set global log_error_verbosity=3;
[root@cheng-01 ~]# tail -f db01.err
clone local data directory = '/data/test/clonedir'

克隆操作步骤06:启动运行克隆实例

bash 复制代码
[root@cheng-01 ~]# mysqld_safe --datadir=/data/test/clonedir --port=3333 --socket=/tmp/mysql3333.sock --user=mysql --mysqlx=off &
[root@cheng-01 ~]# netstat -lntup|grep 3333
tcp6       0      0 :::3333                 :::*                    LISTEN      52674/mysqld 

# 核实查看克隆后数据库信息
[root@cheng-01 ~]# mysql -uroot -p123456 -S /tmp/mysql3333.sock
mysql>  show databases;

实现远程克隆操作过程:

在进行实现远程克隆操作步骤之前,可以利用虚拟软件再次克隆出一台新的数据库8.0版本的服务器主机;

克隆操作步骤01:克隆操作环境准备

bash 复制代码
# 在克隆接收者主机上清理数据库服务环境:
[root@cheng-02 ~]# pkill mysqld
[root@cheng-02 ~]# rm -rf /data/3306/data/*
[root@cheng-02 ~]# rm -rf /data/3306/binlog/*
[root@cheng-02 ~]# rm -rf /data/3306/logs/*

# 在克隆接收者主机上进行实例初始化操作:
[root@cheng-02 ~]# mysqld --initialize-insecure --user=mysql --basedir=/usr/local/mysql --datadir=/data/3306/data
[root@cheng-02 ~]# vim /etc/my.cnf
[mysqld]
server_id=16
-- 修改克隆接收者主机上的server_id的配置信息

# 在克隆接收者主机上进行实例的运行操作:
[root@cheng-02 ~]# /etc/init.d/mysqld start

克隆操作步骤02:加载克隆插件信息

sql 复制代码
# 进行克隆插件加载配置
mysql> INSTALL PLUGIN clone SONAME 'mysql_clone.so';
或者
[mysqld]
plugin-load-add=mysql_clone.so
clone=FORCE_PLUS_PERMANENT
-- 克隆插件信息需要在克隆主机的捐赠者和接受者上都进行安装

# 查看克隆插件加载情况
mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = 'clone';
+------------------+----------------------+
| PLUGIN_NAME | PLUGIN_STATUS |
+------------------+----------------------+
| clone                | ACTIVE                 |
+------------------+----------------------+
1 row in set (0.00 sec)
-- 克隆插件信息需要在克隆主机的捐赠者和接受者上都进行安装后确认

克隆操作步骤03:创建克隆专用用户

sql 复制代码
# 在克隆捐赠者主机上进行授权(数据库01主机上设置)
mysql> create user test_jz@'%' identified by 'password';
mysql> grant backup_admin on *.* to test_jz@'%' ;
-- backup_admin权限是mysql 8.0才有的备份导出的权限;

# 在克隆接收者主机上进行授权(数据库02主机上设置)
mysql> create user test_js@'%' identified by 'password';
mysql> grant clone_admin on *.* to test_js@'%' ;
-- clone_admin权限是mysql 8.0才有的克隆同步数据的权限;

说明:可以在克隆捐赠者主机上和接收者主机上均创建两个用户信息,防止克隆同步数据后,接收者主机上不再含有接收用户信息;

克隆操作步骤04:进行远程克隆操作

sql 复制代码
# 在克隆接收者主机上进行设置
mysql> set global clone_valid_donor_list='192.168.30.101:3306';
-- 设置克隆同步数据的信任列表

# 在克隆接收者主机上进行克隆
[root@cheng-02 ~]# mysql -utest_js -ppassword -h192.168.30.102 -P3306
mysql> clone instance from test_jz@'192.168.30.101':3306 identified by 'password';
-- 在接收者主机上实现远程克隆操作

克隆操作步骤05:观测本地克隆状态

sql 复制代码
mysql>  select stage,state,end_time from performance_schema.clone_progress;
+---------------+----------------+-----------------------------------+
| stage            | state             | end_time                                |
+---------------+----------------+-----------------------------------+
| DROP DATA | Completed | 2022-11-29 00:15:34.002378 |
| FILE COPY   | Completed | 2022-11-29 00:15:35.218397 |
| PAGE COPY  | Completed | 2022-11-29 00:15:35.225659 |
| REDO COPY | Completed | 2022-11-29 00:15:35.229777 |
| FILE SYNC   | Completed | 2022-11-29 00:15:35.773431 |
| RESTART     | Completed | 2022-11-29 00:15:39.189607 |
| RECOVERY   | Completed | 2022-11-29 00:15:39.978301 |
+---------------+----------------+-----------------------------------+
7 rows in set (0.00 sec)
-- 当克隆数据量比较大的时候,可以使用此SQL语句进行克隆状态查看,在克隆接收者主机上进行查看
mysql> show databases;
-- 此时克隆接收者主机上查看到的数据信息,与克隆捐赠者主机上查看到的数据信息一致,即远程克隆操作完成

数据库服务主从架构

数据库服务主从复制概述

MySQL数据库服务从3.23版本就开始提供复制的功能,复制是指将主数据库的DDL和DML操作语句通过二进制日志传到复制服务器上;

然后在从库上(复制服务器)对这些日志重新执行(也叫重做),从而使得从库和主库的数据保持同步;

MySQL支持一台主库同时向多台从库进行复制,从库同时也可以作为其他服务器的主库,实现链状的复制;

MySQL复制的优点主要包含以下3个方面:

  • 如果主库出现问题,可以快速切换到从库提供服务;
  • 可以在从库上执行查询操作,降低主库的访问压力;
  • 可以在从库上执行备份操作,以避免备份期间影响主库的服务;

由于MySQL实现的是异步的复制,所以主从库之间存在一定的差距,在从库上进行的查询操作需要考虑到这些数据的差异,

一般只有更新不频繁的数据或者对实时性要求不高的数据可以通过从库查询,实时性要求高的数据仍然需要从主数据库获得;

数据库服务主从复制原理

  • 复制原理涉及线程

在进行主从数据复制时,是依靠相应线程信息来完成数据复制同步操作的,具体涉及到的线程信息如下:

所在位置 线程名称 作用说明
主库涉及线程 binlog dump thread 用于将主库binlog日志信息进行传输投递的线程 · 可以实现与从库的信息交互 · 可以监控二进制日志的变化 · 可以进行二进制日志的投递
从库涉及线程 slave IO thread · 可以用于连接主数据库服务 · 可以实现与主库线程的交互 · 可以接收和存储二进制日志(接收的二进制日志会存储在中继日志中)
slave SQL thread · 可以解析执行中继日志信息

主库线程信息查看:binlog dump

可以通过show processlist命令在主库上查看binlog dump线程,从binlog dump线程的状态可以看到,mysql的复制是主库主动推送

日志到从库去的,是属于推日志的方式来做同步;

说明:如果是一主多从的架构,将会看见多个binlog dump线程信息,实现对多个从库的日志信息投递;

从库线程信息查看:slave io/slave sql

在从库上通过show processlist可以看到I/O线程和SQL线程;

  • I/O线程等待主库上的binlog dump线程发送事件并更新到中继日志relay log;

    用此线程和主库建立连接,并与主库的dump thread线程进行交互,以及接收和存储主库推送过来的binlog日志信息到relay log;

  • SQL线程读取中继日志relay log并应用变更到数据库;

    用此线程实现回放relay log中的日志信息,实现对从库的SQL语句操作;

从MySQL的复制流程可以得知MySQL的复制是异步的,从库上的数据和主库存在一定的延时;

  • 复制原理涉及文件

在进行主从数据复制时,是依靠相应文件信息来完成数据复制过程中的数据保存的,具体涉及到的文件信息如下:

所在位置 文件信息 解释说明
主库涉及文件 binlog 可以利用二进制日志信息变化,实现主从数据库的异步方式同步
从库涉及文件 relaylog 可以利用中继日志进行临时存储或接收主库投递的二进制日志信息,日志信息会定期自动清理
master.info 可以存储主库相关信息(主库地址 端口 用户 密码 二进制位置点-已经获取的 )(和IO线程相关)
relay-log.info 可以存储SQL线程回放过的日志信息(与SQL线程相关)

从库上的后两个文件(matser/relay-log)已经不以文件方式保存在数据库服务的数据目录中,而是以表格形式直接存储在数据库内部:

sql 复制代码
mysql> show variables like '%info%';
+---------------------------------+----------------+
| Variable_name                    | Value             |
+---------------------------------+----------------+
| master_info_repository     | TABLE            |
| relay_log_info_repository | TABLE            |
+---------------------------------+----------------+
8 rows in set (0.00 sec)

mysql> use mysql;
mysql> show tables;
+----------------------------------+
| Tables_in_mysql                  |
+----------------------------------+
| slave_master_info               |
| slave_relay_log_info           |
+----------------------------------+
37 rows in set (0.01 sec)
-- 可以获取slave_master_info表中的信息,就是change master to配置指定的相关信息;
-- 可以获取 slave_relay_log_info表中的信息,就是SQL线程已经回放过的日志信息
  • 复制原理过程详述(Classic Replication)

MySQL的复制原理大致如下:

  1. 在从库上执行change master to命令,将主库连接信息和binlog位置信息写入master.info文件或 slave_master_info表中;

  2. 在从库上执行start slave命令,用于启动从库的IO和SQL线程功能;

  3. 从库IO线程主要用于读取主库连接信息,实现和主库建立连接,从而使主库派生出binlog dump线程(自动监控binlog);

  4. 从库IO线程根据change master to命令所定义的数据位置点,获取最新的binlog日志信息

  5. mysql主库在事务提交时会把数据变更为事件Events记录在二进制日志文件binlog中;

    mysql主库上的sync_binlog参数控制binlog日志刷新到磁盘;

  6. binlog dump线程会截取binlog日志并投递其日志给从库IO线程,此时主库并不关心投递日志信息的结果;

  7. 此时从库IO线程接收binlog投递信息(缓存),随之会立即更新master.info文件 或 slave_master_info数据表信息;

  8. 从库缓存的binlog日志数据信息会被写入到relaylog中继日志中;

    主库推送二进制日志文件binlog中的事件到从库的中继日志relay log,之后从库根据中继日志relay log重做数据变更操作,

  9. 从库SQL线程将会读取relaylog.info文件或者slave_relay_log_info数据表中信息,获取上次数据回放同步位置点;

    随之继续向后回放同步数据,一旦回放同步数据完成后,再次更新relay.info或slave_relay_log_info数据表信息;

  10. 在从库中回放过的relaylog日志信息,会被relay_log_purge线程定期删除处理这些日志;

  11. 通过逻辑复制以此来达到主库和从库的数据一致;

MySQL通过3个线程来完成主从库间的数据复制:其中binlog dump线程跑在主库上,I/O线程和SQL线程跑在从库上;

当在从库上启动复制(START SLAVE)时,首先创建I/O线程连接主库,主库随后创建binlog dump线程读取数据库事件;

并发送给I/O线程,I/O线程获取到事件数据后更新到从库的中继日志relay log中去,之后从库上的SQL线程读取中继日志relay log,

根据中继日志中的更新的数据库事件并应用;

简述:在两台以上节点进行复制,通过binlog日志实现同步关系,并且采用异步方式进行数据同步;

数据库服务主从复制实践

01 复制环境搭建过程:

操作步骤01:需要准备两台以上数据库实例

bash 复制代码
# 数据库节点01服务已经构建完毕
[root@cheng-01 ~]# mysqld_safe --defaults-file=/data/3307/data/my.cnf &      
[root@cheng-01 ~]# netstat -lntp|grep 3307
tcp6       0      0 :::3307                 :::*                    LISTEN      114722/mysqld  
[root@cheng-01 ~]# mysql -S /tmp/mysql3307.sock
    
# 数据库节点02服务已经构建完毕
[root@cheng-01 ~]# mysqld_safe --defaults-file=/data/3308/data/my.cnf &
[root@cheng-01 ~]# netstat -lntp|grep 3308
tcp6       0      0 :::3308                 :::*                    LISTEN      122865/mysqld   
[root@cheng-01 ~]# mysql -S /tmp/mysql3308.sock

操作步骤02:主数据库二进制日志功能开启

sql 复制代码
# 主数据库需要开启binlog日志功能
mysql> show variables like '%log_bin%';
+---------------------------------+--------------------------------------+
| Variable_name                   | Value                                           |
+---------------------------------+--------------------------------------+
| log_bin                                | ON                                               |
| log_bin_basename             | /data/3307/data/binlog            |
| log_bin_index                     | /data/3307/data/binlog.index |
| sql_log_bin                         | ON                                               |
+---------------------------------+--------------------------------------+
6 rows in set (0.01 sec)
-- 核实确认binlog日志功能在主库上已经开启

操作步骤03:核实主从复制主机的信息情况

sql 复制代码
# 确认多个复制节点的服务标识不同(server id/server_uuid)
mysql> set global server_id=7;
Query OK, 0 rows affected (0.00 sec)

mysql> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|           7 |
+-------------+
1 row in set (0.00 sec)

mysql> select @@server_uuid;
+--------------------------------------+
| @@server_uuid                        |
+--------------------------------------+
| 949efd68-6420-11ed-b1ad-000c2996c4f5 |
+--------------------------------------+
1 row in set (0.00 sec)
-- 主库上server_id server_uuid信息(3307节点做检查)
mysql> set global server_id=8;
Query OK, 0 rows affected (0.00 sec)

mysql> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|           8 |
+-------------+
1 row in set (0.00 sec)

mysql> select @@server_uuid;
+--------------------------------------+
| @@server_uuid                        |
+--------------------------------------+
| ed6c1c6f-6f33-11ed-b630-000c2961cd06 |
+--------------------------------------+
1 row in set (0.00 sec)
-- 从库上server_id server_uuid信息(3308节点做检查)
-- 根据服务标识信息的不同,可以用于在进行主从复制时,辨别节点之间的关系

# 确认多个复制节点的时间信息同步
[root@cheng-01 ~]# date
2025年 11月 30日 星期三 23:44:37 CST
[root@cheng-02 ~]# date
2025年 11月 30日 星期三 23:44:52 CST
-- 核心确认主从节点时间信息同步

# 确认多个复制节点的版本信息一致
[root@cheng-01 ~]# mysql -V
mysql  Ver 8.0.26 for Linux on x86_64 (MySQL Community Server - GPL)
[root@cheng-02 ~]# mysql -V
mysql  Ver 8.0.26 for Linux on x86_64 (MySQL Community Server - GPL)
-- 部分实际应用场景中可以支持不一致,但是复制源端可以是低版本,复制目标端可以是高版本,反之不行;

操作步骤05:创建主从数据同步的用户信息

sql 复制代码
# 在主库上创建复制同步数据用户
mysql> create user repl@'192.168.30.%' identified with mysql_native_password by '123456';
Query OK, 0 rows affected (0.01 sec)
mysql> grant replication slave on *.* to repl@'192.168.30.%';
Query OK, 0 rows affected (0.00 sec)
-- 从库会利用主库上的同步数据用户,进行数据同步传输操作

操作步骤06:进行从库部分数据信息的同步

bash 复制代码
# 可以将主库上的部分数据在从库上先进行同步
[root@cheng-01 ~]# mysqldump -uroot -A -S /tmp/mysql3307.sock --master-data=2 --single-transaction >/tmp/full.sql
-- 在3307主库上进行数据的全备(模拟企业环境的历史数据全备)
[root@cheng-01 ~]# mysql -S /tmp/mysql3308.sock
mysql> source /tmp/full.sql;
-- 在3308从库上进行数据的恢复(模拟企业环境的历史数据恢复)
-- 将原有主机的数据先备份,然后从库中进行恢复一部分数据,随后再进行数据信息同步追加
-- 可以利用同步方式有很多:mysqldump xtrabackup clone_plugin

操作步骤07:配置主从节点数据复制的信息

sql 复制代码
# 设置从库连接主库信息,定义从库连接主库同步位置点自动复制
mysql> help change master to
-- 获取连接主库,以及定义同步位置点的数据库配置模板信息
[root@cheng-01 ~]# vim /tmp/full.sql
-- CHANGE MASTER TO MASTER_LOG_FILE='binlog.000003', MASTER_LOG_POS=681;
-- 通过备份文件获取同步位置点信息
mysql> CHANGE MASTER TO
  MASTER_HOST='192.168.30.101',
  MASTER_USER='repl',
  MASTER_PASSWORD='123456',
  MASTER_PORT=3307,
  MASTER_LOG_FILE='binlog.000003',
  MASTER_LOG_POS=681,
  MASTER_CONNECT_RETRY=10;
-- 以上配置主从同步信息在从库进行执行;

操作步骤08:激活主从节点数据复制的线程

sql 复制代码
# 利用相应线程实现主从数据库的数据同步复制
mysql> start slave;
-- 在从库上激活数据复制同步功能

# 若此时数据同步失败可以重新开启同步功能
mysql> stop slave;
mysql> reset slave all;
-- 在从库上重置数据复制同步功能,重新配置change master to信息,然后重新激活同步复制功能;

# 进行核实主从同步功能是否实现
[root@cheng-01 ~]# mysql -S /tmp/mysql3307.sock
mysql> create database chengdb;
-- 在主库模拟创建数据信息
[root@cheng-01 ~]# mysql -S /tmp/mysql3308.sock
mysql> show databases;
-- 在从库模拟查看数据信息(确认是否同步数据)
mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for source to send event
                  Master_Host: 192.168.30.101
                  Master_User: repl
                  Master_Port: 3307
                Connect_Retry: 10
              Master_Log_File: binlog.000003
          Read_Master_Log_Pos: 869
               Relay_Log_File: cheng-01-relay-bin.000002
                Relay_Log_Pos: 509
        Relay_Master_Log_File: binlog.000003
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
-- 从库上查看数据同步状态情况,看到上面的两个Yes信息,就表示主从数据同步功能设置成功了
复制数据过程监控:

实现主从复制数据监控方法:

方法01:利用数据库自带命令实现监控:

在从库上可以使用SQL语句,进行主从复制数据情况的监控:

sql 复制代码
mysql> show slave status\G
-- 在主库上也可以实现数据复制监控,但是一般情况下更关注的是从库;

监控语句输出信息解读:

内容分类 输出内容 解释说明
主库的复制信息 Master_Host: 192.168.30.101 表示连接主库地址信息
- 利于IO线程工作方面 Master_User: repl 表示连接主库用户信息
Master_Port: 3307 表示连接主库端口信息
Connect_Retry: 10 表示连接主库重试间隔
Master_Log_File: binlog.000004 表示主从同步日志信息
Read_Master_Log_Pos: 156 表示主从同步位置信息
从库的回放信息 Relay_Log_File: cheng-01-relay-bin.000005 表示中继日志回放文件信息
- 利于SQL线程工作方面 Relay_Log_Pos: 365 表示中继日志回放位置信息
Relay_Master_Log_File: binlog.000004 表示对应主库日志文件信息 可以用于帮助判断主从延时的日志量
Exec_Master_Log_Pos: 156 表示对应主库日志位置信息 可以用于帮助判断主从延时的日志量
从库的线程信息 Slave_IO_Running: Yes 表示从库同步数据时-IO线程状态
- 利于判断同步线程情况 Slave_SQL_Running: Yes 表示从库同步数据时-SQL线程状态
Last_IO_Errno: 0 表示从库IO线程异常错误代码
Last_IO_Error: 表示从库IO线程异常错误原因
Last_SQL_Errno: 0 表示从库SQL线程异常错误代码
Last_SQL_Error: 表示从库SQL线程异常错误原因
过滤复制的相关信息 Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
主从复制的延时情况 Seconds_Behind_Master: 0 表示主从之间延时秒数信息
延时从库的状态情况 SQL_Delay: 0 表示延时同步时间间隔情况
SQL_Remaining_Delay: NULL 表示最近事件延时剩余时间
主从GTID复制状态情况 Retrieved_Gtid_Set:
Executed_Gtid_Set:

方法02:利用第三方专业工具实现监控:

可以使用的专业监控工具:pt-table-checksum、pt-table-sync、pt-heartbeat

方法03:利用第三方开源平台实现监控:

可以使用的开源平台介绍:orch (主从拓扑监控管理)

复制故障情况分析:

当出现主从数据库数据不同步时,就可以理解为出现了复数据制故障,一般在从库上分析故障原因,主要是从库上的两个线程出现问题;

  • 从库线程异常分析-IO

确认线程是否出现问题:

tiki 复制代码
# 确认线程运行状态
Slave_IO_Running: Yes
-- 常见异常状态:connecting、no,具体问题情况分析需要查看以下信息;
Last_IO_Errno: 0
Last_IO_Error:
-- 根据以上错误编码和错误信息说明,可以判断产生IO线程异常的原因;

确认线程相关工作职能:(从底层角度分析IO异常原因)

① IO线程主要用于连接主数据库服务;

以上工作职能失败就会导致线程状态为:connecting

​ 可能导致异常原因:

​ - 连接地址、端口、用户、密码信息不对可能会导致连接异常;

​ - 防火墙安全策略阻止连接建立、网络通讯配置异常影响连接建立;

​ - 到达数据库服务连接数上限,造成主从连接产生异常;

​ 线程异常情况排查:

使用主从复制专用用户进行手工连接测试,核实主从复制用户是否可以远程连接登录数据库服务

bash 复制代码
# 正常远程连接测试
[root@cheng-01 ~]# mysql -urepl -p123456 -h192.168.30.101 -P3307
mysql> 
-- 以上测试情况成功;

# 异常远程连接测试
[root@cheng-01 ~]# mysql -urepl1 -p123456 -h192.168.30.101 -P3307
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'repl1'@'cheng-01' (using password: YES)
[root@cheng-01 ~]# mysql -urepl -p123123 -h192.168.30.101 -P3307
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'repl'@'cheng-01' (using password: YES)
-- 以上测试情况失败,输出信息表示建立远程连接的用户名称或密码信息异常;

[root@cheng-01 ~]# mysql -urepl -p123456 -h192.168.30.102 -P3307
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 2003 (HY000): Can't connect to MySQL server on '192.168.30.102:3307' (113)
-- 异常测试情况失败,输出信息表示建立远程连接的地址信息异常;

[root@cheng-01 ~]# mysql -urepl -p123456 -h192.168.30.101 -P3300
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 2003 (HY000): Can't connect to MySQL server on '192.168.30.101:3300' (111)
-- 异常测试情况失败,输出信息表示建立远程连接的端口信息异常;

​ 线程异常情况模拟:

sql 复制代码
# 在从库上临时取消主从关系
[root@cheng-01 ~]# mysql -S /tmp/mysql3308.sock
mysql> stop slave;
mysql> reset slave all;
-- 此次表示主从关系已经解除;

# 在从库上模拟连接错误情况
# 模拟用户名称或者密码信息错误
mysql> CHANGE MASTER TO
  MASTER_HOST='192.168.30.101',
  MASTER_USER='repl',
  MASTER_PASSWORD='123',
  MASTER_PORT=3307,
  MASTER_LOG_FILE='binlog.000003',
  MASTER_LOG_POS=681,
  MASTER_CONNECT_RETRY=10;
-- 模拟从库连接主库时,密码信息出现错误;

mysql> start slave;
-- 再次启动主从同步功能
# 模拟连接地址信息输入错误
CHANGE MASTER TO
  MASTER_HOST='192.168.30.103',
  MASTER_USER='repl',
  MASTER_PASSWORD='123456',
  MASTER_PORT=3307,
  MASTER_LOG_FILE='binlog.000003',
  MASTER_LOG_POS=681,
  MASTER_CONNECT_RETRY=10;

-- 模拟从库连接主库时,地址信息出现错误;
mysql> start slave;
-- 再次启动主从同步功能
# 模拟连接会话超过上限情况
[root@cheng-01 ~]# mysql -S /tmp/mysql3307.sock
-- 在主库上进行连接上限配置
mysql> select @@max_connections;
+---------------------------+
| @@max_connections |
+---------------------------+
|                               151 |
+---------------------------+
1 row in set (0.00 sec)
-- 连接会话数默认为支持151人同时并发连接,超过上限数值后随即拒绝建立连接,但其中还给管理员预留了一个;
mysql> set global max_connections=3;
-- 模拟调整连接数信息
[root@cheng-01 ~]# mysql -S /tmp/mysql3308.sock
mysql> stop slave;
-- 停止从库建立连接
[root@cheng-01 ~]# mysql -uroot  -S /tmp/mysql3307.sock
-- 模拟将连接跑满(重复建立4个连接)
[root@cheng-01 ~]#  mysql -uroot  -S /tmp/mysql3307.sock
ERROR 1040 (HY000): Too many connections
-- 再建立新的连接报错
mysql> start slave;
-- 从库重新建立连接

# 查看主从同步状态情况
# 用户名称或者密码错误异常情况查看:
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_Running: Connecting
Slave_SQL_Running: Yes
Last_IO_Errno: 1045
Last_IO_Error: error connecting to master 'repl@192.168.30.101:3307' - retry-time: 10 retries: 9 message: Access denied for user 'repl'@'cheng-01' (using password: YES)
-- IO线程运行状态为connecting,并且显示IO线程错误码,以及IO线程错误原因说明;
# 地址信息输入异常情况查看:
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_Running: Connecting
Slave_SQL_Running: Yes
Last_IO_Errno: 2003
Last_IO_Error: error connecting to master 'repl@192.168.30.103:3307' - retry-time: 10 retries: 1 message: Can't connect to MySQL server on '192.168.30.103:3307' (113)
-- IO线程运行状态为connecting,并且显示IO线程错误码,以及IO线程错误原因说明;
# 连接上限超出限制情况查看:
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_Running: Connecting
Slave_SQL_Running: Yes
Last_IO_Errno: 1040
Last_IO_Error: error connecting to master 'repl@192.168.30.101:3307' - retry-time: 10 retries: 7 message: Too many connections
-- IO线程运行状态为connecting,并且显示IO线程错误码,以及IO线程错误原因说明;

​ 线程异常情况处理:

sql 复制代码
# 主从搭建过程出现异常:
[root@cheng-01 ~]# mysql -S /tmp/mysql3308.sock
mysql> stop slave;
mysql> reset slave all;
-- 对主从关系进行重置;
CHANGE MASTER TO
  MASTER_HOST='192.168.30.101',
  MASTER_USER='repl',
  MASTER_PASSWORD='123456',
  MASTER_PORT=3307,
  MASTER_LOG_FILE='binlog.000003',
  MASTER_LOG_POS=681,
  MASTER_CONNECT_RETRY=10;
-- 模拟从库重新连接主库;
mysql> drop database chengdb;
mysql> start slave;
-- 再次启动主从同步功能

mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
-- 此时主从异常情况修复;

② IO线程主要用于进行日志信息请求,以及接收日志信息,并将日志信息进行保存(落地);

以上工作职能失败就会导致线程状态为:no

​ 可能导致异常原因:

​ - IO线程在请求日志信息失败,有可能日志信息被无意清理了;

​ - IO线程在请求日志信息失败,有可能主从配置的标识信息重复冲突了;

​ 线程异常情况模拟:

​ 在进行异常情况模拟前,核实确认好主从同步状态是否正常;

sql 复制代码
# 异常情况模拟-01:主库日志信息被清理了
# 在从库上核实同步状态情况
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 192.168.30.101
Master_User: repl
Master_Port: 3307
Connect_Retry: 10
Master_Log_File: binlog.000004
Read_Master_Log_Pos: 341
Relay_Log_File: cheng-01-relay-bin.000005
Relay_Log_Pos: 506

# 在主库上清理日志文件信息
mysql> reset master;
Query OK, 0 rows affected (0.01 sec)
mysql> show master status;
+------------------+-----------+-------------------+-----------------------+-------------------------+
| File                   | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+-----------+-------------------+-----------------------+-------------------------+
| binlog.000001 |         156 |                           |                                 |                                   |
+------------------+-----------+-------------------+-----------------------+-------------------------+
1 row in set (0.00 sec)
-- 模拟主库已经将日志信息清理

# 查看主从同步状态情况
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_Running: No
Slave_SQL_Running: Yes
Last_IO_Errno: 13114
Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'could not find next log; the first event 'binlog.000004' at 156, the last event read from './binlog.000004' at 341, the last byte read from './binlog.000004' at 341.'
-- IO线程运行状态为no,并且显示IO线程错误码,以及IO线程错误原因说明;

# 异常情况模拟-02:主从server_id server_uuid信息配置相同了
# 查看主从服务server_id信息
mysql> select @@server_id;
+-----------------+
| @@server_id |
+-----------------+
|                     7 |
+-----------------+
1 row in set (0.00 sec)
mysql> select @@server_id;
+-----------------+
| @@server_id |
+-----------------+
|                      8 |
+-----------------+
1 row in set (0.00 sec)
-- 核实确认主库server_id为7,从库server_id为8;

# 模拟修改从服务server_id信息
mysql> stop slave;
mysql> set global server_id=7;
mysql> start slave;

# 查看主从同步状态情况
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_Running: No
Slave_SQL_Running: Yes
Last_IO_Errno: 13117
Last_IO_Error: Fatal error: The slave I/O thread stops because master and slave have equal MySQL server ids; these ids must be different for replication to work (or the --replicate-same-server-id option must be used on slave but this does not always make sense; please check the manual before using it).
-- IO线程运行状态为no,并且显示IO线程错误码,以及IO线程错误原因说明;

​ 线程异常情况处理:

sql 复制代码
# 主从搭建过程出现异常修复:
[root@cheng-01 ~]# mysql -S /tmp/mysql3308.sock
mysql> stop slave;
mysql> reset slave all;
-- 对主从关系进行重置;
CHANGE MASTER TO
  MASTER_HOST='192.168.30.101',
  MASTER_USER='repl',
  MASTER_PASSWORD='123456',
  MASTER_PORT=3307,
  MASTER_LOG_FILE='binlog.000001',
  MASTER_LOG_POS=156,
  MASTER_CONNECT_RETRY=10;
-- 模拟从库重新连接主库;
mysql> start slave;
-- 再次启动主从同步功能

mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
-- 此时主从异常情况修复;

# 主从搭建过程出现异常修复:
mysql> set global server_id=8;
mysql> stop slave;
mysql> start slave;

*************************** 1. row ***************************
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
-- 此时主从异常情况修复;
  • 从库线程异常分析-SQL

确认线程是否出现问题:

tiki 复制代码
# 确认线程运行状态
Slave_SQL_Running: Yes
-- 常见异常状态:no,具体问题情况分析需要查看以下信息;
Last_SQL_Errno: 0
Last_SQL_Error:
-- 根据以上错误编码和错误信息说明,可以判断产生SQL线程异常的原因;

确认线程相关工作职能:(从底层角度分析SQL异常原因)

① SQL线程主要用于回放执行relay log日志信息,即执行相关数据同步SQL语句信息;

以上工作职能失败就会导致线程状态为:no(研究SQL线程故障,实质就是在研究SQL语句为什么无法执行)

​ 可能导致异常原因:(从库数据或设置异常导致)

​ - 创建的对象已经存在,涉及到的对象可能有库、表、用户、索引...;

​ - 插入(insert)的操作对象有异常、修改(update alter)的操作对象有异常、删除(delete drop)的操作对象有异常;

​ - 由于数据库设置的约束信息,与执行的SQL语句产生冲突问题;

​ - 在数据库不同版本之间进行数据同步时,可能出现配置冲突问题(比如:5.6可以识别时间为0字段,5.7不能识别时间为0字段)

​ 可能造成异常情况:

​ - 在进行主从配置时,指定的位置点出现错误(change master to);

​ - 在进行主从配置前,从库被写入相应的数据信息了,与主库同步数据产生冲突(误连接从库进行操作了);

​ - 在从库工作繁忙状态时,从库宕机了,业务恢复后可能出现异步同步数据错乱(主库操作创建表操作没同步,同步了插入表操作);

​ - 在进行主从切换时(假设进行的是手工切换),没有正确操作锁定源主库和binlog日志信息;(画图说明)

​ 导致切换前主库数据没有完全同步,切换后从库数据(原主库)比主库数据(原从库)信息更全;

​ - 在应用数据库双主结构时,没有正确使用(经常导致相互同步数据,主键或唯一键冲突)(画图说明)

​ 若企业创建必须使用双主架构,实现双写机制,可以使用全局序列机制,实现主键或唯一键的统一分配;

​ 线程异常情况模拟:

​ 在进行异常情况模拟前,核实确认好主从同步状态是否正常;

sql 复制代码
# 异常情况模拟:模拟误连接从库做写入操作,与主库产生冲突
# 在从库上核实同步状态情况
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 192.168.30.101
Master_User: repl
Master_Port: 3307
Connect_Retry: 10
Master_Log_File: binlog.000001
Read_Master_Log_Pos: 338
Relay_Log_File: cheng-01-relay-bin.000003
Relay_Log_Pos: 321
Relay_Master_Log_File: binlog.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes

# 在从库上创建数据信息(模拟误连接从库执行操作情况)
mysql> create database test1;
Query OK, 1 row affected (0.00 sec)

# 在主库上创建数据信息(实现主库创建数据与从库一致)
mysql> create database test1;
Query OK, 1 row affected (0.00 sec)

# 查看主从同步状态情况
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_Running: Yes
Slave_SQL_Running: No
Last_SQL_Errno: 1007
Last_SQL_Error: Error 'Can't create database 'test1'; database exists' on query. Default database: 'test1'. Query: 'create database test1'
-- SQL线程运行状态为no,并且显示SQL线程错误码,以及SQL线程错误原因说明;

​ 线程异常处理原则:

​ - 主从同步出现数据同步异常,一切数据信息以主库为准;

​ - 尽量不要使用双主架构,避免数据信息双写,造成的数据同步异常;

​ - 主从同步数据信息时候,可以设置从库只读,避免从库误写入冲突;

sql 复制代码
# 从库出现SQL线程异常处理
# 处理方案01:将冲突操作进行回退
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_Running: Yes
Slave_SQL_Running: No
Last_SQL_Errno: 1007
Last_SQL_Error: Error 'Can't create database 'test1'; database exists' on query. Default database: 'test1'. Query: 'create database test1'
-- 此时SQL线程出现异常,需要根据异常错误代码和错误原因描述处理问题;

mysql> drop database test1;
-- 删除从库产生冲突的数据库信息,从而实现冲突情况的回退机制;

mysql> start slave;
-- 冲突异常问题回退后,可以重新启动主从关系

mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
-- 主从关系已经恢复正常;

# 处理方案02:跳过主从同步异常错误,以从库数据为准(不建议使用,除非配合pt-checksum/pt-sync工具使用)
mysql> create database test2;
Query OK, 1 row affected (0.00 sec)
-- 从库创建数据test2,重新SQL线程异常情况
mysql> create database test2;
Query OK, 1 row affected (0.00 sec)
-- 主库创建数据test2,重新SQL线程异常情况
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_Running: Yes
Slave_SQL_Running: No
Last_SQL_Errno: 1007
Last_SQL_Error: Error 'Can't create database 'test2'; database exists' on query. Default database: 'test2'. Query: 'create database test2'
-- 此时SQL线程出现异常,需要根据异常错误代码和错误原因描述处理问题;

mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.01 sec)
mysql> set global sql_slave_skip_counter=1;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> start slave;
Query OK, 0 rows affected, 1 warning (0.01 sec)
-- 先停止主从同步关系,实现跳过错误提示步骤,最后重新建立主从连接;(一般都是配合工具进行修复)
-- 在主键冲突导致的问题,跳过错误时要非常小心,建议将跳过的错误的ID数值需要先抓取出来,否则可以会丢失操作事件

mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
-- 主从关系已经恢复正常;

# 处理方案03:可以设定跳过指定的错误编码
mysql> select @@slave_skip_errors;
+---------------------------+
| @@slave_skip_errors |
+---------------------------+
| OFF                                |
+---------------------------+
1 row in set, 1 warning (0.00 sec)
-- 这种应用风险比较大,不建议生产环境使用
复制延时问题分析:

主从复制的延时问题主要描述的是:(在出现主从数据同步延时问题时,从库的线程还是能够正常工作运行的)

  • 在主库操作执行语句信息后,从库经过一段时间后才进行操作执行的同步;
  • 在主库操作执行语句信息后,从库经过一段时间后也没有进行相关的操作;

主从复制的延时问题造成的影响是:

  • 对于读写分离架构是依赖于主从同步数据环境的,主库作为写节点,从库作为读节点,延时严重会影响从库的读操作体验;
  • 对于高可用架构也是依赖于主从同步数据环境的,主库作为主节点,从库作为备节点,延时严重会影响主备的切换一致性;

主从复制的延时问题出现的原因是:

  • 外部因素导致的延时问题:

    • 网络通讯不稳定,有带宽阻塞等情况,造成主从数据传输同步延时;

    • 主从硬件差异大,从库磁盘性能较低,内存和CPU资源都不够充足;

    • 主从配置区别大,从库配置没有优化,导致并发处理能力低于主库;(参考了解)

  • 主库因素导致的延时问题:

​ - 主要涉及Dump thread工作效率缓慢,可能是由于主库并发压力比较大;

​ - 主要涉及Dump thread工作效率缓慢,可能是由于从库数量比较多导致;

​ - 主要涉及Dump thread工作效率缓慢,主要由于线程本身串型工作方式;(利用组提交缓解此类问题-5.6开始 group commit

​ 主库本身可以并发多个事务运行,默认情况下主从同步Dump thread只有一个,只能采用串型方式传输事务日志信息;

  • 从库因素导致的延时问题:

​ - 从库产生延迟受SQL线程影响较大,由于线程本身串型工作方式导致;

​ 利用不同数据库并行执行事务操作,但是一个库有多张表情况,产生大量并发事务操作,依旧是串型的(5.6开始 多SQL线程回放)

​ 利用logical_clock机制进行并发回放,由于组提交事务是没有冲突的,从库并行执行也不会产生冲突(5.7开始 多SQL线程回放)

​ 根据日志内容信息,获取logical_clock机制的组提交标记信息:(事务级别并发)

bash 复制代码
[root@cheng-01 ~]# cd /data/3307/data/
[root@cheng-01 data]# mysqlbinlog binlog.000001 
#221204 10:27:02 server id 7  end_log_pos 415 CRC32 0xd4ca0729  Anonymous_GTID  last_committed=1       
#221204 12:50:03 server id 7  end_log_pos 603 CRC32 0x06629cba  Anonymous_GTID  last_committed=2        
...省略部分信息...
-- 可以看到日志文件中,有大量last_commited信息,用于标记相同组提交的同步事件信息,并发执行是以事务为单位;
-- 可以看到日志文件中,会利用sequence_number信息,表示一个事务内执行操作顺序;
  • 其他因素导致的延时问题:

​ - 由于数据库大事务产生的数据同步延时问题;(更新100W数据/尽量切割事务)

​ - 由于数据库锁冲突机制的数据同步延时问题;(资源被锁无法同步/隔离级别配置RR-锁冲突严重,可调整RC降低延时 索引主从一致)

​ - 由于数据库过度追求安全配置也会导致同步延时问题(从库关闭双一参数);

主从复制的延时问题监控的方式是:

sql 复制代码
mysql> show slave status\G
*************************** 1. row ***************************
Seconds_Behind_Master: 0
-- 表示主从之间延时秒数时间信息
Relay_Master_Log_File: binlog.000004
Exec_Master_Log_Pos: 156
-- 在从库上利用 show slave status\G 获取binlog日志同步执行位置点
-- 在主库上利用 show master status 获取binlog日志同步生成位置点,与从库进行对比,即可判定是否出现主从延迟问题;