注意
本节和下一节中的许多示例都使用mysql客户端来处理mysqlbinlog生成的二进制日志输出。如果您的二进制日志包含\0(null)字符,那么mysql将无法解析该输出,除非您使用--binary模式选项调用它。
时间点恢复的信息源是在完全备份操作之后生成的一组二进制日志文件。因此,为了允许服务器恢复到某个时间点,必须在其上启用二进制日志记录,这是MySQL 8.0的默认设置
要从二进制日志中恢复数据,您必须知道当前二进制日志文件的名称和位置。默认情况下,服务器在数据目录中创建二进制日志文件,但可以使用--log-bin选项指定路径名,以将文件放置在不同的位置。要查看所有二进制日志文件的列表,请使用以下语句:
mysql> SHOW BINARY LOGS;
要确定当前二进制日志文件的名称,请发出 以下声明:
mysql> SHOW MASTER STATUS;
mysqlbinlog实用程序将二进制日志文件中的事件从二进制格式转换为文本,以便可以查看或应用它们。mysqlbinlog具有根据事件时间或事件在日志中的位置选择二进制日志部分的选项。
应用二进制日志中的事件会导致重新执行它们所表示的数据修改。这样可以在给定的时间段内恢复数据更改。要应用二进制日志中的事件,请使用mysql客户端处理mysqlbinlog输出:
$> mysqlbinlog binlog_files | mysql -u root -p
如果二进制日志文件已经加密(可以从MySQL 8.0.14开始),则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的。
重要
对于SSL模式,VERIFY_CA和VERIFY_IDENTITY是比REQUIRED更好的选择,因为它们有助于防止中间人攻击。若要实现其中一个设置,必须首先确保服务器的CA证书对环境中使用它的所有客户端都可靠可用,否则将导致可用性问题。
当您需要确定事件时间或位置以在执行事件之前选择部分日志内容时,查看日志内容非常有用。要查看日志中的事件,请将mysqlbinlog输出发送到一个分页程序中:
$> mysqlbinlog binlog_files | more
或者,将输出保存在文件中,然后在 文本编辑器:
$> mysqlbinlog binlog_files > tmpfile
$> ... edit 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语句,删除了一个表。您可以执行时间点恢复,将服务器恢复到删除表之前的状态。以下是实现这一目标的一些示例步骤:
注意
虽然恢复的最后一个二进制日志位置也会在恢复和服务器重启后由InnoDB显示,但这不是获取恢复的结束日志位置的可靠方法,因为在显示位置反映的时间之后可能会发生DDL事件和非InnoDB更改。您的备份和恢复工具应该为您的恢复提供最后一个二进制日志位置:例如,如果您正在使用mysqlbinlog执行任务,请检查二进制日志回放的停止位置;如果您使用的是MySQL Enterprise Backup,则最后一个二进制日志位置已保存在备份中。
$> 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的输出中,DROP TABLE为“pets”`cats语句可以在二进制日志的232行#和355行#之间的段中找到,这意味着该语句发生在日志位置232之后,并且该日志位于DROP TABLE语句之后的位置355。
注意
仅使用 --开始日期时间和 --停止日期时间选项来帮助您找到 利息。使用这两个选项指定 不建议应用二进制日志段:有一个 使用 选项。改用 --start-position 和 --stop-position。
$> mysqlbinlog --start-position=155 --stop-position=232 /var/lib/mysql/bin.123456 \
| mysql -u root -p
该命令将所有事务从起始位置恢复到停止位置之前。由于mysqlbinlog的输出在记录每条SQL语句之前都包含SET TIMESTAMP语句,因此恢复的数据和相关的MySQL日志反映了事务执行的原始时间。
您的数据库现在已经恢复到感兴趣的时间点tp,就在表pets.cats被删除之前。
$> mysqlbinlog --start-position=355 /var/lib/mysql/bin.123456 \
| mysql -u root -p
您的数据库已还原为二进制日志文件中记录的最新语句,但跳过了所选事件。