【Mysql高级】日志(下)系统故障,如何恢复数据?

文章目录

  • 前言
  • 一、二进制日志
    • 1,概述
    • 2 ,如何使用二进制日志
      • 2.1查看二进制日志
      • 2.2刷新二进制日志
      • 2.3用二进制日志恢复数据
      • 2.4 删除二进制日志
      • 2.5恢复实例
  • 二、中继日志
    • 1,概述
  • 三,回滚日志
      • 1,概述
      • 2,回滚日志变量设置
  • 四,重做日志
      • 1、概述重做日志的作用
      • 2,重做日志变量含义
  • 总结


前言

上节课,咱们学习了通用查询日志、慢查询日志和错误日志,它们可以帮助我们快速定位系统问题。但实际上,日志也可以帮助我们找回由于误操作而丢失的数据,比如二进制日志(binary log)、中继日志(relay log)、回滚日志(undo log)和重做日志(redolog)


一、二进制日志

1,概述

二进制日志主要记录数据库的更新事件,比如创建数据表、更新表中的数据、数据更新所花费的时长等信息。通过这些信息,我们可以再现数据更新操作的全过程。而且,由于日志的延续性和时效性,我们还可以利用日志,完成无损失的数据恢复和主从服务器之间的数据同步。
可以说,二进制日志是进行数据恢复和数据复制的利器。

2 ,如何使用二进制日志

如何操作二进制日志?操作二进制日志,主要包括查看、刷新二进制日志用二进制日志恢复数据,以及删除二进制日志

2.1查看二进制日志

查看二进制日志主要有 3 种情况,

  • 正在写入的二进制日志
  • 查看所有的二进制日志
  • 查看二进制日志中的所有数据更新事件

查看正在写入的二进制日志Sql:

可以看到查看二进制文件的名称和当前写入的位置:

 mysql> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000009 |      154 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.06 sec)

查看所有的二进制日志

mysql> show binary logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |       589 |
| mysql-bin.000002 |      2196 |
| mysql-bin.000003 |       177 |
| mysql-bin.000005 |       177 |
| mysql-bin.000006 |       177 |
| mysql-bin.000007 |       177 |
| mysql-bin.000008 |    125141 |
| mysql-bin.000009 |       154 |
+------------------+-----------+
8 rows in set (19.51 sec)

查看二进制文件中所有更新事件的二进制日志:
SHOW BINLOG EVENTS in 二进制文件名;

mysql> SHOW BINLOG EVENTS in "mysql-bin.000009";
+------------------+-----+----------------+-----------+-------------+---------------------------------------+
| Log_name         | Pos | Event_type     | Server_id | End_log_pos | Info                                  |
+------------------+-----+----------------+-----------+-------------+---------------------------------------+
| mysql-bin.000009 |   4 | Format_desc    |         1 |         123 | Server ver: 5.7.27-log, Binlog ver: 4 |
| mysql-bin.000009 | 123 | Previous_gtids |         1 |         154 |                                       |
+------------------+-----+----------------+-----------+-------------+---------------------------------------+
2 rows in set (0.06 sec)

2.2刷新二进制日志

刷新二进制日志的 SQL 语句是:

mysql> FLUSH BINARY LOGS;
Query OK, 0 rows affected (0.04 sec)
mysql> show binary logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |       589 |
| mysql-bin.000002 |      2196 |
| mysql-bin.000003 |       177 |
| mysql-bin.000005 |       177 |
| mysql-bin.000006 |       177 |
| mysql-bin.000007 |       177 |
| mysql-bin.000008 |    125141 |
| mysql-bin.000009 |       201 |
| mysql-bin.000010 |       154 |
+------------------+-----------+
9 rows in set (0.07 sec)

这条语句的意思是,关闭服务器正在写入的二进制日志文件,并重新打开一个新文件,文件名的后缀在现有的基础上加 1 ,原来是9现在是10了。

2.3用二进制日志恢复数据

mysqlbinlog  --start-position=xxx   --stop-position=yyy   "二进制文件名"  | mysql -u user -p 

这条命令的意思是,执行二进制日志中从位置 xxx 开始,到 yyy 截止的所有数据更新操作。这里的截止位置也可以不写,意思是从位置 xxx 开始,执行二进制文件中的所有数据更新操作。

2.4 删除二进制日志

如果我们已经把日志文件保存到了安全的地方,就可以通过下面的 SQL 语句删除所有二进制日志文件,以释放磁盘空间:

mysql> RESET MASTER
    -> ;
2013 - Lost connection to MySQL server during query
mysql> RESET MASTER;
Query OK, 0 rows affected (0.20 sec)

mysql> SHOW BINARY LOGS;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000005 |       154 |
+------------------+-----------+
1 row in set (0.08 sec)

