新建连接失败?

 关于链接数据库报错: ERROR 1135 (HY000): 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

看到这个信息会有些迷惑,大概就是要么是内存不够了,要么是遇到 OS 的bug了。但是通过free命令查看我们的内存是足够的,难道真的就是OS 的bug ?不会这么巧吧。

既然说的是内存不够了, 猜测有可能是某个资源确实是越到了瓶颈,那么执行ulimit看看呢:

[mysql@xxxx ~]$ ulimit -a
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 127405
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 204800
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) 1024        ---->  这里似乎有点猫腻
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

到这里可以发现max user processes 这个地方似乎有点小,而我们的DB的连接数恰好达到1024,看起来和这里的限制有很大的关系,而这个限制一般情况下我们是通过 /etc/security/limits.conf这个文件配置的:

[mysql@xxxx ~]$ cat /etc/security/limits.conf |grep -vE '^#|^$'
soft nofile 204800
hard nofile 204800

通过cat 这个文件后发现并没有限制这么小呢,猜想会不会是limit.d目录下还有另外的配置,从而发现这个目录下还有个隐藏的配置文件90-nproc.conf,打开该文件一看果不其然是有个限制。

[mysql@xxxx ~]$ cat /etc/security/limits.d/90-nproc.conf 
# Default limit for number of user's processes to prevent
# accidental fork bombs.
# See rhbz #432903 for reasoning.
*          soft    nproc     1024

通过修改这个值,然后重启DB后,我们就可以创建更多的连接了。

到此问题已经解决了,那么留下几个问题:

  1. 为什么会是90-nproc.conf 这个文件呢?
  2. 对于一个已经启动的进程如果查看这个进程的资源限制呢?
  3. 如果动态的修改这些限制而不重启进程?

    • 关于为什么会是 90-nproc.conf 这个文件的值会生效? 可以查看Linux 源代码 pam_limits.c,定位 pam_sm_open_session 这个函数。它会先读取limits.conf 文件,然后在看limits.d 目录下是否存在 *.conf 的配置文件,如果有这样的配置文件,那么依次读取进来,覆盖 limits.conf 的相关配置。
retval = parse_config_file(pamh, pwd->pw_name, pwd->pw_uid, pwd->pw_gid, ctrl, pl);
if (retval != PAM_SUCCESS || pl->conf_file != NULL)
/* skip reading limits.d if config file explicitely specified */
    goto out;

/* Read subsequent *.conf files, if they exist. */
if (!glob_rc) {
/* Parse the *.conf files. */
for (i = 0; globbuf.gl_pathv[i] != NULL; i++) {
pl->conf_file = globbuf.gl_pathv[i];
retval = parse_config_file(pamh, pwd->pw_name, pwd->pw_uid, pwd->pw_gid, ctrl, pl);
if (retval != PAM_SUCCESS)
        goto out;
        }
    }
  • 如何得知我们的进程启动时候的资源限制如何? 
    可以通过 ps找到这个进程的PID ,然后 cat /proc/$PID/limits 文件得到进程资源限制
[root@Rus_naruto_192-168-3-59 ~]# cat /proc/25675/limits 
Limit                     Soft Limit           Hard Limit           Units     
Max cpu time              unlimited            unlimited            seconds   
Max file size             unlimited            unlimited            bytes     
Max data size             unlimited            unlimited            bytes     
Max stack size            10485760             unlimited            bytes     
Max core file size        unlimited            unlimited            bytes     
Max resident set          unlimited            unlimited            bytes     
Max processes             102400               102400               processes 
Max open files            204800               204800               files     
Max locked memory         65536                65536                bytes     
Max address space         unlimited            unlimited            bytes     
Max file locks            unlimited            unlimited            locks     
Max pending signals       127405               127405               signals   
Max msgqueue size         819200               819200               bytes     
Max nice priority         0                    0                    
Max realtime priority     0                    0                    
Max realtime timeout      unlimited            unlimited            us        
  • 有时候重启进程是个危险的操作,而且不是所以进程都可以随时重启的,那当我们知道这个进程存在资源限制的瓶颈时,怎么通过动态调整这个限制来确保我们的服务正常运行呢? 
    比如通过 /proc/$pid/limits 文件,得知我们的mysql进程存在OS级别的最大连接数限制,像调整一下这个限制可以通过一下步骤来完成:
[root@xxxx ~]# ps -ef|grep mysqld
mysql    24831    1  0 Aug07 ?        00:00:00 /bin/sh /usr/local/mysql/bin/mysqld_safe --defaults-file=/etc/my.cnf --user=mysql
mysql    25675 24831  0 Aug07 ?        00:00:34 /usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf --basedir=/usr/local/mysql --datadir=/data/mysqldata/data --plugin-dir=/usr/local/mysql/lib/plugin --log-error=/data/mysqldata/data/xxxxxx.err --pid-file=/data/mysqldata/data/xxxxx.pid --socket=/data/mysqldata/mysql.sock --port=xxxx
[root@xxxx ~]# echo -n "Max processes=204800:204800" > /proc/25675/limits
[root@xxxx ~]# cat /proc/25675/limits 
Limit                     Soft Limit           Hard Limit           Units     
Max cpu time              unlimited            unlimited            seconds   
Max file size             unlimited            unlimited            bytes     
Max data size             unlimited            unlimited            bytes     
Max stack size            10485760             unlimited            bytes     
Max core file size        unlimited            unlimited            bytes     
Max resident set          unlimited            unlimited            bytes     
Max processes             204800               204800               processes 
Max open files            204800               204800               files     
Max locked memory         65536                65536                bytes     
Max address space         unlimited            unlimited            bytes     
Max file locks            unlimited            unlimited            locks     
Max pending signals       127405               127405               signals   
Max msgqueue size         819200               819200               bytes     
Max nice priority         0                    0                    
Max realtime priority     0                    0                    
Max realtime timeout      unlimited            unlimited            us        

修改了这个值后是否真的有效?如何验证?我们可以通过把这个值该小后,然后不断的增加连接数,当连接数达到我们的限制时,看看是否会报错;然后在动态修改这个值,看看连接能否建立。 
mysql 连接可以简单的写个for循环,然后每个连接sleep 2秒钟 for i inseq 150;do mysql -uxxx -pxxxx -Pxxx -h xxxx -e "select sleep(3)" & done

注: 动态的修改了/proc/$pid/limits 值之后,只是临时生效,如果进程重启这个限制又会重新读取配置文件的值,一劳永逸的办法是修改完成进程运行时的限制,然后在修改配置文件的参数。

posted @   vitoxie.xiepaup  阅读(826)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示