Skip to main content

5.时间点(增量)恢复

简介

时间点恢复是指恢复到给定时间点的数据更改。通常,这种类型的恢复是在恢复完整备份后执行的,使服务器恢复到备份时的状态。然后,时间点恢复使服务器从完整备份时增量更新到最新状态,最近的时间。

使用二进制日志进行时间点恢复

时间点恢复的信息源是完整备份操作后生成的一组二进制日志文件。因此,为了允许服务器恢复到某个时间点,必须在其上启用二进制日志记录,这是 MySQL 8.3 的默认设置。

要从二进制日志恢复数据,必须知道当前二进制日志文件的名称和位置。默认情况下,服务器在数据目录中创建二进制日志文件,但可以使用选项指定路径名 --log-bin以将文件放置在不同的位置。

要查看所有二进制日志文件的列表,请使用以下语句:

SHOW BINARY LOGS;

#输出结果和格式
# Log_name, File_size, Encrypted
'binlog.000001', '944', 'No'
'binlog.000002', '181', 'No'
'binlog.000003', '1074628338', 'No'
'binlog.000004', '1074245912', 'No'
......

要确定当前二进制日志文件的名称,请发出以下语句:

SHOW BINARY LOG STATUS;

#输出结果和格式
# File, Position, Binlog_Do_DB, Binlog_Ignore_DB, Executed_Gtid_Set
'binlog.000009', '348170964', '', '', ''

mysqlbinlog实用程序将二进制日志文件中的事件从二进制格式转换为文本,以便可以查看或应用它们。mysqlbinlog具有用于根据日志中事件时间或事件位置选择二进制日志部分的选项。

应用二进制日志中的事件会导致它们所代表的数据修改被重新执行。这使得能够恢复给定时间范围内的数据更改。要应用二进制日志中的事件,

请使用mysql客户端处理 mysqlbinlog 输出 :

mysqlbinlog binlog_files | mysql -u root -p

如果二进制日志文件已加密,mysqlbinlog 无法像上例那样直接读取它们,但可以使用 --read-from-remote-server ( -R ) 选项从服务器读取它们 。例如:

mysqlbinlog --read-from-remote-server --host=host_name --port=3306  --user=root --password --ssl-mode=required  binlog_files | mysql -u root -p
  • 选项 --ssl-mode=required用于确保二进制日志文件中的数据在传输过程中受到保护

当需要确定事件时间或位置以在执行事件之前选择部分日志内容时,查看日志内容会很有用。要查看日志中的事件,请将 mysqlbinlog输出发送到分页程序中:

mysqlbinlog binlog_files | more

或者,将输出保存在文件中并在文本编辑器中查看该文件:

mysqlbinlog binlog_files > tmpfile

编辑文件后,应用内容如下:

mysql -u root -p < tmpfile

如果要在 MySQL 服务器上应用多个二进制日志,请使用单个连接来应用要处理的所有二进制日志文件的内容。

mysqlbinlog binlog.000001 binlog.000002 | mysql -u root -p

另一种方法是将整个日志写入单个文件,然后处理该文件:

mysqlbinlog binlog.000001 >  /tmp/statements.sql
mysqlbinlog binlog.000002 >> /tmp/statements.sql
mysql -u root -p -e "source /tmp/statements.sql"

使用事件位置进行时间点恢复

上一节解释了使用二进制日志执行时间点恢复的总体思路,本节通过示例详细说明操作。

示例

