MySQL binlog只记录对数据有更改的语句。另外,二进制日志是由事务组成,只有完整的事务被记录在上面。
The server creates a new file in the series each time it starts or flushes the logs. The server also creates a new binary log file automatically after the current log’s size reaches max_binlog_size.
Sever会在每次重启或flush日志的时候创建一个新的binlog文件。另外,当binlog文件达到
预定义的max_binlog_size
大小的时候也会创建一个。
binlog存储格式
确认MySQL Binlog类型为是row-based(默认)还是statement-based。
mysql> show global variables like '%binlog_format%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW |
+---------------+-------+
默认是基于行,比如插入一行,日志里直接存的的是数据。另外一种是基于语句,是直接存SQL语句。
binlog魔数
魔数就是一个普通的常量,binlog的魔数为:0xfe 0x62 0x69 0x6e
转换为ASCII 0xfe 'b''i''n'
。每个文件的开头四个字节都是这个魔数,代表这是BINLOG文件。
[root@bogon mysql]# hexdump -C mysqlbin.000001
00000000 fe 62 69 6e c6 f9 37 5e 0f 00 00 00 00 77 00 00 |.bin..7^.....w..|
Event
binlog日志的主要组成部分是Event。Event包含头部分和数据部分。
头部分包含时间,server-id,event类型等头信息,
数据部分包含事件特定的数据,主要记录修改了什么数据。
日志文件的第一个事件和最后一个事件比较特殊。第一个事件描述事件记录格式的版本,第二个事件是日志轮转(log rotate)事件。
Event结构
MySQL 5.7 GA以上使用的是V4格式日志,
下图描述event的结构,表示方式是offset:length
,如时间戳timestamp的起始偏移量为0,后4个字节是存时间戳的。
一般情况下不存在extra_headers
这个字段,即event header是固定19字节。
+=====================================+
| event | timestamp 0 : 4 |
| header +----------------------------+
| | type_code 4 : 1 |
| +----------------------------+
| | server_id 5 : 4 |
| +----------------------------+
| | event_length 9 : 4 |
| +----------------------------+
| | next_position 13 : 4 |
| +----------------------------+
| | flags 17 : 2 |
| +----------------------------+
| | extra_headers 19 : x-19 |
+=====================================+
| event | fixed part x : y |
| data +----------------------------+
| | variable part |
+=====================================+
event data部分是由定长部分和变长部分组成。定长部分是根据event类型,同种event类型的定长部分相同,定长部分的长度(y)是由日志第一个事件 format description event (FDE)确定的。
以下解释下各个字段:
ref: https://dev.mysql.com/doc/internals/en/event-header-fields.html
field | description |
---|---|
timestamp | 自1970年开始以来过的秒数 |
type_code | 事件类型 |
server_id | server id |
event_length | 整个事件的长度,通常在1000 bytes以内 |
next_position | 下一个事件的位置 |
binlog提交时机
Binary logging is done immediately after a statement or transaction completes but before any locks are released or any commit is done. This ensures that the log is logged in commit order.
二进制日志在事务提交之前完成。事务未提交的时候,MySQL Server会缓存全部更改,知道接受到COMMIT语句。
事务开始时,线程会分配一个缓存区来缓存语句。如果缓存区过大,则会创建一个新的临时文件。
这个缓存区的预定义大小也是环境变量控制的:
mysql> show global variables like '%binlog_cache_size%';
+-----------------------+----------------------+
| Variable_name | Value |
+-----------------------+----------------------+
| binlog_cache_size | 32768 |
| max_binlog_cache_size | 18446744073709547520 |
+-----------------------+----------------------+
binlog的恢复
binlog恢复是MySQL的按时间点恢复,需要注意以下方面:
- 加入要恢复的时间点跨越多个二进制日志,要在一个命令里完成恢复。
MySQL可以按照时间点和位置进行恢复:
https://dev.mysql.com/doc/refman/8.0/en/point-in-time-recovery.html
按照位置进行恢复的话,你需要了解二进制日志的事件。因为一个插入操作由四个事件组成。
恢复常用命令
# 列出全部二进制日志
SHOW BINARY LOGS;
# 二进制日志现在所处的位置
SHOW MASTER STATUS;
# 将二进制日志重放
mysqlbinlog binlog_files | mysql -u root -p
# 重放方式:自日期开始到二进制日志末尾(指定时间)
mysqlbinlog --start-datetime="2005-04-20 9:55:00" binlog.000001| mysql -u root -p
# 重放方式:自某位置开始到二进制日志末尾(指定位置)
mysqlbinlog --start-position=368315 binlog.000001| mysql -u root -p