You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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上限是否生效

  1. 登录每个MySQL实例,执行:
    SHOW VARIABLES LIKE 'open_files_limit';
    
    看返回值是不是65536,如果不是,说明系统层面的限制没放开。
  2. 找到对应实例的进程ID(ps aux | grep mysql),然后查看进程的实际FD限制:
    cat /proc/<mysql_pid>/limits
    
    重点看Max open files的软限制和硬限制,必须至少是65536,否则MySQL的配置无法生效。

第二步:分析单个实例的FD使用明细

不要只看总数,要具体看每个FD是什么:

  1. 查看单个实例打开的所有文件:
    lsof -p <mysql_pid>
    
    可以分类统计,比如数一下日志文件、socket、临时文件的数量,看这些非数据文件占了多少FD。
  2. 统计单个实例的MyISAM文件数量:
    lsof -p <pid> | grep -E "\.MY(I|D)$" | wc -l
    
    两个实例的总和应该接近你之前统计的15万+,这能确认MyISAM是不是主要消耗源。

第三步:检查MyISAM相关参数配置

  1. 查看表缓存参数:
    SHOW VARIABLES LIKE 'table_open_cache';
    SHOW VARIABLES LIKE 'table_definition_cache';
    
    如果这两个值远大于你实际的表数量(比如你只有10万张表,结果设了20万),就会导致MySQL打开大量不必要的表文件。建议根据实际表数量调整,比如设为表数量的1.2-1.5倍。
  2. 查看MyISAM专属的文件限制:
    SHOW VARIABLES LIKE 'myisam_open_files';
    
    这个参数控制同时打开的MyISAM表数量,如果设置得过高,也会加剧FD消耗。

第四步:排查其他FD消耗点

  1. 查看当前连接数:
    SHOW GLOBAL STATUS LIKE 'Threads_connected';
    
    如果连接数上千,那每个连接的FD消耗累加起来也不少。
  2. 检查日志文件情况:
    SHOW BINARY LOGS;
    
    如果二进制日志保留了几十个甚至上百个,每个都会占用FD,可以通过expire_logs_days设置自动清理。
  3. 查看临时表使用情况:
    SHOW GLOBAL STATUS LIKE 'Created_tmp_disk_tables';
    
    如果这个数值增长很快,说明大量查询依赖磁盘临时表,需要优化查询或者调整tmp_table_size/max_heap_table_size参数。

第五步:修复系统层面的FD限制

如果发现进程的FD限制低于65536,需要修改系统配置:

  1. 编辑/etc/security/limits.conf,添加:
    mysql soft nofile 65536
    mysql hard nofile 65536
    
  2. 重启MySQL服务,然后再次用/proc/<pid>/limits验证限制是否生效。

内容的提问来源于stack exchange,提问作者shrenik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:07:05