前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【翻译】MySQL 复制:如何处理1236或 MY-013114错误

【翻译】MySQL 复制:如何处理1236或 MY-013114错误

作者头像
保持热爱奔赴山海
修改2024-06-26 10:29:07
1210
修改2024-06-26 10:29:07
举报
文章被收录于专栏:数据库相关数据库相关

复制一直是 MySQL 的核心功能,数十年来一直支持高可用性。但是,您仍可能会遇到让您彻夜难眠的复制错误。最常见且最难处理的错误之一是:“从二进制日志读取数据时出现致命错误 1236 ”。

这篇博文是一次全新的尝试,旨在解释此错误的典型原因以及处理该问题的方法。

错误的 GTID

如今,典型的复制设置使用GTID模式,完整的错误消息如下所示:

代码语言:txt
复制
mysql > show replica status\G
*************************** 1. row ***************************
...
           Replica_IO_Running: No
          Replica_SQL_Running: Yes
...
           Last_IO_Errno: 13114
           Last_IO_Error: Got fatal error 1236 from source when reading data from binary log: 'Cannot replicate because the source purged required binary logs. Replicate the missing transactions from elsewhere, or provision a new replica from backup. Consider increasing the source's binary log expiration period. The GTID set sent by the replica is '00022738-1111-1111-1111-111111111111:1-370', and the missing transactions are '00022739-2222-2222-2222-222222222222:1-2''

因此,我们得到了额外的信息 - errno 13114,尽管它并没有增加太多内容:

代码语言:txt
复制
$ perror 13114
MySQL error code MY-013114 (ER_SERVER_SOURCE_FATAL_ERROR_READING_BINLOG): Got fatal error %d from source when reading data from binary log: '%-.512s'

但是,关于错误原因还有更多详细信息。该消息解释说,源不再具有所需的二进制日志,而 GTID 详细信息则提供了更精确的见解:“ ”。the missing transactions are '00022739-2222-2222-2222-222222222222:1-2'

进一步挖掘,我们可以看到主服务器在gtid_executed中有两个 GTID 集,而副本服务器只有一个:

主库

代码语言:txt
复制
mysql > select @@global.gtid_executed,@@global.gtid_purged\G
*************************** 1. row ***************************
@@global.gtid_executed: 00022738-1111-1111-1111-111111111111:1-370,
00022739-2222-2222-2222-222222222222:1-2
  @@global.gtid_purged: 00022738-1111-1111-1111-111111111111:1-357,
00022739-2222-2222-2222-222222222222:1-2
1 row in set (0.00 sec)

从库

代码语言:txt
复制
mysql > select @@global.gtid_executed,@@global.gtid_purged\G
*************************** 1. row ***************************
@@global.gtid_executed: 00022738-1111-1111-1111-111111111111:1-370
  @@global.gtid_purged: 
1 row in set (0.00 sec)

此外,这个额外的集合被标记为已清除。因此,它无法提供给副本。我们称之为错误事务。 

由于二进制日志已被清除,我们无法调查这两个额外事务的含义,除非源实例二进制日志已备份并且我们可以在历史记录中找到它们。

假设没有办法检查这些内容。在这种情况下,恢复复制的快速解决方案是插入具有相同 GTID 的空事务,然后检查实例是否存在不一致(即使用pt-table-checksum)。为了实现这一点,在副本上,我们可以这样做:

代码语言:txt
复制
mysql > set gtid_next='00022739-2222-2222-2222-222222222222:1';
Query OK, 0 rows affected (0.00 sec)

mysql > begin; commit;
Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.01 sec)

mysql > set gtid_next='00022739-2222-2222-2222-222222222222:2';
Query OK, 0 rows affected (0.00 sec)

mysql > begin; commit;
Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.01 sec)

mysql > set gtid_next=automatic;
Query OK, 0 rows affected (0.00 sec)

mysql > select @@global.gtid_executed,@@global.gtid_purged\G
*************************** 1. row ***************************
@@global.gtid_executed: 00022738-1111-1111-1111-111111111111:1-370,
00022739-2222-2222-2222-222222222222:1-2
  @@global.gtid_purged: 
1 row in set (0.00 sec)

mysql > start replica;
Query OK, 0 rows affected (0.00 sec)

