MySQL的binlog(二进制日志)是MySQL数据库中非常重要的日志文件,它记录了所有对数据库的修改操作(如INSERT、UPDATE、DELETE等)。通过 binlog,我们可以实现数据恢复、主从复制、数据审计等功能。因此,定期备份binlog是数据库运维中的关键任务之一。
1 binlog基本概念
1.1 binlog的作用
binlog是MySQL的二进制日志文件,记录了所有对数据库的修改操作。具有以下特点:记录内容:SQL语句或行数据的变化(取决于binlog_format配置)作用:
- 数据恢复:当数据库发生误操作或数据丢失时,可以通过binlog恢复到指定时间点
- 主从复制:binlog是实现MySQL主从复制的核心,从库通过读取主库的binlog来同步数据
- 数据审计:binlog记录了所有对数据库的修改操作,可以用于数据审计和问题排查
1.2 binlog的三种格式
- STATEMENT:记录SQL语句
- ROW:记录每一行数据的变化
- MIXED:混合模式,默认记录SQL语句,但在某些情况下记录行数据
# 查看当前的binlog格式
mysql> SHOW VARIABLES LIKE 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin | ON |
+---------------+-------+
1 row in set (0.00 sec)
mysql>
2 启用binlog
在MySQL中,binlog默认是关闭的,要启用binlog,需要修改MySQL配置文件.
2.1 启用binlog操作步骤
1.编辑MySQL配置文件(通常是/etc/my.cnf)
vim /etc/my.cnf
# [mysqld] 部分添加以下配置:
[mysqld]
log_bin = /data/mysql/log/mysql-bin.log # 启用binlog,并指定文件路径
server_id = 1 # 设置服务器唯一 ID(主从复制时需要)
binlog_format = STATEMENT # 设置binlog格式为STATEMENT
expire_logs_days = 7 # binlog文件保留7天
2.重启MySQL服务
systemctl restart mysqld
2.2 验证是否启用
# 命令
SHOW VARIABLES LIKE 'log_bin';
# 输出示例
mysql> SHOW VARIABLES LIKE 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin | ON |
+---------------+-------+
1 row in set (0.01 sec)
mysql>
3 查看binlog文件
3.1 查看binlog文件列表
# 命令
show binary logs;
# 输出示例
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 398 |
+------------------+-----------+
1 row in set (0.00 sec)
mysql>
3.2 查看当前正在使用的binlog文件
# 命令
show master status;
# 输出示例
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | binlog_Do_DB | binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 | 398 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.01 sec)
mysql>
3.3 查看binlog文件内容
# 命令
mysqlbinlog /data/mysql/log/mysql-bin.000001
# 输出示例
[root@node3 log]# mysqlbinlog /data/mysql/log/mysql-bin.000001
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#250315 19:54:50 server id 100 end_log_pos 123 CRC32 0xfca8eab0 Start: binlog v 4, server v 5.7.43-log created 250315 19:54:50 at startup
# Warning: this binlog is either in use or was not closed properly.
ROLLBACK/*!*/;
binlog '
imrVZw9kAAAAdwAAAHsAAAABAAQANS43LjQzLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAACKatVnEzgNAAgAEgAEBAQEEgAAXwAEGggAAAAICAgCAAAACgoKKioAEjQA
AbDqqPw=
'/*!*/;
# at 123
#250315 19:54:50 server id 100 end_log_pos 154 CRC32 0x0ad1d83d Previous-GTIDs
# [empty]
# at 154
#250315 19:55:50 server id 100 end_log_pos 219 CRC32 0x54470a2a Anonymous_GTID last_committed=0 sequence_number=1 rbr_only=no
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 219
#250315 19:55:50 server id 100 end_log_pos 398 CRC32 0x2e75e0e5 Query thread_id=2 exec_time=0 error_code=0
SET TIMESTAMP=1742039750/*!*/;
SET @@session.pseudo_thread_id=2/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1436549152/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=8/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
ALTER USER 'root'@'localhost' IDENTIFIED WITH 'mysql_native_password' AS '*957813CB0CF9EE59CA0B5D537F62E14D825D3C96'
/*!*/;
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
[root@node3 log]#
4 手动刷新binlog
# 命令
flush binary logs;
# 输出示例
mysql> flush binary logs;
Query OK, 0 rows affected (0.02 sec)
mysql>
说明:执行手动刷新命令后,MySQL会关闭当前的binlog文件并创建一个新的binlog文件,便于备份
mysql> flush binary logs;
Query OK, 0 rows affected (0.01 sec)
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 445 |
| mysql-bin.000002 | 154 |
+------------------+-----------+
2 rows in set (0.00 sec)
mysql>
5 binlog备份数据
5.1 导出指定时间范围的binlog
mysqlbinlog --start-datetime="2025-03-15 00:00:00" --stop-datetime="2025-03-15 19:00:00" /data/mysql/log/mysql-bin.000002 > /data/mysql/backup/binlog_20250315.sql
参数说明:
--start-datetime:指定开始时间
--stop-datetime:指定结束时间
/data/mysql/log/mysql-bin.000005:要导出的binlog文件
/data/mysql/tmp/backup/binlog_20250314.sql:导出的SQL文件路径
5.2 导出指定位置范围的binlog
mysqlbinlog --start-position=123 --stop-position=456 /data/mysql/log/mysql-bin.000002 > /data/mysql/backup/binlog_position.sql
5.3 解码ROW格式的binlog
# 如果binlog格式为 ROW,需要使用--base64-output=DECODE-ROWS选项解码
mysqlbinlog --base64-output=DECODE-ROWS --verbose /data/mysql/log/mysql-bin.000002 > /backup/binlog_decoded.sql
6 实战案例:基于binlog恢复数据
6.1 准备工作
# 在mydb数据库中创建一张临时表,并在临时表插入10条数据
mysql> use mydb;
Database changed
mysql> CREATE TABLE tmp_user (
-> id INT AUTO_INCREMENT PRIMARY KEY,
-> name VARCHAR(50) NOT NULL,
-> age INT
-> ) ENGINE=InnoDB;
INSERT INTO tmp_user (name, age) VALUES
('A', 25),
('B', 30),
Query OK, 0 rows affected (0.06 sec)
mysql> INSERT INTO tmp_user (name, age) VALUES
-> ('A', 25),
-> ('B', 30),
-> ('C', 22),
-> ('D', 28),
-> ('E', 26),
-> ('F', 35),
-> ('G', 29),
-> ('H', 31),
-> ('I', 27),
-> ('J', 24);
commit;Query OK, 10 rows affected (0.07 sec)
Records: 10 Duplicates: 0 Warnings: 0
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
mysql>
mysql> select *from tmp_user;
+----+------+------+
| id | name | age |
+----+------+------+
| 1 | A | 25 |
| 2 | B | 30 |
| 3 | C | 22 |
| 4 | D | 28 |
| 5 | E | 26 |
| 6 | F | 35 |
| 7 | G | 29 |
| 8 | H | 31 |
| 9 | I | 27 |
| 10 | J | 24 |
+----+------+------+
10 rows in set (0.00 sec)
mysql>
6.2 模拟删除表数据
# 模拟误操作将tmp_user表数据删除
mysql> delete from tmp_user;
Query OK, 10 rows affected (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
mysql>
6.3 基于binlog实现数据恢复
6.3.1 查询误操作时间节点
# 这里我们是通过general_log进行查找误操作时间点,使用general_log的前提是开启了general_log
1. 查询是否开启general_log,如果是On则开启
mysql> SHOW VARIABLES LIKE 'general_log';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| general_log | ON |
+---------------+-------+
1 row in set (0.01 sec)
mysql>
2. 查看slow_query_log文件路径
mysql> SHOW VARIABLES LIKE 'general_log_file';
+------------------+-----------------------------+
| Variable_name | Value |
+------------------+-----------------------------+
| general_log_file | /data/mysql/log/general.log |
+------------------+-----------------------------+
1 row in set (0.00 sec)
mysql>
3. 分析general_log的文件/data/mysql/log/general.log
[root@node3 log]# grep -i "insert into" /data/mysql/log/general.log
2025-03-15T23:27:00.712243+08:00 2 Query INSERT INTO tmp_user (name, age) VALUES
[root@node3 log]#
6.3.2 导出binlog
mysqlbinlog --start-datetime="2025-03-15 23:27:00" --stop-datetime="2025-03-15 23:27:05" /data/mysql/log/mysql-bin.000005 > /data/mysql/backup/binlog_recovery.sql
6.3.3 恢复数据
mysql -u root -p -D mydb < /data/mysql/backup/binlog_recovery.sql
[root@node1 log]# mysql -u root -p -D mydb < /data/mysql/backup/binlog_recovery.sql
Enter password:
[root@node1 log]#
6.3.4 验证数据是否恢复
mysql> select * from tmp_user;
+----+------+------+
| id | name | age |
+----+------+------+
| 1 | A | 25 |
| 2 | B | 30 |
| 3 | C | 22 |
| 4 | D | 28 |
| 5 | E | 26 |
| 6 | F | 35 |
| 7 | G | 29 |
| 8 | H | 31 |
| 9 | I | 27 |
| 10 | J | 24 |
+----+------+------+
10 rows in set (0.00 sec)
mysql>