Mysql報Too many connections,不要亂用ulimit了,看看如何正確修改進程的最大文件數


背景

今天在學習mysql時,看到一個案例,大體來說,就是客戶端報Too many connections。但是,客戶端的連接池,限制為了200,兩個客戶端java進程,那也才400,然后mysql配置了800的連接。

mysql是在my.cnf中配置了:


[root@localhost CAD_OneKeyDeploy]# vim /etc/my.cnf

[mysqld]
datadir = /var/lib/mysql
socket = /var/lib/mysql/mysql.sock
max_connections=800
symbolic-links = 0

這個不應該吧,我最多建立400個連接,數據庫設置了最大連接為800,結果就報:Too many connections。

然后在mysql上執行:

SHOW VARIABLES LIKE 'max_connections'

發現結果是200左右,說明設置了沒生效啊。

結果在mysql的啟動日志:

Could not increase number of max_open_files to more than mysqld (request: 65535)
Changed limits: max_connections: 214 (requested 2000)

然后案例中的博主就去修改了:

ulimit -HSn 65535
vim /etc/security/limits.conf

我跟着操作了一把,結果,發現並不是那么回事。

也就是說,我照着做了,沒生效,那,到底怎么回事?

這里,我總結了一些資料,大家先看看,然后最后我會說明,怎么去正確設置一個進程的最大文件數量。

進程的最大文件數量,受到多方面影響:

登錄shell后,手動啟動的進程

影響因素包括:

  • 操作系統整體的、所有進程可以打開的文件數量總和(由/proc/sys/fs/file-max控制);
  • 該shell用戶,可以打開的最大文件數量(由 /etc/security/limits.conf控制);
  • 進程本身的最大文件數量限制(可以通過os提高的api控制,如setrlimit)

開機自動啟動的進程

影響因素包括:

  • 操作系統整體的、所有進程可以打開的文件數量總和(由/proc/sys/fs/file-max控制);
  • 如果由systemd方式啟動,則systemd的service文件中可以進行限制。

受知識所限,目前知道的就上面這些,shell據我所知,還分log和no-log shell,不是很懂,先跳過。

查看某個已運行進程的資源限制

在經過一番修改后,想知道修改是否生效時,可以通過如下方式:

先把進程運行起來,查看其最終生效的資源限制的辦法,就是如下:

[root@localhost ~]# cat /proc/6660/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            8388608              unlimited            bytes     
Max core file size        0                    unlimited            bytes     
Max resident set          unlimited            unlimited            bytes     
Max processes             3795                 3795                 processes 
-----------------------------如下
Max open files            5000                 5000                 files     
Max locked memory         65536                65536                bytes     
Max address space         unlimited            unlimited            bytes     
Max file locks            unlimited            unlimited            locks     
Max pending signals       3795                 3795                 signals   
Max msgqueue size         819200               819200               bytes     
Max nice priority         0                    0                    
Max realtime priority     0                    0                    
Max realtime timeout      unlimited            unlimited            us        

os級別,如何查看與設置

查看可通過如下命令:

[root@localhost ~]# cat  /proc/sys/fs/file-max
95086

這里其實就是查看了/proc下的某個文件,那么這個文件的意思是啥呢?查看幫助:

man proc
...
/proc/sys/fs/file-max

This file defines a system-wide limit on the number of open files for all processes.  (See also setrlimit(2), which can be used by a process to set the per-process limit, RLIMIT_NOFILE, on the number of files  it  may open.)  If you get lots of error messages in the kernel log about running out of file handles (look for "VFS: file-max limit <number> reached"), try increasing this value:

echo 100000 > /proc/sys/fs/file-max

The kernel constant NR_OPEN imposes an upper limit on the value that may be placed in file-max.

If you increase /proc/sys/fs/file-max, be sure to increase /proc/sys/fs/inode-max to 3-4 times the new value of /proc/sys/fs/file-max, or you will run out of inodes.

Privileged processes (CAP_SYS_ADMIN) can override the file-max limit.

簡單翻譯下,該文件定義了一個操作系統級別的,最大可以打開的文件數量限制(針對所有進程加起來)。

針對一個進程,去設置針對每個進程的最大可打開文件數量的限制,可以查看setrlimit中的RLIMIT_NOFILE