结果显示,所有二进制日志文件都被删除了,MySQL 从头准备了一个“.000005”为后缀的新的二进制日志文件。
我们也可以通过 SQL 语句,删除比指定二进制日志文件编号小的所有二进制日志文件。

mysql> show binary logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000006 |       201 |
| mysql-bin.000007 |       201 |
| mysql-bin.000008 |       201 |
| mysql-bin.000009 |       201 |
| mysql-bin.000010 |       154 |
+------------------+-----------+
5 rows in set (0.08 sec)

mysql> purge master logs to "mysql-bin.000010";
Query OK, 0 rows affected (0.04 sec)

mysql> show binary logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000010 |       154 |
+------------------+-----------+
1 row in set (0.09 sec)

比mysql-bin.00001 小的日志都被删除了

2.5恢复实例

这里我们先增减一条数据然后,删除,在通过mysqlbinlog 恢复数据

第一步:增加数据3然后删除
【Mysql高级】日志(下)系统故障,如何恢复数据?_第1张图片

第二步:恢复数据3

##查看日志中的事件
mysql> SHOW BINLOG EVENTS in "mysql-bin.000010";
+------------------+-----+----------------+-----------+-------------+-------------------------------------------------------------------------------------------------+
| Log_name         | Pos | Event_type     | Server_id | End_log_pos | Info                                                                                            |
+------------------+-----+----------------+-----------+-------------+-------------------------------------------------------------------------------------------------+
| mysql-bin.000010 |   4 | Format_desc    |         1 |         123 | Server ver: 5.7.27-log, Binlog ver: 4                                                           |
| mysql-bin.000010 | 123 | Previous_gtids |         1 |         154 |                                                                                                 |
| mysql-bin.000010 | 154 | Anonymous_Gtid |         1 |         219 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'                                                            |
| mysql-bin.000010 | 219 | Query          |         1 |         298 | BEGIN                                                                                           |
| mysql-bin.000010 | 298 | Query          |         1 |         455 | use `blog`; INSERT INTO `blog`.`ms_admin` (`id`, `username`, `password`) VALUES (3, 'ss', 'sd') |
| mysql-bin.000010 | 455 | Xid            |         1 |         486 | COMMIT /* xid=120 */                                                                            |
+------------------+-----+----------------+-----------+-------------+-------------------------------------------------------------------------------------------------+

##使用二进制日志进行恢复的命令
[root@cz1998 bin]# ./mysqlbinlog  --start-position=298 --stop-position=486 "/www/mysql_data/mysql-5.7.27/data/mysql-bin.000010"  | ./mysql -uroot -p 
Enter password: 
[root@cz1998 bin]# ^C


【Mysql高级】日志(下)系统故障,如何恢复数据?_第2张图片

通过查看二进制日志中的事件,你会发现,写入第二条记录的时候,MySQL 使用了一个事务操作,起始位置是298,截止位置是486。这样,就可以用mysqlbinlog 工具进行数据恢复了。日志名称是“/www/mysql_data/mysql-5.7.27/data/mysql-bin.000010”读取日志的起始位置是 298。
第三步:查看数据是否恢复
在这里插入图片描述
数据回复了 ,这里说明恢复成功。

二、中继日志

1,概述

中继日志只在主从服务器架构的从服务器上存在。从服务器为了与主服务器保持一致,要从主服务器读取二进制日志的内容,并且把读取到的信息写入本地的日志文件中,这个从服务器本地的日志文件就叫中继日志。然后,从服务器读取中继日志,并根据中继日志的内容对从服务器的数据进行更新,完成主从服务器的数据同步。
搭建好主从服务器之后,中继日志默认会保存在从服务器的

  1. 数据目录(/www/mysql_data/mysql-5.7.27/data)
  2. 文件名的格式是:从服务器名 -relay-bin. 序号
  3. 中继日志还有一个索引文件:从服务器名 -relay-bin.index,用来定位当前正在使用的中继日志

中继日志与二进制日志的格式相同,可以用 mysqlbinlog 工具进行查看。下面是中继日志的一个片段:

【Mysql高级】日志(下)系统故障,如何恢复数据?_第3张图片

这一段的意思是,主服务器(“server id 1”)对表 demo.test 进行了 2 步操作:

  1. 定位到表 demo.test 编号是 91 的记录,日志位置是 832;
  2. 删除编号是 91 的记录,日志位置是 872。
  3. 关于中继日志,有一个很容易踩到的坑。如果从服务器宕机,有的时候为了系统恢复,你要重装操作系统,这样就可能会导致你的服务器名称与之前不同。而中继日志的名称里面是包含从服务器名的。因此,在这种情况下,就可能导致你恢复从服务器的时候,无法从宕机前的中继日志里读取数据,以为是日志文件损坏了,其实是文件名不对了。解决的方法也很简单,只要把从服务器的名称改回之前的名称就可以了。

