Skip to main content

MySQL Errcode: 24 Too many open files

1 错误详情

MySQL said: Out of resources when opening file '/var/folders/84/b3ghw9z51kg8xlrykdwrvqpw0000gn/T/#sqla0c_e_11f.MAI' (Errcode: 24 "Too many open files")

image-20201015172853944

2 排查问题

可能的原因

  • mysql进程打开的文件数量 超过了系统允许的最大数量

排查步骤

  • 检查mac 系统文件数量限制

    #查看系统句柄配置 命令:
    $ launchctl limit
    #执行的结果:
    zhoujh@zhoujhdeMBP ~ % launchctl limit
    cpu unlimited unlimited
    filesize unlimited unlimited
    data unlimited unlimited
    stack 8388608 67104768
    core 0 unlimited
    rss unlimited unlimited
    memlock unlimited unlimited
    maxproc 2784 4176
    maxfiles 256 unlimited # soft-limit:256 | hard-limit:unlimited

    #或者用命令:
    $ ulimit -a
    #执行的结果:
    zhoujh@zhoujhdeMBP ~ % ulimit -a
    -t: cpu time (seconds) unlimited
    -f: file size (blocks) unlimited
    -d: data seg size (kbytes) unlimited
    -s: stack size (kbytes) 8192
    -c: core file size (blocks) 0
    -v: address space (kbytes) unlimited
    -l: locked-in-memory size (kbytes) unlimited
    -u: processes 2784
    -n: file descriptors 256

    # 查看当前内核和进程能打开的文件描述符限制
    $ sysctl -a | grep files
    zhoujh@zhoujhdeMBP ~ % sysctl -a |grep files
    kern.maxfiles: 49152 # 系统级的限制
    kern.maxfilesperproc: 24576 # 内核级的限
    kern.num_files: 6188

  • 查看当前mysql进程已用的文件句柄

    #利用lsof查看:
    lsof -c mysql
    #执行结果 可以看出打开了很多文件 说明是文件数超出了256 所以报错
    zhoujh@zhoujhdeMBP ~ % lsof -c mysql
    COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
    mysqld 2572 zhoujh cwd DIR 1,7 1152 2319917 /usr/local/var/mysql
    mysqld 2572 zhoujh txt REG 1,7 15747544 23743982 /usr/local/Cellar/mariadb@10.3/10.3.23/bin/mysqld
    mysqld 2572 zhoujh txt REG 1,7 490556 22873844 /usr/local/Cellar/openssl@1.1/1.1.1g/lib/libssl.1.1.dylib
    mysqld 2572 zhoujh txt REG 1,7 2262368 22873850 /usr/local/Cellar/openssl@1.1/1.1.1g/lib/libcrypto.1.1.dylib
    mysqld 2572 zhoujh txt REG 1,7 24576 33942989 /usr/local/var/mysql/tc.log
    mysqld 2572 zhoujh txt REG 1,7 28512 33930114 /Library/Preferences/Logging/.plist-cache.Ire7fQDK
    mysqld 2572 zhoujh txt REG 1,7 1568368 1152921500312826105 /usr/lib/dyld
    mysqld 2572 zhoujh 0r CHR 3,2 0t0 310 /dev/null
    mysqld 2572 zhoujh 1w REG 1,7 46425 25857787 /usr/local/var/mysql/zhoujhdeMBP.RT-AX88U.err
    mysqld 2572 zhoujh 2w REG 1,7 46425 25857787 /usr/local/var/mysql/zhoujhdeMBP.RT-AX88U.err
    mysqld 2572 zhoujh 3u REG 1,7 52 2319921 /usr/local/var/mysql/aria_log_control
    mysqld 2572 zhoujh 4r DIR 1,7 1152 2319917 /usr/local/var/mysql
    mysqld 2572 zhoujh 5u REG 1,7 32768 2320101 /usr/local/var/mysql/aria_log.00000001
    mysqld 2572 zhoujh 6u REG 1,7 817889280 2319918 /usr/local/var/mysql/ibdata1
    mysqld 2572 zhoujh 7u REG 1,7 0 33942984 /private/var/folders/84/b3ghw9z51kg8xlrykdwrvqpw0000gn/T/ibmCUk7P
    mysqld 2572 zhoujh 8u REG 1,7 0 33942985 /private/var/folders/84/b3ghw9z51kg8xlrykdwrvqpw0000gn/T/ibJ9Durq
    mysqld 2572 zhoujh 9u REG 1,7 0 33942986 /private/var/folders/84/b3ghw9z51kg8xlrykdwrvqpw0000gn/T/ibrNIlka
    mysqld 2572 zhoujh 10u REG 1,7 50331648 2320927 /usr/local/var/mysql/ib_logfile0
    mysqld 2572 zhoujh 11u REG 1,7 50331648 2320928 /usr/local/var/mysql/ib_logfile1
    mysqld 2572 zhoujh 12u REG 1,7 12582912 33942988 /usr/local/var/mysql/ibtmp1
    mysqld 2572 zhoujh 13u REG 1,7 0 33942987 /private/var/folders/84/b3ghw9z51kg8xlrykdwrvqpw0000gn/T/ibBuLfH8
    mysqld 2572 zhoujh 14u REG 1,7 180224 2320130 /usr/local/var/mysql/mysql/innodb_table_stats.ibd
    mysqld 2572 zhoujh 15u REG 1,7 24576 33942989 /usr/local/var/mysql/tc.log
    mysqld 2572 zhoujh 16u REG 1,7 37748736 33908957 /usr/local/var/mysql/sdb/transferto_orders.ibd
    mysqld 2572 zhoujh 17u unix 0xaa2db352875e520b 0t0 /tmp/mysql.sock
    mysqld 2572 zhoujh 18u REG 1,7 98304 19054104 /usr/local/var/mysql/spin@002dcopy/alarms.ibd
    mysqld 2572 zhoujh 19u REG 1,7 2646605824 33908961 /usr/local/var/mysql/sdb/user_account_logs.ibd
    mysqld 2572 zhoujh 20u REG 1,7 113246208 33909660 /usr/local/var/mysql/sdb/user_address_details.ibd
    mysqld 2572 zhoujh 21u REG 1,7 1908408320 33909679 /usr/local/var/mysql/sdb/user_credits_account_logs.ibd
    mysqld 2572 zhoujh 22u systm 0xaa2db352a9d9aafb 0t0 [ctl com.apple.netsrc id 7 unit 41]
    mysqld 2572 zhoujh 23u REG 1,7 54525952 33909994 /usr/local/var/mysql/sdb/user_credits_account_reports.ibd
    mysqld 2572 zhoujh 24u REG 1,7 310378496 33910006 /usr/local/var/mysql/sdb/user_credits_accounts.ibd
    mysqld 2572 zhoujh 25u REG 1,7 98304 33910068 /usr/local/var/mysql/sdb/user_departments.ibd
    mysqld 2572 zhoujh 26u REG 1,7 14680064 33910070 /usr/local/var/mysql/sdb/user_discounts.ibd
    mysqld 2572 zhoujh 27u REG 1,7 15728640 33910072 /usr/local/var/mysql/sdb/user_favorites.ibd
    mysqld 2572 zhoujh 28u REG 1,7 131072 33910075 /usr/local/var/mysql/sdb/user_groups.ibd
    mysqld 2572 zhoujh 29u REG 1,7 393216 33910077 /usr/local/var/mysql/sdb/user_pay_limits.ibd
    mysqld 2572 zhoujh 30u REG 1,7 98304 33910082 /usr/local/var/mysql/sdb/user_phone_infos.ibd
    mysqld 2572 zhoujh 31u REG 1,7 968884224 33910084 /usr/local/var/mysql/sdb/user_point_logs.ibd
    mysqld 2572 zhoujh 32u REG 1,7 1493172224 33910307 /usr/local/var/mysql/sdb/user_verifications.ibd
    mysqld 2572 zhoujh 33u REG 1,7 2113929216 33910684 /usr/local/var/mysql/sdb/users.ibd
    mysqld 2572 zhoujh 34u REG 1,7 114688 33911079 /usr/local/var/mysql/sdb/voucher_items.ibd

  • 可以看出mysql打开的文件句柄数量很多,应该是超出了最大256的限制 所以报错