如果要修改,則:

echo 100000 > /proc/sys/fs/file-max

修改后,重啟os生效。

coding時,調用api進行資源限制

可通過man查看:

man setrlimit

GETRLIMIT(2)                                                                                           Linux Programmer's Manual                                                                                           GETRLIMIT(2)

NAME
       getrlimit, setrlimit, prlimit - get/set resource limits

SYNOPSIS
       #include <sys/time.h>
       #include <sys/resource.h>

       int getrlimit(int resource, struct rlimit *rlim);
       int setrlimit(int resource, const struct rlimit *rlim);

		The getrlimit() and setrlimit() system calls get and set resource limits respectively.  		Each resource has an associated soft and hard limit, as defined by the rlimit structure:

           struct rlimit {
               rlim_t rlim_cur;  /* Soft limit */
               rlim_t rlim_max;  /* Hard limit (ceiling for rlim_cur) */
           };

注意,這個都是針對當前進程的,即,如果你用c語言編程,基本就會直接和這個打交道。

RLIMIT_NPROC

The maximum number of processes (or, more precisely on Linux, threads) that can be created for the real user ID of the calling process.  Upon encountering this limit, fork(2) fails with the error EAGAIN.

我在redis的源碼中,見過相關的api調用。

針對單個用戶/用戶組的資源限制(修改后,重新登錄shell后,啟動的進程生效)

查看:

vim /etc/security/limits.conf

如果要修改,則在上述文件中,增加如下兩行,前面的通配符,表示匹配任意用戶和group

* soft nofile 65535
* hard nofile 65535

這里把任意用戶的最大文件數量,改為了65535.

另外,我這里看了下elastic search的官網,因為我記得它就是比較繁瑣,需要改這些,

https://www.elastic.co/guide/en/elasticsearch/reference/master/setting-system-settings.html#ulimit

其中有如下一段話:

On Linux systems, persistent limits can be set for a particular user by editing the /etc/security/limits.conf file. To set the maximum number of open files for the elasticsearch user to 65,535, add the following line to the limits.conf file:

elasticsearch  -  nofile  65535

This change will only take effect the next time the elasticsearch user opens a new session.

意思是,在linux上,針對某個用戶的持久化資源,可以通過設置/etc/security/limits.conf。

比如,要設置elasticsearch用戶的最大文件數量為65535,需要增加如下行:

elasticsearch  -  nofile  65535

注意,上面還說了,該change只在下次 elasticsearch 開啟一個新session時生效。

上面那個elasticsearch的文檔,真心不錯,大家可以看看。

所以,這個是shell級別的,修改后,要重新登錄shell,該修改文件才生效,同時,要在登錄shell后,啟動的進程才有用。

簡單測試

我們修改該文件為:

* soft nofile 6666
* hard nofile 6666

然后啟動一個進程,監聽1235端口:

[root@localhost ~]# nc -l 1235

然后在另外一個shell中,查看該進程的資源信息:

[root@localhost ~]#       netstat -nltp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:1235            0.0.0.0:*               LISTEN      7015/nc             
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      6632/sshd           
tcp6       0      0 :::3306                 :::*                    LISTEN      6670/mysqld         
tcp6       0      0 :::1235                 :::*                    LISTEN      7015/nc             
tcp6       0      0 :::22                   :::*                    LISTEN      6632/sshd           
[root@localhost ~]# cat /proc/7015/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            8388608              unlimited            bytes     
Max core file size        0                    unlimited            bytes     
Max resident set          unlimited            unlimited            bytes     
Max processes             3795                 3795                 processes 
Max open files            65535                65535                files     

這里的最后一行可以發現,文件數量為65535.

然后我們關閉shell,重新登錄,此時,就會去執行新的/etc/security/limits.conf,設置為6666,然后我們啟動個進程:

[root@localhost ~]# nc -l 1236

另一個shell中查看該進程:

[root@localhost ~]#       netstat -nltp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:1236            0.0.0.0:*               LISTEN      7089/nc             
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      6632/sshd           
tcp6       0      0 :::3306                 :::*                    LISTEN      6670/mysqld         
tcp6       0      0 :::1236                 :::*                    LISTEN      7089/nc             
tcp6       0      0 :::22                   :::*                    LISTEN      6632/sshd           
[root@localhost ~]# cat /proc/7089/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            8388608              unlimited            bytes     
Max core file size        0                    unlimited            bytes     
Max resident set          unlimited            unlimited            bytes     
Max processes             3795                 3795                 processes 
Max open files            6666                 6666                 files  

