我们正在使用带有一个主设备和一个从设备的 MySQL DB。我们已经使用这个设置几个月了。从站同步今天停止,我们得到的错误是:
Last_IO_Errno: 1236
Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master'
Last_SQL_Errno: 1594
Last_SQL_Error: Relay log read failure: Could not parse relay log event entry. The possible reasons are: the master's binary log is corrupted (you can check this by running 'mysqlbinlog' on the binary log), the slave's relay log is corrupted (you can check this by running 'mysqlbinlog' on the relay log), a network problem, or a bug in the master's or slave's MySQL code. If you want to check the master's binary log or slave's relay log, you will be able to know their names by issuing 'SHOW SLAVE STATUS' on this slave.
我们尝试重新启动从属的 mysql 服务,并在没有帮助的情况下启动和停止从属复制。经过进一步调查,我们发现查询量特别大存在问题。在主服务器的错误日志中,我们得到如下错误日志:
[ERROR] Error in Log_event::read_log_event(): 'Event too big', data_len: 1936941420, event_type: 109
我们已确定导致此问题的查询。我们可以忽略该查询的更新。此错误会不断记录在 mysql 错误日志中。
问题是,在那个特定的日志位置之后,主服务器无法从中继日志中读取。我们只想从主服务器的二进制日志中删除那个特定的中继日志号。我们如何从二进制日志文件中删除特定的中继日志条目?是的,由于这个原因,我们的应用程序处于危急状态。:(
想到的一个可能的解决方案是将 master_log_position 设置为下一个:
或者只使用sql_slave_skip_counter = 1。如果这不起作用,您可以尝试解析 binlog(如果 mysqlbinlog 能够解析它......):
编辑脚本并删除直到并包括长语句的部分。在slave上手动运行修改后的脚本,将master_logfile设置为下一个binlog:
您也可以检查,以防万一,如果 master 和 slave 使用相同的 *max_allowed_packet*。
很久以前,由于 SAN 的一些严重问题,我们在 master 上有一个损坏的二进制日志,它做了一些 SAN 真正真正不应该做的事情,比如写入零块而不是实际数据,这是我们后来了解到的。
我的解决方案是通过将奴隶上的 master_log_position 设置为主 bin 日志中的下一个有效语句来跳过损坏的块/日志条目,并希望跳过/丢失的语句不会破坏逻辑级别上的任何内容,即从属抱怨重复之后的关键之类的东西。
在这种情况下,问题是在二进制日志中找到下一个有效位置。
因此,我查看了 mysql 的开发人员文档以了解二进制日志的内部结构,并使用十六进制编辑器查看了我损坏的主二进制日志。在从站上可以看到最后一个有效条目的位置,从那里开始。
由于二进制日志包含几乎以文本形式记录的 sql 语句,因此我能够识别下一个 INSERT / UPDATE / something 语句的位置。在实际语句之前减去二进制日志头字段的大小(请参阅开发人员文档),将 master_log_position 设置为该值并重新启动从站。如果你击中了一个有效的位置,它会继续,否则它会抱怨。您也可以使用 mysqlbinlog 将语句转储到该位置。
这对胆小的人来说没什么,我不能给你更详细的一步一步的指导。
如果您的二进制日志确实损坏了(在我看来,date_len 是从 bin 日志中的一个字段中提取的,这不是一个有效值,这就是从站抱怨的原因),本书的解决方案是重建通过将新的备份从主服务器恢复到从服务器(等等,例如设置新的从服务器),因为您以后无法判断数据是否真的与您的主服务器同步,因为您跳过了一些语句。
此错误通常是由硬件故障或错误引起的,该错误非常模糊,以至于十多年来都没有被发现。肯定会修复它而没有任何异常风险的最佳解决方案是完全重新初始化复制。您可以通过使用 或 来执行此操作而无需停机或
xtrabackup
锁定mysqldump --single-transaction
。首先,您需要查看
SHOW SLAVE STATUS\G
输出。在那里你可以找到你的 mysqlbinlog。如果您有 TB 的数据,复制可能会很昂贵,因此可能有一种方法可以在不完全重建从属服务器的情况下恢复复制。您可以在主服务器上使用 mysqlbinlog 来识别事务的开始位置并查找附近的位置(您的
Exec_Master_Log_Pos
)。很有可能列出的位置实际上有错误,并且 binlog 中没有事务从该位置开始。您也很可能会发现这些交易之间的坐标距离远不及您的max_allowed_packet
价值。如果是这种情况,您可以将从属上的复制坐标重置为最后一个事务 mysqlbinlog 列表,该列表在从属认为它所在的位置之前。您可以在这篇MariaDB 和 MySQL 故障排除文章中找到有关具体操作的更多详细信息。
在大多数情况下,如果有一个主键并且我们正在使用
binlog_format=ROW
,复制将在缺失的行(在删除时)或重复键(在插入时)上中断,我们可以跳过事务并恢复。是的,将 master_log_position 设置为下一个有效语句是可行的方法。
找到正确日志位置的一个好方法是在 mysqlbinlog 中使用 --hexdump 选项,如下所示:
您可以看到语句在块的中途被破坏,下一条记录从 0x6202000 开始(31830156 是小端格式的下一个时间戳)。0x6202000 是十进制的 102768640。
所以解决方法是: