文档结构  
翻译进度:已翻译     翻译赏金:0 元 (?)    ¥ 我要打赏

过去这段时间我和我的同事注意到了越来越多的我们的一些客户碰到了这样的错误信息:

SQLSTATE[HY000] [1135] Can't create a new thread (errno 11); if you are not out of available memory, you can consult the manual for a possible OS-dependent bug.

如果你在 Google 上搜索这个错误的话会看到一些很规范的解决方法 —— 就是提升 MySQL 用户的进程和线程数,一般都是在 /etc/security/limits.conf 增加如下一行配置:

第 1 段(可获 1.14 积分)
mysql   soft   nproc    4096

然后用户退出并重新登录,然后重启 MySQL 服务。如果你的系统是 RHEL/CentOS 5, Ubuntu 或者是 Fedora 9 之前的版本,那么这个解决方案是可行的。但是在 RHEL/CentOS 6 (以及衍生版) 和 Fedora 9 或者更新版本,你会发现这个挑战不起作用。

在 Fedora 9 和 RHEL 6 中引入了一个 Bug 修复,表面上看是为了使系统更加稳定可靠(译者注:Fork bomb 的详细介绍请看维基百科)。关于这个 Bug 的详情可以参考红帽的 Bug 。这次所谓的 Bug 修复引入了一个新的 PAM limits 文件 —— 90-nproc.conf ,该文件位于 /etc/security/limits.d 目录,一般包含如下内容:

# Default limit for number of user's processes to prevent
# accidental fork bombs.
# See rhbz #432903 for reasoning.

*            soft     nproc      1024
第 2 段(可获 1.59 积分)

如果只是看这个配置文件,似乎不存在什么问题,除了有这么一个小问题(就是这个文件会被优先加载)。

90-nproc.conf 文件覆盖了任何你之前在 /etc/security/limits.conf 中设置的进程和线程数量限制!!!

因此就算你已经调整了 /etc/security/limits.conf 中的配置,为 MySQL 用户明确的设定了大于 1024 的 nproc 限制,但是这个限制由于 90-nproc.conf 文件的存在而失效。如果你希望在 RHEL 6+/Fedora 9+ 下提升 mysqld 进程和线程数限制,需要如下几步:

  1. 直接修改 90-nproc.conf 中的 nproc 配置
  2. 完全删除 90-nproc.conf 文件(虽然这个文件可能在下一次 PAM 升级时重新生成)
  3. 在 /etc/security/limits.d 目录中生成一个更高数值的文件 (例如 91-mysql.conf) 然后在这个文件中设置限制 —— 这是我推荐的解决方案。
第 3 段(可获 2.11 积分)

慢着,这有点像午夜电视剧一样,精彩的还在后面!

我们经常忘掉的一件事是,当谈到调整 /etc/security/limits.conf 的 nrpoc/nofile 配置时,甚至是这个新的 90-nproc.conf 文件,这个文件只用来配置 PAM 用户限制模块的行为,也就是说文件的配置调整只对当前登录用户的会话有效。具体的意思是,在系统启动时,由 SysV 的 init 启动脚本所启动的服务实例并不受这些 limits 配置文件的更改所影响。相反的,当你使用登录账号来重启进程时,这些基于 PAM 的 limits 才对服务有效。最终的结果就是一个 “Heisenbug(译者注:术语“Heisenbug”是海森堡不确定性原理的双关语,指生产环境下不经意出现、费尽九牛二虎之力却无法重现的计算机Bug。所以要同时重现基本情形和Bug本身几乎是不可能的。),实际影响 MySQL 实例的 nproc 限制取决于这个服务是什么时候启动的,如果你并非频繁重启 MySQL 服务,那么可能很长时间你都不会察觉到这个问题。

第 4 段(可获 2.05 积分)

为了重现这个问题,我们在一个标准的 CentOS 6.4 服务器上,不对 /etc/security/limits.conf 和 /etc/security/limits.d/90-nproc.conf 文件做任何调整,这是一个缺省的安装。如果我们重启服务器,那么 MySQL 会在系统启动的过程中自动启动,然后检查进程的限制,我们会发现“最大进程数”似乎有足够的空间。如果 max_connections 设置为 1200,那么就算同时有 1200 个并发连接也不会出现“无法创建线程”的错误。

第 5 段(可获 1.31 积分)
( root @ revolution 23 : 53 : 20 ) # cat /proc/`pidof mysqld`/limits | egrep "(processes|files)"
Max processes        22888        22888        processes
Max open files      6000          6000          files

然后当我们需要升级 MySQL 时,在升级过程中并不打算重启机器。我们只是安装了最新的 RPM 并重启 mysqld 服务。或者可能我们碰到一些问题需要重启 MySQL 服务的,具体什么原因这里不关心。但是现在再去看进程和线程数的限制发生了什么变化:

# service mysql restart
Shutting down MySQL ( Percona Server ) . . . SUCCESS !
Starting MySQL ( Percona Server ) . . SUCCESS !
[ ~ ]
# cat /proc/`pidof mysqld`/limits | egrep "(processes|files)"
Max processes        1024        unlimited       processes
Max open files      4206        4206              files
第 6 段(可获 0.96 积分)

现在,一旦服务器的并发连接数超过 1024 的话,我们就会开始碰到“无法创建线程”的错误。如果你是因为升级 MySQL 才重启的话,你可能会错误的(但是合理的)以为这是由于新的更新版本中存在了什么 Bug 导致的,因为在退回以前版本后该错误就不再出现。这个问题最糟糕的地方是它只出现过一次,似乎我们只能通过回滚 MySQL 版本来解决,因为要让 PAM 限制的修改生效的唯一方法是启动一个新的会话(注销然后重新登录系统)。如果我们的 MySQL 负载很重,而且 InnoDB 的缓冲区非常大,重启一次 MySQL 会需要比较长的时间,而且在缓冲区数据填充阶段数据库的性能也是很差的。如果我们可以在不重启 MySQL 服务器就可以修改这些资源限制的话。。。。。。

第 7 段(可获 2.28 积分)

事实证明,我们的确可以做到。在 2.6.32 以及更新版本的内核(RHEL 6 刚好是使用 2.6.32 版本内核)中就有一个便利的方法来快速提升一个运行中进程的资源限制,这个过程是无需重启服务,可以避免之前碰到那些不愉快的事情。我们可以使用 root 权限运行以下命令,需要将 SOFT_LIMIT 和 HARD_LIMIT 替换成你想要的进程/线程数的限制。如果不想限制可以使用 nolimited 值,否则的话就填写数值即可:

echo -n "Max processes=SOFT_LIMIT:HARD_LIMIT" > /proc/`pidof mysqld`/limits
第 8 段(可获 1.3 积分)

那么我们从这篇文字中了解到什么呢?

如果你的系统是 Fedora 9/RHEL 6 或者相应的衍生版,你就会受这个问题影响,可以通过以下三步来完全解决这个问题:

  1. 使用前面提到的 “echo” 技巧来确保所运行的服务器限制是不够的
  2. 编辑 90-nproc.conf (或者创建新文件 91-mysql.conf) 来设置想要的进程和线程数限制,使得服务器重启后设置值仍有效
  3. 确保你先注销后再登录进系统后再重启 MySQL 服务;尽管你已经做了前面两步,你仍需要在重启 mysql 服务时做这一步操作,以确保 mysqld 进程使用所设置的值
第 9 段(可获 2.1 积分)

文章评论