MySQL Binlog详解


MySQL Binlog

MySQL 的 Binlog 日志是一种二进制格式的日志,Binlog 记录所有的 DDL 和 DML 语句(除了数据查询语句SELECT、SHOW等),以 Event 的形式记录,同时记录语句执行时间。

Binlog 包括两类文件:

  • 二进制日志索引文件(.index):记录所有的二进制文件。
  • 二进制日志文件(.00000*):记录所有 DDL 和 DML 语句事件。

作用

  1. 数据恢复

    因为 Binlog 详细记录了所有修改数据的 SQL,当某一时刻的数据误操作而导致出问题,或者数据库宕机数据丢失,那么可以根据 Binlog 来回放历史数据。

  2. 主从复制

    想要做多机备份的业务,可以去监听当前写库的 Binlog 日志,同步写库的所有更改。

MySQL Binlog配置

设置此参数表示启用binlog功能,并制定二进制日志的存储目录
log-bin=/home/mysql/binlog/

#mysql-bin.*日志文件最大字节(单位:字节)
#设置最大100MB
max_binlog_size=104857600

#设置了只保留7天BINLOG(单位:天)
expire_logs_days = 7

#binlog日志只记录指定库的更新
#binlog-do-db=db_name

#binlog日志不记录指定库的更新
#binlog-ignore-db=db_name

#写缓冲多少次,刷一次磁盘,默认0
sync_binlog=0
  • max_binlog_size :Binlog 最大和默认值是 1G,该设置并不能严格控制 Binlog 的大小,尤其是 Binlog 比较靠近最大值而又遇到一个比较大事务时,为了保证事务的完整性不可能做切换日志的动作,只能将该事务的所有 SQL 都记录进当前日志直到事务结束。所以真实文件有时候会大于 max_binlog_size 设定值。
    expire_logs_days :Binlog 过期删除不是服务定时执行,是需要借助事件触发才执行,事件包括:

    • 服务器重启
    • 服务器被更新
    • 日志达到了最大日志长度 max_binlog_size
    • 日志被刷新

    二进制日志由配置文件的 log-bin 选项负责启用,MySQL 服务器将在数据根目录创建两个新文件mysql-bin.000001mysql-bin.index,若配置选项没有给出文件名,MySQL 将使用主机名称命名这两个文件,其中 .index 文件包含一份全体日志文件的清单。

    sync_binlog:这个参数决定了 Binlog 日志的更新频率。默认 0 ,表示该操作由操作系统根据自身负载自行决定多久写一次磁盘。

    sync_binlog = 1 表示每一条事务提交都会立刻写盘。sync_binlog=n 表示 n 个事务提交才会写盘。

    根据 MySQL 文档,写 Binlog 的时机是:SQL transaction 执行完,但任何相关的 Locks 还未释放或事务还未最终 commit 前。这样保证了 Binlog 记录的操作时序与数据库实际的数据变更顺序一致。

Binlog 日志格式

针对不同的使用场景,Binlog 也提供了可定制化的服务,提供了三种模式来提供不同详细程度的日志内容。

  • Statement 模式:基于 SQL 语句的复制(statement-based replication-SBR)
  • Row 模式:基于行的复制(row-based replication-RBR)
  • Mixed 模式:混合模式复制(mixed-based replication-MBR)
Statement 模式

保存每一条修改数据的SQL。

该模式只保存一条普通的SQL语句,不涉及到执行的上下文信息。

因为每台 MySQL 数据库的本地环境可能不一样,那么对于依赖到本地环境的函数或者上下文处理的逻辑 SQL 去处理的时候可能同样的语句在不同的机器上执行出来的效果不一致。

比如像 sleep()函数,last_insert_id()函数,等等,这些都跟特定时间的本地环境有关。

Row 模式

MySQL V5.1.5 版本开始支持Row模式的 Binlog,它与 Statement 模式的区别在于它不保存具体的 SQL 语句,而是记录具体被修改的信息。

比如一条 update 语句更新10条数据,如果是 Statement 模式那就保存一条 SQL 就够,但是 Row 模式会保存每一行分别更新了什么,有10条数据。

Row 模式的优缺点就很明显了。保存每一个更改的详细信息必然会带来存储空间的快速膨胀,换来的是事件操作的详细记录。所以要求越高代价越高。

Mixed 模式

Mixed 模式即以上两种模式的综合体。既然上面两种模式分别走了极简和一丝不苟的极端,那是否可以区分使用场景的情况下将这两种模式综合起来呢?

在 Mixed 模式中,一般的更新语句使用 Statement 模式来保存 Binlog,但是遇到一些函数操作,可能会影响数据准确性的操作则使用 Row 模式来保存。这种方式需要根据每一条具体的 SQL 语句来区分选择哪种模式。

MySQL 从 V5.1.8 开始提供 Mixed 模式,V5.7.7 之前的版本默认是Statement 模式,之后默认使用Row模式, 但是在 8.0 以上版本已经默认使用 Mixed 模式了。

通过 mysqlbinlog 命令手动恢复数据

如果我们当前的 MySQL 库被无操作或者误删除了,那么该如何通过 Binlog 来恢复到删除之前的数据状态呢?

首先发现误操作之后,先停止 MySQL 服务,防止继续更新。

接着通过 mysqlbinlog命令对二进制文件进行分析,查看误操作之前的位点信息在哪里。

接下来肯定就是恢复数据,当前数据库的数据已经是错的,那么就从开始位置到误操作之前位点的数据肯定的都是正确的;如果误操作之后也有正常的数据进来,这一段时间的位点数据也要备份。

比如说:

误操作的位点开始值为 501,误操作结束的位置为705,之后到800的位点都是正确数据。

那么从 0 - 500 ,706 - 800 都是有效数据,接着我们就可以进行数据恢复了。

先将数据库备份并清空。

接着使用 mysqlbinlog 来恢复数据:

0 - 500 的数据:

mysqlbinlog --start-position=0  --stop-position=500  bin-log.000003 > /root/back.sql;

上面命令的作用就是将 0 -500 位点的数据恢复到自定义的 SQL 文件中。同理 706 - 800 的数据也是一样操作。之后我们执行这两个 SQL 文件就行了。


文章作者: SongAn
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 SongAn !
  目录