我正在使用mysqlbinlog --stop-never --read-from-remote-server
标志将我的二进制日志文件复制到辅助服务器。如果主数据库服务器受到威胁,我想在远程服务器上重放二进制日志,但我在处理“当前”二进制日志时遇到了问题。
使用mysqlbinlog
将其转换为 SQL 时,我总是会收到如下错误:
错误:Log_event::read_log_event() 中的错误:'读取错误',data_len:2682,事件_type:2 错误:无法读取偏移量 4426095 处的条目:日志格式错误或读取错误
我假设此问题与此 binlog 文件尚未在主数据库服务器上关闭或刷新有关。flush logs
在主数据库服务器上运行后,我的文件没有这个问题。
所以,我的问题是:如果主数据库服务器受到威胁并且我无法运行flush logs
,只能访问已复制到远程服务器的二进制日志文件。如何清理、关闭或刷新在数据库中断事件时打开的二进制日志?
刷新 master 上的日志几乎可以偶然解决您的问题。当主日志文件轮转时,
mysqlbinlog
关闭当前文件并打开下一个文件,这会隐式刷新所有缓冲数据。您不能像
mysqlbinlog
实际服务器那样触发按需刷新其日志,但我找到了一种触发它以将文件保持在始终刷新状态的方法,这似乎是改善结果的可行方法.当 Oracle 将
--raw
选项添加到 时mysqlbinlog
,它与--read-from-remote-server
和--stop-never
可用于捕获 master 的 binlog 的实时备份,他们至少忽略了一些看似显而易见的事情。鉴于该功能的记录目的......
...这似乎是一个明显的疏忽,
mysqlbinlog
每次写入后都不会费心刷新其输出流。也许这就是为什么他们将“现场”放在引号中的原因。:)
我的测试证实
mysqlbinlog
,在交付时,它会在其缓冲区中留下可能已被刷新的悬空数据,但这似乎是一个相当容易解决的问题。例如,
mysql-5.6.27/client/mysqlbinlog.cc
第 2477 行的这个小改动:此更改导致通过
mysqlbinlog
不断匹配返回的大小创建的文件的大小SHOW MASTER STATUS;
,而不是总是看起来落后几个字节。我一直都知道这种轻微的滞后,但从未深入研究过。当然,持续刷新缓冲区是有代价的,但这似乎是“备份”目的不可或缺的必要条件。请注意,这只是用户空间缓冲区的刷新,它不是一个fsync()
或类似的,所以我认为它在性能方面不会有什么不同......无论如何,它不会影响主人。使用逻辑
||
是因为my_fwrite()
在成功时返回 0,所以我们短路并且在失败时不尝试刷新,如果任一操作失败我们会出错,因为fflush()
成功时也会返回 0。此更改应该会显着改善您看到的行为。
当然,你仍然有可能得到一个不完整的日志,因为它仍然是一个打开的文件并且仍在被写入......但是当在低流量环境中测试这个修复时,热复制文件会导致对我来说可用的 binlog——而在其他情况下,在相同的环境中,使用 stock 二进制文件时文件末尾几乎总是不完整的。
对于不同的版本(仅限 5.6+——此功能在 5.6 之前根本没有实现),源代码中的行可能不同,但仍然很容易发现,并且与此处指示的行号不远。
Facebook 的 MySQL 5.6 分支具有类似但更复杂的修复程序,以及一个新选项,该选项
--flush-result-file
使刷新不太激进,但可配置。然而,我发现以目前的形式编译它不必要地困难,所以我开发了上面的小补丁。只要您正在修补 mysqlbinlog,您可能会发现另一个小调整对于解决另一个设计疏忽很有用。官方发行版中的
mysqlbinlog
实用程序缺乏对--compress
命令行选项的支持(尽管 Percona 明智地将其添加到他们的选项中。)但是,启用压缩也很容易。我刚刚针对这个问题想出了上面的修复方法,但我已经使用下面的修复方法很长一段时间了,因为——再一次——在我看来,它一直是一个明显缺失的功能。
从 5.6.27 源码来看,它看起来是这样的:
此更改不启用对传递
--compress
命令行选项的支持——它只是在与主服务器的连接上打开客户端压缩协议,对于支持它的任何主服务器(它们基本上都这样做),从而减少网络量传输日志所需的带宽——有时为 10:1 或更高,具体取决于特定的有效负载。它不会更改生成文件的内容——它只是启用对网络传输数据的压缩。slave_compressed_protocol
在网络上,从主服务器的角度来看,这与在从服务器上启用具有相同的效果。(文档含糊不清,但此设置对主服务器没有影响,除非主服务器也是另一台服务器的从服务器。)