简介
binlog是一个二进制格式的文件,用于记录用户对数据的更新操作,一般来说,开启binlog大概会带来1%的性能损耗。
binlog的使用场景:主从复制、数据恢复
binlog日志中包含日志索引文件和日志文件,日志索引文件用于记录所有的二进制文件,日志文件中记录对数据库的修改操作,包括DML和DDL
查看binlog的配置
在mysql客户端执行如下命令,查看binlog的相关配置
1、查看是否开启binlog: show variables like 'log_bin' ,ON表示已开启
2、查看binlog的相关变量: show variables like '%log_bin%' 、 show variables like '%binlog%'
变量内容讲解:
-
是否开启binlog
-
log_bin:默认值为ON,表示已开启binlog
-
sql_log_bin:当前会话的binlog记录是否开启,ON是已开启
-
-
binlog的文件存放位置:
- log_bin_basename:binlog文件的基础路径,例如 /var/lib/mysql/binlog.000001 等文件
- log_bin_index:binlog索引文件的路径
-
binlog_format:binlog的日志格式,默认是ROW,共有有三个可选值:
- ROW:记录每行数据的变化,不记录SQL语句,它的优点是数据安全,缺点是日志文件比较大,不易阅读
- STATEMENT:记录实际执行的sql语句
- MIXED:混合模式,大部分使用STATEMENT,特殊情况使用ROW,例如某些根据时间来删除数据的sql,它对于数据库的操作是不稳定的,不同时间执行会获得不同的结果,所以需要使用ROW模式。
-
binlog保留策略的相关配置:
- binlog_expire_logs_seconds:默认值是2592000,单位是秒,表示30天,表示binlog默认保留30天
- binlog_expire_logs_auto_purge:值为ON,表示自动清理过期的binlog
-
binlog性能相关配置:
- max_binlog_size:单个binlog文件最大1GB
- sync_binlog:每次提交都同步到磁盘,默认中是1
- 0:由系统决定何时同步
- 1:每次事务提交都同步(最安全,数据不丢失)
- N:每N次事务提交同步一次
- binlog_cache_size:binlog缓存32KB
-
高级特性:
- binlog_row_image:FULL,记录完整的行数据
- binlog_checksum:CRC32,binlog校验算法
- binlog_row_metadata:MINIMAL,行元数据记录最小化
- binlog_rows_query_log_events: OFF,不记录原始SQL语句,如果设为ON,会在ROW格式下同时记录原始SQL语句,建议在生产环境设为ON,便于问题排查
总结:从这些配置中,可以看出
- binlog默认是开启的
- binlog的存放目录,这里是/var/lib/mysql/
- binlog的格式,这里是ROW,它记录的sql操作的数据,并且会导致binlog文件比较大
- binlog的生成,默认每次提交都同步到磁盘,默认保留30天
配置binlog
案例:
text
[mysqld]
#配置serverid
server-id=1
这里全部使用binlog的默认配置,只额外配置一个服务器的id,主从同步时需要使用到
配置完成后重启mysql服务:systemctl restart mysqld
介绍binlog中的内容
binlog由一系列事件组成,除了binlog自身独有的事件,例如文件创建、文件轮转,大多数事件都对应了mysql的一条sql。
事件的结构:
- 事件头:包含事件类型、时间戳、服务器ID等
- 事件体:事件的具体内容
- 校验和
binlog中的事件类型:
- Format_desc事件:binlog文件的开始事件,所有binlog文件都是已这个事件开始的。这个事件记录的信息中包含服务器的版本、binlog版本
- Previous_gtids事件:记录之前所有binlog文件中的gtid集合
- Anonymous_Gtid事件:在没有启动GTID时,标识事务开始,
- Query事件:查询事件
- Table_map事件:表映射事件,建立表名到内部id的映射,通过这种方式减少数据量
- Delete_rows事件:删除行,
- Xid事件:事务提交事件
- Rotate事件:binlog文件轮转事件,当前binlog文件结束,切换到下一个binlog文件
这里没有列举出全部,还有诸如 Update_rows、Write_rows 等事件
事件的位置:position,相当于这个事件的下标,在文件中唯一标识这个事件,根据它来操作binlog
事件的GTID:Global Transaction Identifier,全局事务标识符,mysql 5.6之后引入的新特性,为每个事务分配一个全局唯一的标识符。GTID默认是关闭的,通过它来指定事件会更方便。
查看binlog中的内容
1、查看当前mysql实例有哪些binlog:show master logs
text
+---------------+-----------+-----------+
| Log_name | File_size | Encrypted |
+---------------+-----------+-----------+
| binlog.000028 | 377 | No |
| binlog.000029 | 509 | No |
| binlog.000030 | 157 | No |
+---------------+-----------+-----------+
这里共查询到3个binlog文件,包括文件名称、文件大小、是否加密
2、查看当前binlog点位:show master status
text
+---------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------+----------+--------------+------------------+-------------------+
| binlog.000030 | 157 | | | |
+---------------+----------+--------------+------------------+-------------------+
这里的内容是最后一个binlog文件的名称、最后一次操作时间的position值
3、查看binlog中的事件:show binlog events in 'binlog.000029';
text
+---------------+-----+----------------+-----------+-------------+--------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+---------------+-----+----------------+-----------+-------------+--------------------------------------+
| binlog.000029 | 4 | Format_desc | 1 | 126 | Server ver: 8.0.38, Binlog ver: 4 |
| binlog.000029 | 126 | Previous_gtids | 1 | 157 | |
| binlog.000029 | 157 | Anonymous_Gtid | 1 | 236 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| binlog.000029 | 236 | Query | 1 | 311 | BEGIN |
| binlog.000029 | 311 | Table_map | 1 | 374 | table_id: 97 (blog.ms_tag) |
| binlog.000029 | 374 | Delete_rows | 1 | 434 | table_id: 97 flags: STMT_END_F |
| binlog.000029 | 434 | Xid | 1 | 465 | COMMIT /* xid=17 */ |
| binlog.000029 | 465 | Rotate | 1 | 509 | binlog.000030;pos=4 |
+---------------+-----+----------------+-----------+-------------+--------------------------------------+
内容解读:这里只做部分介绍,可以在Info列中看到,BEGIN到COMMIT之间,就是一个删除事务,根据binlog来恢复数据,就是以事务为单位的。
3、查看binlog文件中的内容:mysqlbinlog binlog.000029,使用mysqlbinlog命令,进入binlog所在目录,查看文件中的内容,因为是二进制内容,所以要使用mysqlbinlog命令。
文件中,关于sql操作的数据,使用加密的,如果想要查看,需要指定参数:mysqlbinlog --base64-output=DECODE-ROWS -v binlog.000029
原始的sql日志不太好看,有一个关键点,就是找 # at N 的位置,它表示一个事件开始,N是字节偏移
根据binlog恢复数据
根据binlog恢复数据的原理,是通过把binlog中执行的操作全部再执行一次,然后跳过需要被排除的操作,来恢复错误操作带来的影响,同时还要注意,如果binlog因过期等原因被删除,那么通过binlog无法恢复数据。
任意时间点的数据状态 = 基础备份状态 + 从备份时间点到目标时间点的所有变更 - 需要排除的错误变更,所以使用binlog恢复数据,依赖最新备份的数据 + 这之间所有的binlog日期 - 错误变更,或者全量的binlog日志
常见的方式是:定期备份数据,然后清理已备份数据的binlog,如果需要通过binlog来恢复数据,就把数据恢复到最新备份,然后执行最新备份到当前时间的binlog,跳过需要被排除的事务,从而达到恢复操作的目的。
恢复时必须以事务为单位,也就是日志中BEGIN到COMMIT之间的所有操作,是一个单位
恢复数据之前最好备份当前数据,同时停止服务,避免误操作。
方式一
案例:重新执行所有的binlog,跳过需要被排除的事务,通过position来指定需要被排除的事务
text
# 应用删除前的操作(4-236)
mysqlbinlog --start-position=4 --stop-position=236 binlog.000029 | mysql -u root -p blog
# 应用删除后的操作(465-509)
mysqlbinlog --start-position=465 binlog.000029 | mysql -u root -p blog
这里只是一个案例,演示一下命令的使用,实际上当前binlog无法恢复数据,因为在删除数据之前,新增数据的binlog已经过期了,所以即使执行当前命令,也无法恢复数据。这里仅仅演示命令的使用。
案例2:通过时间点来指定需要被排除的事务
text
mysqlbinlog \
--start-datetime="2025-12-19 00:00:00" \
--stop-datetime="2025-12-19 13:56:09" \
binlog.000029 | mysql -u root -p blog
这里是把数据库中的数据恢复到指定时间点之前,因为在日志中,删除操作在 251219 13:56:10 执行,所以指定一个比它早的时间 "2025-12-19 13:56:09"
方式二
根据binlog,生成相反的操作,然后恢复数据,这需要依赖第三方工具,例如binlog2sql,有时间再介绍
通过binlog同步数据的流程
通过binlog同步数据的流程:
- 主库写binlog
- 主库发送binlog,主库会使用一个单独的线程来发送binlog
- 从库接收binlog,并且把它写入到relay log
- 从库回放:从库执行relay log中的sql,达到数据同步的目的