举例来说,假设2020年3月11日20:06:00左右,执行了一条删除表的SQL语句。可以执行时间点恢复,将服务器恢复到表删除之前的状态。以下是实现这一目标的一些示例步骤:

  1. 恢复在point-in-time of interest时间点( 叫做 tp ,在我们的示例中为 2020 年 3 月 11 日 20:06:00)之前创建的最后一个完整备份。完成后,记下已将服务器恢复到的二进制日志位置以供以后使用,然后重新启动服务器。

  2. 查找与您要恢复数据库的时间点相对应的精确二进制日志事件位置。在我们的示例中,假设我们知道表删除发生的大致时间(tp),我们可以通过使用mysqlbinlog实用程序检查该时间附近的日志内容来找到日志位置。使用 --start-datetime--stop-datetime选项指定 周围的短时间段 ,然后在输出中查找事件。例如: 

    #查找事件
    mysqlbinlog --start-datetime="2020-03-11 20:05:00" \
    --stop-datetime="2020-03-11 20:08:00" --verbose \
    /var/lib/mysql/bin.123456 | grep -C 15 "DROP TABLE"

    /*!80014 SET @@session.original_server_version=80019*//*!*/;
    /*!80014 SET @@session.immediate_server_version=80019*//*!*/;
    SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
    # at 232
    #200311 20:06:20 server id 1 end_log_pos 355 CRC32 0x2fc1e5ea Query thread_id=16 exec_time=0 error_code=0
    SET TIMESTAMP=1583971580/*!*/;
    SET @@session.pseudo_thread_id=16/*!*/;
    SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
    SET @@session.sql_mode=1168113696/*!*/;
    SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
    /*!\C utf8mb4 *//*!*/;
    SET @@session.character_set_client=255,@@session.collation_connection=255,@@session.collation_server=255/*!*/;
    SET @@session.lc_time_names=0/*!*/;
    SET @@session.collation_database=DEFAULT/*!*/;
    /*!80011 SET @@session.default_collation_for_utf8mb4=255*//*!*/;
    DROP TABLE `pets`.`cats` /* generated by server */
    /*!*/;
    # at 355
    #200311 20:07:48 server id 1 end_log_pos 434 CRC32 0x123d65df Anonymous_GTID last_committed=1 sequence_number=2 rbr_only=no original_committed_timestamp=1583971668462467 immediate_commit_timestamp=1583971668462467 transaction_length=473
    # original_commit_timestamp=1583971668462467 (2020-03-11 20:07:48.462467 EDT)
    # immediate_commit_timestamp=1583971668462467 (2020-03-11 20:07:48.462467 EDT)
    /*!80001 SET @@session.original_commit_timestamp=1583971668462467*//*!*/;
    /*!80014 SET @@session.original_server_version=80019*//*!*/;
    /*!80014 SET @@session.immediate_server_version=80019*//*!*/;
    SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
    # at 434
    #200311 20:07:48 server id 1 end_log_pos 828 CRC32 0x57fac9ac Query thread_id=16 exec_time=0 error_code=0 Xid = 217
    use `pets`/*!*/;
    SET TIMESTAMP=1583971668/*!*/;
    /*!80013 SET @@session.sql_require_primary_key=0*//*!*/;
    CREATE TABLE dogs

    从mysqlbinlog的输出中,可以在二进制日志第232行和第355行之间的段中找到DROP TABLE pets.cats语句,这意味着该语句发生在日志位置232之后, 日志位于 DROP TABLE 语句之后的位置 355。

    注意:

    仅使用 --start-datetime和 --stop-datetime 选项来帮助您找到感兴趣的实际事件位置。不建议使用这两个选项来指定要应用的二进制日志段的范围:使用这些选项时丢失二进制日志事件的风险较高。使用 --start-position和 --stop-position代替。

  3. 将二进制日志文件中的事件应用到服务器,在步骤 1 中找到的日志位置开始(假设为 155),到步骤 2 中找到的pt时间点之前的位置结束(这是 232):

    mysqlbinlog --start-position=155 --stop-position=232 /var/lib/mysql/bin.123456 \
    | mysql -u root -p

    该命令恢复从起始位置到停止位置之前的所有事务。由于mysqlbinlog的输出包括 SET TIMESTAMP记录的每条SQL语句之前的语句,因此恢复的数据和相关MySQL日志反映了事务执行的原始时间。

    数据库现已恢复到表 pets.cats 被删除的 tp 时间点。

  4. 除了已经完成的时间点恢复之外,如果还想重新执行您感兴趣的时间点(tp)之后的所有语句,请再次使用 mysqlbinlog 将 tp 之后的所有事件应用到服务器。在步骤 2 中注意到,在我们想要跳过的语句之后,日志位于位置 355; 我们可以将它用于 --start-position 选项,以便包含该位置之后的任何语句:

    mysqlbinlog --start-position=355 /var/lib/mysql/bin.123456 \
    | mysql -u root -p

    您的数据库已恢复到二进制日志文件中记录的最新语句,但跳过了所选事件。