mysql > show replica status\G
*************************** 1. row ***************************
...
           Replica_IO_Running: Yes
          Replica_SQL_Running: Yes

出现这种情况的典型原因是,错误的事务首先出现在副本上,一段时间之后,同一个副本被提升为新的源。

如果所有副本都以只读模式运行,为什么会发生这种情况?好吧,这是我的测试副本的情况:

代码语言:txt
复制
mysql > select @@super_read_only,@@read_only;
+-------------------+-------------+
| @@super_read_only | @@read_only |
+-------------------+-------------+
|                 1 |           1 |
+-------------------+-------------+
1 row in set (0.00 sec)

mysql > flush hosts;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql > show binlog events in 'mysql-bin.000002';
+------------------+-----+----------------+-----------+-------------+-------------------------------------------------------------------+
| Log_name         | Pos | Event_type     | Server_id | End_log_pos | Info                                                              |
+------------------+-----+----------------+-----------+-------------+-------------------------------------------------------------------+
| mysql-bin.000002 |   4 | Format_desc    |     22739 |         126 | Server ver: 8.0.37, Binlog ver: 4                                 |
| mysql-bin.000002 | 126 | Previous_gtids |     22739 |         197 | 00022738-1111-1111-1111-111111111111:1-357                        |
| mysql-bin.000002 | 197 | Gtid           |     22739 |         274 | SET @@SESSION.GTID_NEXT= '00022739-2222-2222-2222-222222222222:1' |
| mysql-bin.000002 | 274 | Query          |     22739 |         351 | flush hosts                                                       |
| mysql-bin.000002 | 351 | Gtid           |     22739 |         428 | SET @@SESSION.GTID_NEXT= '00022739-2222-2222-2222-222222222222:2' |
| mysql-bin.000002 | 428 | Query          |     22739 |         505 | flush hosts                                                       |
+------------------+-----+----------------+-----------+-------------+-------------------------------------------------------------------+
6 rows in set (0.00 sec)

即使启用了super_read_only,也可以使用本地服务器的 UUID 添加 binlog 事件。因此,当稍后此 binlog 轮换并且实例升级时,其他副本将无法同步这些事件!这个问题几年前就被报告过,至今仍然有效:https://bugs.mysql.com/bug.php? id=88720

TIPS: 经在percona 8.0.36-28上测试,这个flush hosts已经不会写binlog了,并且会给出warning警告,建议使用TRUNCATE TABLE performance_schema.host_cache 。

max_allowed_pa​​cket 太小了?

错误 1236 的另一种可能情况是 MySQL 报告超出了允许的最大数据包大小。副本状态的示例错误状态可能如下所示:

代码语言:txt
复制
Last_IO_Errno: 13114
Last_IO_Error: Got fatal error 1236 from source when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on source; the first event '' at 4, the last event read from './mysql-bin.000002' at 7628, the last byte read from './mysql-bin.000002' at 7647.'

副本端对应的错误日志条目为:

代码语言:txt
复制
2024-06-05T14:19:57.956581Z 10 [ERROR] [MY-010557] [Repl] Error reading packet from server for channel '': log event entry exceeded max_allowed_packet; Increase max_allowed_packet on source; the first event '' at 4, the last event read from './mysql-bin.000002' at 7628, the last byte read from './mysql-bin.000002' at 7647. (server_errno=1236)
2024-06-05T14:19:57.956622Z 10 [ERROR] [MY-013114] [Repl] Replica I/O for channel '': Got fatal error 1236 from source when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on source; the first event '' at 4, the last event read from './mysql-bin.000002' at 7628, the last byte read from './mysql-bin.000002' at 7647.', Error_code: MY-013114

现在,上面提供的建议以及增加源上的max_allowed_pa​​cket设置的错误可能完全不合理。即使源已将其设置为最大可能值(即 1GB),也会打印该错误:

代码语言:txt
复制
mysql > select @@max_allowed_packet;
+----------------------+
| @@max_allowed_packet |
+----------------------+
|           1073741824 |
+----------------------+
1 row in set (0.00 sec)

在副本端,默认情况下,最大数据包大小通过replica_max_allowed_pa​​cket设置(也是 1G)。