可以看到,已經變成6666了。

總結一下,該方式,修改文件后,需要重啟shell后生效,且需要是在該shell中啟動的進程才生效。

ulimit 方式(不推薦)

注意,該種方式,僅當前shell生效,且,僅在修改后,啟動的進程才有效。

比如,我們這里在shell1下,修改:

[root@localhost ~]# ulimit -HSn 9999
[root@localhost ~]# nc -l 1234

然后啟動了一個進程,監聽1234端口。

然后我們看看該進程的資源信息:

[root@localhost ~]#       netstat -nltp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:1234            0.0.0.0:*               LISTEN      6982/nc             
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      6632/sshd           
tcp6       0      0 :::3306                 :::*                    LISTEN      6670/mysqld         
tcp6       0      0 :::1234                 :::*                    LISTEN      6982/nc             
tcp6       0      0 :::22                   :::*                    LISTEN      6632/sshd           
[root@localhost ~]# cat /proc/6982/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            8388608              unlimited            bytes     
Max core file size        0                    unlimited            bytes     
Max resident set          unlimited            unlimited            bytes     
Max processes             3795                 3795                 processes 
Max open files            9999                 9999                 files     

然后,在我關閉該shell,重新登錄shell進來后,執行

[root@localhost ~]# nc -l 1234

此時再去查看:

[root@localhost ~]#       netstat -nltp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:1234            0.0.0.0:*               LISTEN      7007/nc             
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      6632/sshd           
tcp6       0      0 :::3306                 :::*                    LISTEN      6670/mysqld         
tcp6       0      0 :::1234                 :::*                    LISTEN      7007/nc             
tcp6       0      0 :::22                   :::*                    LISTEN      6632/sshd           

[root@localhost ~]# cat /proc/7007/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            8388608              unlimited            bytes     
Max core file size        0                    unlimited            bytes     
Max resident set          unlimited            unlimited            bytes     
Max processes             3795                 3795                 processes 
--------------------------- 1
Max open files            65535                65535                files     
Max locked memory         65536                65536                bytes     
Max address space         unlimited            unlimited            bytes     

注意,這里1處顯示,已經變成了65535.

注意這個的限制,是設置了該值后,在此之后啟動的進程才有用;而且對於開機自啟的進程,應該是沒什么用的。

我不建議這種方式。


ulimit [-HSTabcdefilmnpqrstuvx [limit]]

Provides  control over the resources available to the shell and to processes started by it, on systems that allow such control. 


如果要長久生效,可以這樣:

echo ulimit -SHn 65535 >> /etc/profile

但是,這個是只針對由該shell啟動的進程。比如開機啟動的那些,比如mysql,應該是沒法用這個控制的。

當mysql使用systemd方式開機自啟時,怎么正確修改

我們這邊的mysql,是使用rpm安裝的,安裝的時候,就用了如下命令:

    sed -i '/\# End of file/i * soft nofile 65535' /etc/security/limits.conf
    sed -i '/\# End of file/i * hard nofile 65535' /etc/security/limits.conf
    echo ulimit -SHn 65535 >> /etc/profile
    source /etc/profile

同時,也修改了其配置文件:

/etc/my.cnf

[root@localhost CAD_OneKeyDeploy]# vim /etc/my.cnf

[mysqld]
datadir = /var/lib/mysql
socket = /var/lib/mysql/mysql.sock
max_connections=10000
symbolic-links = 0

比如這里的max_connections=10000。

但是,開機重啟后,使用:

[root@localhost CAD_OneKeyDeploy]# cat /proc/6677/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            8388608              unlimited            bytes     
Max core file size        0                    unlimited            bytes     
Max resident set          unlimited            unlimited            bytes     
Max processes             3795                 3795                 processes 
// 1------------------
Max open files            5000                 5000                 files     
Max locked memory         65536                65536                bytes     

上面1處,最大打開文件是5000,這是為啥呢?說明沒效果啊。

