问题描述
最近遇到一个问题,主从每隔一段时间就报错tuncate表不存在,然后过一会start slave就能恢复,如下日志:
[ERROR] Slave SQL for channel '': Error 'Table '***.***' doesn't exist' on query. Default database: '***'. Query: 'TRUNCATE TABLE ***', Error_code: 1146
[Warning] Slave: Table '***.***' doesn't exist Error_code: 1146
[ERROR] Error running query, slave SQL thread aborted. Fix the problem, and restart the slave SQL thread with "SLAVE START". We stopped at log 'mysql-bin.***' position ***.
相关时间点,没有其他的报错,且日志级别为3。
当然这里表做了屏蔽,但是错误就是这个。
检查项目
- 表是否有主外键,触发器,结果为单表没有主键和外键无触发器
- 是否有可能修改表的大小写,结果为没有修改过
- 是否开启了MTS,结果为MTS关闭
看起来这个问题就比较奇怪了,关键是过一会start slave又正常了,又可以跑一段时间。
查找原因
然后我们仔细又分析了MySQL的error日志。发现虽然不是在主从报错的时间点,但是偶尔会出现这样的报错
Error in accept: Too many open files in system
很显然这是由于accept返回socket fd的时候由于最大打开文件数量限制导致的,继而查找mysqld的limit ,也就是/proc/mysqlpid/limits
image.png
可见这里没有问题,而且这个库表不多,理论上没有可能超过这个限制,继续查找我们发现系统的fs.file-max设置比较小为65535(sysctl.cnf),这是整个系统的,显然这很小了,因为这个服务器上还有很多其他的应用。
fs.file-max:This file defines a system-wide limit on the number of open files for all processes.
那么如果偶尔超过了限制fs.file-max是否会导致truncate报错Table '.' doesn't exist呢?理论上应该是有其他报错的比如上面的Too many open files in system。
接着在5.7种进行2种truncate 表不存在的测试:
- frm文件不存在的情况下truncate table,报错Table '.' doesn't exist
- frm文件存在,但是数据字典不存在的情况下,truncate table这个表也是报错Table '.' doesn't exist
但是两者的报错栈实际不是一个位置,前者是在open frm文件的时候见检查到错误了报错,后者是在通过innodb数据字典建立table share的时候发现信息不存在报错。那么结合这里的案例,前者的可能性更大,因为frm文件通常打开后会关闭,而不是一个常驻在fd,那么超过最大文件数就会导致打开frm报错,且如果innodb字典有问题再次start slave应该也会报错。那么,当超过最大打开文件数的时候打开frm文件是否会导致truncate出现这种问题呢?
接着就查看打开和检查frm相关的函数如下:
image.png
这里看起来确实没有打印errno和其相关的含义,而是直接return一个错误。
测试和修改
那么看起来就很像了,接着我们进行测试,这里使用如下的方式,
mysql client:
mysql> select version();
+------------+
| version() |
+------------+
| 5.7.40-log |
+------------+
1 row in set (0.00 sec)
mysql> show variables like '%log_error_verbosity%';
+---------------------+-------+
| Variable_name | Value |
+---------------------+-------+
| log_error_verbosity | 3 |
+---------------------+-------+
1 row in set (0.01 sec)
mysql> truncate table io;
Query OK, 0 rows affected (0.00 sec)
mysql> truncate table io;
Query OK, 0 rows affected (0.00 sec)
mysql> truncate table io;
Query OK, 0 rows affected (0.00 sec)
mysql> truncate table io;
Query OK, 0 rows affected (0.00 sec)
change os file-max
vi /etc/sysctl.conf add fs.file-max = 128
sysctl -p
back to mysql client
mysql> truncate table io;
ERROR 1146 (42S02): Table 'mytest.io' doesn't exist
mysql> drop table io;
ERROR 1051 (42S02): Unknown table 'mytest.io'
check mysql error log,no obvious error reported.
这样就能重现这个问题,如果在某一时刻正在做truncate但是这个时候超过file-max的设置,那么就会报这个错,而过后打开文件数关闭一些后再次启动start slave又恢复了,这实际上和主从关系不大。这个地方实际上只要加上errno的打印就好了,应该是报错不明显的问题,至少应该在日志文件打印如下日志:
2023-03-22T07:41:26.995765Z 2 [ERROR] Error in open frm file: ./t2/myt.frm, Too many open files in system
2023-03-22T07:41:36.834439Z 2 [ERROR] Error in open frm file: ./t2/myt.frm, Too many open files in system
但是提交BUG后发现(具体的重现和问题点也可以参见BUG),5.7已经不做这类修复了,只会做crash和安全的修复如下:
https://bugs.mysql.com/bug.php?id=110460
看来今年有大招要放啊。









网友评论