首先,检查罪魁祸首二进制日志是否确实大于 1 GB 非常重要,因为如果不是,则错误很可能与日志损坏有关,例如,当源突然重新启动并且 sync_binlog<>1 时。无论如何,都应使用 mysqlbinlog工具测试 binlog 文件是否完全可解析。当 binlog 文件未完全写入磁盘(由于突然断电)时,令人惊讶的是,错误消息可能看起来完全相同。

但是,如果 binlog 为 1 GB 或更大且未损坏,则这可能是由于遇到以下错误造成的(至今仍然有效):

https://bugs.mysql.com/bug.php?id=107113 – 当单行足够大时 https://bugs.mysql.com/bug.php?id=55231 – 当 binlog 文件大小超过 4GB 时【这个问题相对容易遇到】

为了避免这种错误变体,应避免非常大的事务,并且sync_binlog = 1应最大限度地降低损坏的风险。

缺少二进制日志文件

导致相同错误的另一个常见原因可能是这样的:

代码语言:txt
复制
Last_IO_Errno: 13114
Last_IO_Error: Got fatal error 1236 from source when reading data from binary log: 'Could not find first log file name in binary log index file'

通常情况下,在非 GTID 模式下以及启用 GTID 模式但禁用auto_position功能时,都可能发生这种情况。因此,复制 IO 线程正在查看二进制日志文件和位置。 

原因很简单——在副本能够下载所需的二进制日志之前,源服务器已经轮换了该日志。因此,例如,在源服务器上,有:

代码语言:txt
复制
mysql > show binary logs;
+------------------+-----------+-----------+
| Log_name         | File_size | Encrypted |
+------------------+-----------+-----------+
| mysql-bin.000005 |      1674 | No        |
+------------------+-----------+-----------+
1 row in set (0.00 sec)

但副本需要前一个文件才能继续:

代码语言:txt
复制
mysql > show replica status\G
*************************** 1. row ***************************
             Replica_IO_State: 
                  Source_Host: 127.0.0.1
                  Source_User: rsandbox
                  Source_Port: 22738
                Connect_Retry: 60
              Source_Log_File: mysql-bin.000004
          Read_Source_Log_Pos: 716
               Relay_Log_File: mysql-relay.000004
                Relay_Log_Pos: 892
        Relay_Source_Log_File: mysql-bin.000004
           Replica_IO_Running: No
          Replica_SQL_Running: Yes
…
               Auto_Position: 0

应实施适当的日志轮换策略以避免此问题。通常,MySQL 管理员使用相对较短的保留设置(通过binlog_expire_logs_seconds ),因为很难预测磁盘空间使用情况,这取决于实际写入量而不是时间。我认为使用 Percona 的扩展和变量binlog_space_limit可以更轻松地更好地利用 binlog 的专用磁盘空间!

磁盘空间不足

源上的磁盘空间问题可能会导致另一种错误,例如:

代码语言:txt
复制
Last_IO_Errno: 1236
Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'binlog truncated in the middle of event; consider out of disk space on master; the first event '' at 4, the last event read from './mysqld-bin.000001' at 12826202, the last byte read from './mysqld-bin.000001' at 12826221.'

很常见的情况是临时空间(tmpdir 或 innodb_tmpdir)安装在单独的小分区上。当该分区已满时,binlog 缓存文件无法写入磁盘,结果 二进制日志条目被损坏,导致副本失败并出现相同的错误。

参考: 

https://bugs.mysql.com/bug.php?id=86991 https://bugs.mysql.com/bug.php?id=72457

其他活动错误导致 binlog 损坏并打印相同错误消息的示例: https://bugs.mysql.com/bug.php ?id= 75746 https://bugs.mysql.com/bug.php?id=75507

概括

一般来说,处理这种复制错误类别可能具有挑战性。在某些情况下,最好从源备份重新创建副本数据。实现此目的的快速方法包括XtraBackup克隆插件

但在其他情况下,您可以尝试使用我们的工具以更轻量级的方式识别和同步表差异,如下所示:https: //www.percona.com/blog/mysql-replication-primer-with-pt-table-checksum-and-pt-table-sync/

本文系外文翻译,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系外文翻译前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 错误的 GTID
  • max_allowed_pa​​cket 太小了?
  • 缺少二进制日志文件
  • 磁盘空间不足
  • 概括
相关产品与服务
云数据库 MySQL
腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档