CentOS环境下MySQL 5.6.38为何出现大量打开的文件描述符?
MySQL打开文件描述符远超配置值的原因与排查方案
这个问题我碰到过好几次,咱们一步步来拆解原因,再梳理排查思路:
先搞清楚:为什么lsof计数和--open-files-limit不一致?
首先你要明确两个核心点:
- 你运行了两个MySQL实例,每个实例的
--open-files-limit=65536,理论上两个实例总共能打开的FD(文件描述符)上限是131072,但你的lsof统计是196410,确实超出了配置值。 lsof的统计范围比你想象的广:它会把所有和mysql进程相关的文件都算进去,不止是.MYI/.MYD这类数据文件,还包括socket连接、日志文件、库文件、临时表文件、管道等。你之前过滤统计的.MYI+.MYD就有15万+,加上其他类型的FD,总和超配置就很正常,但关键是为什么会突破单个实例的65536限制?
可能的根本原因
1. --open-files-limit配置根本没生效
MySQL这个参数的生效依赖系统层面的进程FD限制:
- 即使你在启动参数里写了65536,如果系统给MySQL进程的
nofile(软/硬限制)低于这个值,MySQL会自动把自身的FD上限降到系统允许的最大值,不会报错。 - 比如如果mysql用户的ulimit软限制是1024,那不管你怎么设,MySQL实际的FD上限最多就是1024。
2. MyISAM引擎的“文件缓存”特性拖了后腿
你这里MyISAM的.MYI/.MYD加起来有15万+,这是核心问题之一:
- MyISAM默认会缓存打开的表文件,靠
table_open_cache和table_definition_cache这两个参数控制缓存数量。如果你的数据库里表数量极多,且这两个参数设置得太大,MySQL会一直打开大量表文件不释放,直接耗尽FD。 - 每个MyISAM表对应
.MYI(索引)和.MYD(数据)两个文件,访问一次就会打开这两个文件,缓存满了也不会主动释放(除非设置了table_open_cache_instances做分片,但默认可能没开)。
3. 其他隐藏的FD消耗
- 连接数过高:每个MySQL连接会占用1-3个FD(比如客户端连接的socket、临时文件等),如果实例的并发连接数很高,累加起来也很可观。
- 日志文件堆积:二进制日志、中继日志(主从架构)、慢查询日志如果保留了大量旧文件,每个都会占用FD。
- 磁盘临时表:如果查询需要创建大量磁盘临时表(而不是内存临时表),每个临时表都会占用至少一个FD。
一步步排查调试的具体步骤
第一步:确认MySQL实例的实际FD上限是否生效
- 登录每个MySQL实例,执行:
看返回值是不是65536,如果不是,说明系统层面的限制没放开。SHOW VARIABLES LIKE 'open_files_limit'; - 找到对应实例的进程ID(
ps aux | grep mysql),然后查看进程的实际FD限制:
重点看cat /proc/<mysql_pid>/limitsMax open files的软限制和硬限制,必须至少是65536,否则MySQL的配置无法生效。
第二步:分析单个实例的FD使用明细
不要只看总数,要具体看每个FD是什么:
- 查看单个实例打开的所有文件:
可以分类统计,比如数一下日志文件、socket、临时文件的数量,看这些非数据文件占了多少FD。lsof -p <mysql_pid> - 统计单个实例的MyISAM文件数量:
两个实例的总和应该接近你之前统计的15万+,这能确认MyISAM是不是主要消耗源。lsof -p <pid> | grep -E "\.MY(I|D)$" | wc -l
第三步:检查MyISAM相关参数配置
- 查看表缓存参数:
如果这两个值远大于你实际的表数量(比如你只有10万张表,结果设了20万),就会导致MySQL打开大量不必要的表文件。建议根据实际表数量调整,比如设为表数量的1.2-1.5倍。SHOW VARIABLES LIKE 'table_open_cache'; SHOW VARIABLES LIKE 'table_definition_cache'; - 查看MyISAM专属的文件限制:
这个参数控制同时打开的MyISAM表数量,如果设置得过高,也会加剧FD消耗。SHOW VARIABLES LIKE 'myisam_open_files';
第四步:排查其他FD消耗点
- 查看当前连接数:
如果连接数上千,那每个连接的FD消耗累加起来也不少。SHOW GLOBAL STATUS LIKE 'Threads_connected'; - 检查日志文件情况:
如果二进制日志保留了几十个甚至上百个,每个都会占用FD,可以通过SHOW BINARY LOGS;expire_logs_days设置自动清理。 - 查看临时表使用情况:
如果这个数值增长很快,说明大量查询依赖磁盘临时表,需要优化查询或者调整SHOW GLOBAL STATUS LIKE 'Created_tmp_disk_tables';tmp_table_size/max_heap_table_size参数。
第五步:修复系统层面的FD限制
如果发现进程的FD限制低于65536,需要修改系统配置:
- 编辑
/etc/security/limits.conf,添加:mysql soft nofile 65536 mysql hard nofile 65536 - 重启MySQL服务,然后再次用
/proc/<pid>/limits验证限制是否生效。
内容的提问来源于stack exchange,提问作者shrenik
相关产品推荐
相关产品推荐