三,回滚日志

1,概述

回滚日志的作用是进行事务回滚
1,当事务执行的时候,回滚日志中记录了事务中每次数据更新前的状态。当事务需要回滚的时候,可以通过读取回滚日志,恢复到指定的位置。
2,另一方面,回滚日志也可以让其他的事务读取到这个事务对数据更改之前的值,从而确保了其他事务可以不受这个事务修改数据的影响。

2,回滚日志变量设置

mysql> SHOW VARIABLES LIKE "%innodb_max_undo_log_size%";
+--------------------------+------------+
| Variable_name            | Value      |
+--------------------------+------------+
| innodb_max_undo_log_size | 1073741824 |
+--------------------------+------------+
1 row in set (0.01 sec)

变量"innodb_max_undo_log_size”的意思是,单个回滚日志最大可占用 1G 字节存储空

下面几个变量定义了
是否加密、是否自动截断 ,是否有独立的表空间。


mysql> SHOW VARIABLES LIKE '%innodb_undo%';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_undo_directory    | ./    |-- 表示回滚日志的存储目录是数据目录。
| innodb_undo_log_truncate | OFF   |--表示回滚日志是否自动截断回收,这个变量有效的前提是设置了独立表空间。
| innodb_undo_logs         | 128   |--
| innodb_undo_tablespaces  | 0     |----表示回滚日志有自己的独立表空间,而不是在其享表空间
+--------------------------+-------+
4 rows in set (0.00 sec)

如果开启了 innodb_file_per_table ,将放在每个表的.ibd文件中。

四,重做日志

1、概述重做日志的作用

重做日志是存储在磁盘上的一种日志文件,主要有 2 个作用。

  1. 在系统遇到故障的恢复过程中,可以修复被未完成的事务修改的数据。
    MySQL为了提高数据存取的效率,减少磁盘操作的频率,对数据的更新操作不会立即写到磁盘上,而是把数据更新先保存在内存中,积累到一定程度,再集中进行磁盘读写操作。这样就存在一个问题:一旦出现宕机或者停电等异常情况,内存中保存的数据更新操作可能会丢失。
  2. 这个时候就可以通过读取重做日志中记录的数据更新操作,把没来得及写到磁盘上的数据更新写到磁盘上,确保数据的完整性。我们可以通过系统变量的值,了解重做日志所在的文件夹和文件的数量。这些是我们进一步了解系统运行机制的必要条件,有助于我们开发出高效的数据库应用。

2,重做日志变量含义

mysql> SHOW VARIABLES LIKE '%innodb_log_files_in_group%';
+---------------------------+-------+
| Variable_name             | Value |
+---------------------------+-------+
| innodb_log_files_in_group | 2     |
+---------------------------+-------+
1 row in set (0.00 sec)

结果显示,变量 innodb_log_files_in_group 值是 2,表示有 2 个重做日志文件。需要注意的是,变量 innodb_log_files_in_group 值的取值范围是 1~4,这四个文件分别用于记录不同的操作

  1. 用户创建表的插入操作;
  2. 用户创建表的更新和删除操作;
  3. 临时表的插入操作;
  4. 临时表的更新和删除操作;
    那么,为什么在我的电脑上,变量 innodb_log_files_in_group 值是 2 呢?其实这是因为,我只执行了对用户创建表的插入操作和更新删除操作,所以,只用到了 2个文件。如果我还执行了临时表的插入和更新删除的操作,那么这个变量的值就会变成4,也就是会有4个重做日志文件了。

总结

我们学习了二进制日志、中继日志、回滚日志和重做日志。

  1. 二进制日志:主要用于主从服务器之间的数据同步,以及服务器遇到故障时数据的无损失恢复。
  2. 中继日志:就是主从服务器架构中,从服务器用来存放主服务器二进制日志内容的一个中间文件。从服务器通过读取中继日志的内容,来同步主服务器上的操作。
  3. 回滚日志:用来存储事务中数据更新前的状态,以便回滚和保持其他事务的数据一致性。
  4. 重做日志:是为了确保数值持久性、防止数据更新丢失的一种日志。
  5. 在这几种日志中,你一定要格外注意二进制日志的用法。有了它,我们就可以通过数据库的全量备份和二进制日志中保存的增量信息,完成数据库的无损失恢复。不过,我要提醒你,如果你遇到数据量大、数据库和数据表很多(比如分库分表的应用)的场景,用二进制日志进行数据恢复,是很有挑战性的,因为起止位置不容易管理。在这种情况下,一个有效的解决办法是配置主从数据库服务器,甚至是一主多从的架构,二进制日志文件的内容通过中继日志,同步到主数据库服务器中,这样就可以有效避免数据库故障导致的数据异常等问题。

你可能感兴趣的:(Mysql,mysql,数据库,database)