為啥呢,找了半天,發現我們的mysql是通過systemd方式啟動的。

[root@localhost CAD_OneKeyDeploy]#  systemctl status mysqld
● mysqld.service - MySQL Server
   // 1
   Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)
   Active: active (running) since Sat 2020-07-18 10:58:07 CST; 44min ago
     Docs: man:mysqld(8)
           http://dev.mysql.com/doc/refman/en/using-systemd.html
  Process: 6674 ExecStart=/usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid $MYSQLD_OPTS (code=exited, status=0/SUCCESS)
  Process: 6636 ExecStartPre=/usr/bin/mysqld_pre_systemd (code=exited, status=0/SUCCESS)
 Main PID: 6677 (mysqld)
   CGroup: /system.slice/mysqld.service
           └─6677 /usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid

Jul 18 10:58:05 localhost.localdomain systemd[1]: Starting MySQL Server...
Jul 18 10:58:07 localhost.localdomain systemd[1]: Started MySQL Server.

上面1處,指定了該service的位置:

/usr/lib/systemd/system/mysqld.service.

我們打開該文件看一下:

...
[Service]
User=mysql
Group=mysql

Type=forking

PIDFile=/var/run/mysqld/mysqld.pid

# Disable service start and stop timeout logic of systemd for mysqld service.
TimeoutSec=0

# Execute pre and post scripts as root
PermissionsStartOnly=true

# Needed to create system tables
ExecStartPre=/usr/bin/mysqld_pre_systemd

# Start main service
ExecStart=/usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid $MYSQLD_OPTS
          
# Use this to switch malloc implementation
EnvironmentFile=-/etc/sysconfig/mysql

# 1 Sets open_files_limit 
LimitNOFILE = 5000

注意這里的最后一行,

# 1 Sets open_files_limit 
LimitNOFILE = 5000

應該就是這個的問題了。

我這里改成10000,然后執行:

systemctl daemon-reload

然后重啟mysql:

systemctl restart mysqld

重新查看最大資源限制:

[root@localhost CAD_OneKeyDeploy]# cat /proc/`pidof mysqld`/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            8388608              unlimited            bytes     
Max core file size        0                    unlimited            bytes     
Max resident set          unlimited            unlimited            bytes     
Max processes             3795                 3795                 processes 
Max open files            10000                10000                files     

看最后一行,已經改成10000了。

重啟后測試,依然是10000,說明修改成功了。

查看/var/log/mysql.log可以發現如下字樣:

2020-07-18T03:48:11.235058Z 0 [Warning] Changed limits: max_open_files: 10000 (requested 50000)

這里,因為我們在systemd的service中限制成了10000,所以這里就顯示成10000了。

測試

mysql中,/usr/lib/systemd/system/mysqld.service為10000,/etc/security/limits.conf 設為6666時,最終使用哪個值?

重啟后發現,答案為:10000.

為什么?大家看/etc/security/limits.conf 注釋:

# /etc/security/limits.conf
#
#This file sets the resource limits for the users logged in via PAM.
#It does not affect resource limits of the system services.

該文件,對通過PAM登錄的用戶進行資源限制;不影響system service。

上面的情況是重啟,然后我又測試:

通過shell登錄后,執行:

[root@localhost ~]# systemctl restart mysqld
[root@localhost ~]# cat /proc/`pidof mysqld`/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            8388608              unlimited            bytes     
Max core file size        0                    unlimited            bytes     
Max resident set          unlimited            unlimited            bytes     
Max processes             3795                 3795                 processes 
Max open files            10000                10000                files     

可以發現,最大文件數,依然是10000,不受 /etc/security/limits.conf影響。

總結

os級別的,必須改后重啟;

ulimit方式,極度不推薦,只能是臨時修改;

/etc/security/limits.conf 方式,用戶級別,修改后,用戶需重登陸shell,文件才生效;此后啟動的進程才生效。

systemd方式的開機自啟動進程,修改對應的service文件才有效。通過該方式設置的,不受/etc/security/limits.conf 影響。

參考:

https://mp.weixin.qq.com/s?__biz=MjM5ODY4ODIxOA==&mid=2653203432&idx=1&sn=7051c8b580c6d3c3f112527c847df381
CentOS 7中MySQL連接數被限制為214個的解決方法


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM