一文读懂MySQL的BinLog写入机制|原创

时间:2022-08-19 01:19:32

来源:后端开发技术


本文深入讲解了MySQL中的重要日志 binlog 的写入机制以及影响IO性能的关键配置,并且介绍了如何利用binlog去恢复数据,保证MySQL的可靠性。

binlog 写入机制

binlog 的写入逻辑并不复杂:事务执行过程中,先把日志写到 binlog cache,事务提交的时候,再把 binlog cache 写到 binlog 文件中。

一文读懂MySQL的BinLog写入机制|原创

binlog cache

binlog cache 在事务的运行期间暂存着binlog的数据,binlog cache 是在每个线程内空间独立的。如果启用了bin log日志,MySQL 会为每个客户端分配一个二进制日志缓存。如果您经常使用大型事务,则可以增加此缓存大小以获得更好的性能,可通过  binlog_cache_size 配置其大小,默认 32768 bytes

如果binlog cache空间足够,在事务提交的时候,cache中的内容会被清空,同时这些数据会被写入到 binlog files 中;因为 bin log内容无论多大在事务提交时都需要一次性写入,所以当 bin log cache放不下的时候,就需要暂存到磁盘,然后提交被写入到 binlog files。

一文读懂MySQL的BinLog写入机制|原创

参数 binlog_cache_size:控制单个线程内 binlog cache 所占内存的大小

上面说的 写入到 bin log 中其实又拆为两部分:

write:首先会写入 page cache 中的 binlog files 中,page cache 就是一块内存。(不占用磁盘IOPS)

fsync:然后操作系统执行 fsync 时 bin log 才会从 page cache 中真正持久化到磁盘。(占用磁盘IOPS)一文读懂MySQL的BinLog写入机制|原创

write 和 fsync 时机

关于write和fsync 的时机,是通过参数 sync_binlog 控制:

sync_binlog=0:表示每次提交事务只是 write,不执行 fsync,也就是binlog不做持久化。(不建议)

sync_binlog=1:表示每次提交事务都要发生 fsync。

sync_binlog=N:表示每次事务都会write,但是N次事务提交会执行fsync进行持久化。

通常来说,为了提高IOPS,会将这个参数设为100-1000。缺点是如果还没有执行fsync就宕机,最多会丢失最近N个事务的binlog日志。如果为了保证数据安全,就设为1。

官方文档描述如下:

一文读懂MySQL的BinLog写入机制|原创

如果 binlog 内容缺失怎么办

对于通过 redo log 可以恢复数据,我们都已经知道了,但是如果 binlog 内容缺失呢?

根据 sync_binlog 参数描述,如果设置为大于一,就代表N次事务才会将log持久化到磁盘中。而与此同时,redo log 的 innodb_flush_log_at_trx_commit 参数设置为1,表示每次事务提交都会执行 fsync。

如果对于Redo log有什么不懂,请移步前一篇文章。

「原创」竟然redolog写入机制都不懂…怎么破?

2022-06-03

一文读懂MySQL的BinLog写入机制|原创


这就产生了一种可能,如果发生mysql服务器了crash,此时redolog已经做持久化,但是binlog还有事务仍保存在page cache中,没有来得及执行fsync。宕机后重启服务,依赖redolog恢复数据,就会出现binlog 长度比真实数据所应该需要的长度短的情况。

面对数据完整但是binlog缺失,这种情况下会出现什么异样呢?开始我苦思不得其解,最终在MySQL5.7的官方文档中找到了答案。

官方文档描述如下:

If the MySQL server discovers at crash recovery that the binary log is shorter than it should have been, it lacks at least one successfully committed InnoDB transaction. This should not happen if sync_binlog=1 and the disk/file system do an actual sync when they are requested to (some do not), so the server prints an error message The binary log *file_name* is shorter than its expected size. In this case, this binary log is not correct and replication should be restarted from a fresh snapshot of the source's data.

如果 MySQL 服务器在崩溃恢复时发现二进制日志比应有的短,则它至少缺少一个成功提交的 InnoDB 事务。如果 sync_binlog=1 并且磁盘/文件系统在请求时进行实际同步(有些则没有),则不会发生这种情况,所以服务器打印一条错误消息日志。在这种情况下,此二进制日志不正确,应从源数据的新快照重新启动复制。

按照官方描述,如果将 sync_binlog设为1不会出现这种情况,如果出现了binlog比预期少,则会在服务器打印一条binlog日志的异常log:The binary log xxx is shorter than its expected size.

所以这种情况需要去人为干预处理,从最新的快照数据源重新复制。

如何使用Bin Log 恢复历史数据

binlog 会记录所有的逻辑操作,并且是采用“追加写”的形式,不会像redo log一样去覆盖日志文件。bin log 里面的数据是可靠的,一定是事务提交后的数据,这就全靠 redo log 两阶段提交来保证。

众所周知,我们可以通过 bin log 恢复任意时间点的数据,如何做到呢?

其实这是有前提的,我们必须要有定期备份全量数据的机制,比如半个月、每周、或者每天。

假定场景:比如今天中午12点有一次误删表数据,需要找回数据,如何做?

  • 首先,找到最近的一次全量备份,比如昨天凌晨1点,那就从这个备份恢复到临时库;
  • 然后,从备份的时间昨天凌晨1点开始,将备份的 binlog 依次取出来重放,直到今天中午12点的数据。

这样临时库就到达了误删数据之前的状态,然后可以把表数据从临时库取出来,按需求恢复到线上正式数据库