3 解决办法

1 通过launchctl修复

# Usage: launchctl limit \[<limit-name> \[<both-limits> | <soft-limit> <hard-limit>\]
# 查看文件描述符限制
launchctl limit maxfiles
maxfiles 256 unlimited

# 修改软限制为512 系统重启失效
sudo launchctl limit maxfiles 512 unlimited

# 可将launchctl子命令写入/etc/launchd.conf中
# 在launchd启动时 会执行该文件中的命令
limit maxfiles 512 unlimited

2 通过添加plist文件修复(推荐)

  1. 新建文件 Library/LaunchDaemons/limit.maxfiles.plist 文件,写入

     <?xml version="1.0" encoding="UTF-8"?>  
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
    "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
    <key>Label</key>
    <string>limit.maxfiles</string>
    <key>ProgramArguments</key>
    <array>
    <string>launchctl</string>
    <string>limit</string>
    <string>maxfiles</string>
    <string>64000</string>
    <string>524288</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>ServiceIPC</key>
    <false/>
    </dict>
    </plist>
  2. 修改文件权限

     sudo chown root:wheel /Library/LaunchDaemons/limit.maxfiles.plist
    sudo chmod 644 /Library/LaunchDaemons/limit.maxfiles.plist
  3. 加载 plist 文件

    (或重启系统后生效 launchd 在启动时会自动加载该目录的 plist)

     sudo launchctl load -w /Library/LaunchDaemons/limit.maxfiles.plist
  4. 确认更改后的限制

     launchctl limit maxfiles

4 参考1

Mac OS X下的资源限制和修改

在 Mac OS X 下,有如下三个命令与系统资源有关。

launchctl

launchctl 管理 OS X 的启动脚本,控制启动计算机时需要开启的服务 (通过后台进程 launchd)。也可以设置定时执行特定任务的脚本,类似 Linux cron。

例如,开机时自动启动 Apache 服务器:

$ sudo launchctl load -w /System/Library/LaunchDaemons/org.apache.httpd.plist

关于 launchctl 的 plist 格式和用法参考:

  1. launchctl man page
  2. launchd plist man page
  3. mac-os-x-launchd-is-cool
  4. creating launchd jobs

简单来说,plist 文件用类似 XML 格式定义了一个命令 (及启动参数) 和该命令的执行方式(定时执行,系统启动执行,用户登录执行等)。我们这里不着重讨论,我们关心 launchctl 中如何查看 / 更改系统资源限制。

  • launchctl 查看|更改系统资源限制

# Usage: launchctl limit \[<limit-name> \[<both-limits> | <soft-limit> <hard-limit>\]
# 查看文件描述符限制
launchctl limit maxfiles
maxfiles 256 unlimited

# 修改软限制为512 系统重启失效
sudo launchctl limit maxfiles 512 unlimited

# 可将launchctl子命令写入/etc/launchd.conf中
# 在launchd启动时 会执行该文件中的命令
limit maxfiles 512 unlimited
  • 通过写入plist文件 更改系统资源限制

通过将更改命令写入 plist 文件,并在启动时执行,也可永久更改资源限制:

  1. 新建文件 Library/LaunchDaemons/limit.maxfiles.plist 文件,写入

     <?xml version="1.0" encoding="UTF-8"?>  
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
    "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
    <key>Label</key>
    <string>limit.maxfiles</string>
    <key>ProgramArguments</key>
    <array>
    <string>launchctl</string>
    <string>limit</string>
    <string>maxfiles</string>
    <string>64000</string>
    <string>524288</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>ServiceIPC</key>
    <false/>
    </dict>
    </plist>
  2. 修改文件权限

     sudo chown root:wheel /Library/LaunchDaemons/limit.maxfiles.plist
    sudo chmod 644 /Library/LaunchDaemons/limit.maxfiles.plist
  3. 加载 plist 文件

    (或重启系统后生效 launchd 在启动时会自动加载该目录的 plist)

     sudo launchctl load -w /Library/LaunchDaemons/limit.maxfiles.plist
  4. 确认更改后的限制

     launchctl limit maxfiles

sysctl

大多数类 Unix 系统都通过 (Linux/*BSD/OS X) 都提供该命令来更改资源限制和内核配置:

# 查看当前内核和进程能打开的文件描述符限制
$ sysctl -A | grep kern.maxfiles
kern.maxfiles: 12288 # 系统级的限制
kern.maxfilesperproc: 10240 # 内核级的限制

# 通过sysctl命令热更改 系统重启后失效
$ sysctl -w kern.maxfilesperproc=20480

# 通过配置文件永久更改 重启生效
# 在/etc/sysctl.conf中写入
kern.maxfiles=20480 kern.maxfilesperproc=24576

ulimit

ulimit 是 shell 的内置命令,用于查看 / 更改当前 shell 及其创建的子进程的资源限制。使用比较简单:

\# 查看当前shell(及其子进程)的所有限制
ulimit -a
# 改变进程能打开的最大文件描述符数软限制 当shell关闭后失效
# 将其写入对应shell的startup文件(如~/.bashrc, ~/.zshrc),可保留更改
ulimit -S -n 1024


区别联系

这三个命令的关系在 Mac OS X 各版本中尤其混乱,先说说本人的一些试验 (Mac OS X 10.10.3):

  • 在默认配置下 (不配置 plist 和 sysctl.conf),launchctl 的 maxfiles 默认值为 (256, unlimited),sysctl 的 maxfiles 默认值为 (12288, 10240),而 ulimit -n 得到的值为 4864。

  • 当不定义 plist 而定义 sysctl.conf,那么重启后 launchctl 和 ulimit 看到的上限仍为默认值,sysctl 看到的上限与 sysctl.conf 定义的一致。

  • 当同时在/etc/sysctl.conf/Library/LaunchDaemons/limit.maxfiles.plist中定义 maxfiles 时,plist 文件中的配置会覆盖 sysctl.conf 中的配置。如果通过系统重启应用 plist,三个命令看到的上限均为 plist 配置。如果通过 launchctl load 加载 plist,则会同步影响 sysctl 看到的上限,而不会影响 shell 下的 ulimit 上限。

  • 如果通过 launchctl 配置的软上限和硬上限分别为 S 和 H(非 unlimited),那么通过 launchctl 应用配置后最终得到软上限和硬上限都为 S。如果设定的上限为 S 和 unlimited,实际上应用的参数为 S 和 10240(sysctl 中 kern.maxfilesperproc 默认值),当 S > 10240 时,会设置失败,S < 10240 时,会得到 (S, 10240)

  • ulimit -H -n 1000 降低硬上限无需 Root 权限,升高则需要

趁着头大,还可以看看这几篇文章:

  1. open files limit does not work as before in osx yosemite
  2. maximum files in mac os x
  3. how to persist ulimit settings in osx mavericks
  4. open files limit in max os x
  5. increase the maximum number of open file descriptors in snow leopard

网上对 Mac OS X 各版本的解决方案各不相同,并且对这三个命令 (特别是 launchctl 和 sysctl) 在资源限制上的联系与区别也没有清晰的解释。

按照我的理解和折腾出来的经验:

  1. ulimit 只影响当前 Shell 下的进程,并且受限于 kern.maxfilesperproc
  2. 如果配置了 plist,那么重启后,ulimit 和 sysctl 均会继承 plist 中的值
  3. 热修改 sysctl 上限值不会影响 launchctl,而反之,launchctl 会影响 sysctl 上限值

综上,在 Mac OS X 10.10(我的版本,没试过之前的) 之后,使用 plist 是最合理的方案 (但 launchctl 貌似只能设定一样的软限制和硬限制,如果将硬限制设为 ulimited,则会使用 kern.maxfilesperproc 值)。在系统重启后,kern.maxfilesperproc 和 ulimit -n 都会继承 plist maxfiles 的值。

5 参考2

launchctl 参考

launchctl 管理 MacOS 的启动脚本,控制启动计算机时需要开启的服务。也可以设置定时执行特定任务的脚本,就像Linux cron一样。

常用命令

# 1.显示当前的启动脚本
launchctl list

# 2.开机时自动启动Apache服务器
sudo launchctl load -w /System/Library/LaunchDaemons/org.apache.httpd.plist

# 3.设置开机启动并立即启动改服务
launchctl load -w **.pist

# 4. 设置开机启动但不立即启动服务
launchctl load **.pist

# 5. 停止正在运行的启动脚本
sudo launchctl unload [path/to/script]

# 6. 再加上-w选项即可去除开机启动
sudo launchctl unload -w [path/to/script]

执行定时脚本|设置开机启动步骤

# 1.写执行脚本 (通过 brew 安装软件 brew 会为我们自动生成。)
# 2. 去对应的目录下建立plist文件
# 3. 加载服务
# 3.1 cd 进入指定 plist 文件目录
# 3.2 加载和取消加载
# 加载
launchctl load *.plist
# 取消 加载
launchctl unload *.plist
#3.3 查看服务
launchctl list

ulimit | sysctl | lauchctl 区别

三者介绍

  • ulimit

    • This is a builtin command of your shell (bash/ash/zsh etc). It temporarily sets process limits for the current shell. This is not OS X specific by the way.
    • 这是一种嵌入shell的命令,只能临时设置当前shell(也就是当前进程)的参数。unix-like OS都有。
  • sysctl

    • Most unix-like (Linux/*BSD/OS X) systems set global limit/kernel settings via the sysctlcommand//etc/sysctl.conf config file. But see below for the OS X caveat.
    • 大部分unix-like OS都采用这个来设置全局的内核限制,sysctl为命令,/etc/sysctl.conf为配置文件。不过请看下面的launchctl
  • launchctl

    • Seems like OS X does not honor sysctl.conf on startup anymore ( https://discussions.apple.com/thread/2781309?start=0&tstart=0). So on OS X, it looks like sysctlis merely usable for temporarily setting the global limits.
    • 看起来OS X在启动的时候不在尊重sysctl.conf的配置(附链接)。所以在OS X上,sysctl仅仅能够临时设置全局限制。

说明

ulimit

  • ulimit
    • ulimit仅作用于当前shell,也就是当前进程
    • ulimit -n 的设置理所当然的也是临时设置
    • ulimit下的open files才是真正影响当前进程打开文件的配置
    • 修改open files的上限不能超过 kern.maxfilesperproc设置(参见下面sysctl参数)
  • launchctl
    • launchctl为macOS特有配置
    • $ launchctl limit maxfiles
      • maxfiles 1024 10240
    • 可将launchctl子命令写入/etc/launchd.conf中
    • 有软配和硬配。软配为每个进程可自由控制,但不能超过硬配;硬配为只有root才能修改,目的就是给软配划定上限。
    • 修改该项配置会直接同时设置sysctl的 kern.maxfilesperproc参数
    • 热修改sysctl上限值不会影响launchctl,而反之,launchctl会影响sysctl上限值
  • sysctl
    • sysctl为系统控制
    • $ sysctl -a|grep files
      • kern.maxfiles: 10240
      • kern.maxfilesperproc: 512
    • 由以上两个配置项决定,第一个为内核总文件上限,第二个为每个进程允许的上限

系统的资源是有限的 (如 CPU,内存,内核所能打开的最大文件数等),资源限制对针对进程能使用的系统资源设定上限。防止恶意进程无限制地占用系统资源。

资源限制分为两种,硬限制 (Hard Limit) 和软限制(Soft Limit),软限制作用于实际进程并且可以修改,但不能超过硬限制,硬限制只有 Root 权限才能修改。