“Too many open files”是一个比较常见的错误,不仅仅是在 MySQL 中。只要是在 Linux 中启动的进程,都有可能遇到这个错误。

究其原因,是进程打开的文件描述符数超过了自身的限制。

这个限制,是进程级别的,在 MySQL 中,与 open_files_limit 的设置有关。

但是 open_files_limit 并不是所设即所得,配置的和实际生效的并不完全一样。

​一、测试Demo

配置文件中的配置。

open_files_limit = 65536
table_open_cache = 1000
max_connections = 2000

切换到 mysql 用户下,启动实例,看看这三个参数,外加 table_definition_cache 的实际有效值。

[root@node1 ~]# su - mysql

[mysql@node1 ~]$ /usr/local/mysql5.7.34/bin/mysqld --defaults-file=/etc/my.cnf &

mysql> select @@open_files_limit,@@table_open_cache,@@max_connections,@@table_definition_cache;
+--------------------+--------------------+-------------------+--------------------------+
| @@open_files_limit | @@table_open_cache | @@max_connections | @@table_definition_cache |
+--------------------+--------------------+-------------------+--------------------------+
| 2048 | 400 | 1238 | 600 |
+--------------------+--------------------+-------------------+--------------------------+
1 row in set (0.01 sec)

实际值和配置值,竟然没有一个相同,是不是很意外?

二、源码分析

下面,结合源码看看这三个参数的生成逻辑。

# vim mysql-5.7.34/sql/mysqld.cc

#ifdef _WIN32
int win_main(int argc, char **argv)
#else
int mysqld_main(int argc, char **argv)
#endif
{
...
sys_var_init();
ulong requested_open_files;
adjust_related_options(&requested_open_files);
...
}

其中:

  • sys_var_init():初始化系统参数(System Variables)。

  • adjust_related_options():在初始化的基础上,调整相关参数的配置。

下面看看 adjust_related_options 的处理逻辑

void adjust_related_options(ulong *requested_open_files)
{
/* In bootstrap, disable grant tables (we are about to create them) */
if (opt_bootstrap)
opt_noacl= 1; /* The order is critical here, because of dependencies. */
adjust_open_files_limit(requested_open_files);
adjust_max_connections(*requested_open_files);
adjust_table_cache_size(*requested_open_files);
adjust_table_def_size();
}

其中,

  • adjust_open_files_limit:调整 open_files_limit,调整后的值会赋值给 requested_open_files。

  • adjust_max_connections:调整 max_connections,依赖于 requested_open_files,即调整后的 open_files_limit。

  • adjust_table_cache_size:调整 table_cache_size,依赖于调整后的 open_files_limit 和 max_connections。

  • adjust_table_def_size:调整 table_definition_cache,依赖于调整后的 table_cache_size。

这四个参数中,最为复杂的是 open_files_limit 的调整,它涉及到系统对进程能打开的最大文件描述符的限制。

不妨,先基于调整后的 open_files_limit,看看后面三个参数的调整逻辑。

2.1 max_connections

首先,看看 max_connections 的取值逻辑

void adjust_max_connections(ulong requested_open_files)
{
ulong limit; limit= requested_open_files - 10 - TABLE_OPEN_CACHE_MIN * 2; if (limit < max_connections)
{
sql_print_warning("Changed limits: max_connections: %lu (requested %lu)",
limit, max_connections); // This can be done unprotected since it is only called on startup.
max_connections= limit;
}
}

其中,

  • requested_open_files:调整后的 open_files_limit。具体在本 Demo,是 2048。

  • TABLE_OPEN_CACHE_MIN:常量,代表 table_cache_size 可允许的最小值。

    #define TABLE_OPEN_CACHE_MIN    400
  • max_connections:max_connections 的初始值。取配置文件中的配置,2000。如果配置文件中没有设置,则默认为 151。

基于代码中的计算逻辑,limit = 2048 - 10 - 400 * 2 = 1238。

1238 小于 2000,所以 max_connections 最后取值为 1238,与 Demo 开头的查询结果一致。

2.2 table_cache_size

接下来,看看 table_cache_size 的取值逻辑

void adjust_table_cache_size(ulong requested_open_files)
{
ulong limit; limit= max<ulong>((requested_open_files - 10 - max_connections) / 2,
TABLE_OPEN_CACHE_MIN); if (limit < table_cache_size)
{
sql_print_warning("Changed limits: table_open_cache: %lu (requested %lu)",
limit, table_cache_size); table_cache_size= limit;
} table_cache_size_per_instance= table_cache_size / table_cache_instances;
}

其中,

  • max_connections:max_connections 调整后的的值,即 1238。

  • table_cache_instances:table_open_cache_instances。

  • table_cache_size:table_cache_size 的初始值。在这个 Demo 中,是 1000。

基于代码中的计算逻辑,limit = max( ( 2048 - 10 - 1238 ) / 2,400 ) = 400。

400 小于 1000,所以,table_cache_size 最后取值为 400。

2.3 table_definition_cache

接下来,看看 table_definition_cache 的取值逻辑

void adjust_table_def_size()
{
ulong default_value;
sys_var *var; default_value= min<ulong> (400 + table_cache_size / 2, 2000);
var= intern_find_sys_var(STRING_WITH_LEN("table_definition_cache"));
assert(var != NULL);
var->update_default(default_value); if (! table_definition_cache_specified)
table_def_size= default_value;
}

同样,table_cache_size 也是调整后的值,即 400。

default_value = min( 400 + 400 / 2,2000) = 600。

顾名思义,default_value 是默认值。如果没有显式设置 table_definition_cache,则取默认值。

2.4 open_files_limit

最后看看 open_files_limit 的取值逻辑

void adjust_open_files_limit(ulong *requested_open_files)
{
ulong limit_1;
ulong limit_2;
ulong limit_3;
ulong request_open_files;
ulong effective_open_files; /* MyISAM requires two file handles per table. */
limit_1= 10 + max_connections + table_cache_size * 2; /*
We are trying to allocate no less than max_connections*5 file
handles (i.e. we are trying to set the limit so that they will
be available).
*/
limit_2= max_connections * 5; /* Try to allocate no less than 5000 by default. */
limit_3= open_files_limit ? open_files_limit : 5000; request_open_files= max<ulong>(max<ulong>(limit_1, limit_2), limit_3); /* Notice: my_set_max_open_files() may return more than requested. */
effective_open_files= my_set_max_open_files(request_open_files); if (effective_open_files < request_open_files)
{
if (open_files_limit == 0)
{
sql_print_warning("Changed limits: max_open_files: %lu (requested %lu)",
effective_open_files, request_open_files);
}
else
{
sql_print_warning("Could not increase number of max_open_files to "
"more than %lu (request: %lu)",
effective_open_files, request_open_files);
}
} open_files_limit= effective_open_files;
if (requested_open_files)
*requested_open_files= min<ulong>(effective_open_files, request_open_files);
}

因为是最先调整的参数,所以,这里的 max_connections,table_cache_size,open_files_limit 都是初始值。

基于代码中的计算逻辑,

  • limit_1 = 10 + max_connections + table_cache_size _ 2 = 10 + 2000 + 1000 _ 2 = 4100

  • limit_2 = max_connections _ 5 = 2000 _ 5 = 10000

  • limit_3 = open_files_limit ? open_files_limit : 5000 = 65536

request_open_files = max(max(limit_1, limit_2), limit_3) = 65536,可理解为需要打开的文件数。

接下来,调用 my_set_max_open_files 函数获取 effective_open_files,后者是实际能打开的最大文件数。

看看 my_set_max_open_files 的处理逻辑。

uint my_set_max_open_files(uint files)
{
struct st_my_file_info *tmp;
DBUG_ENTER("my_set_max_open_files");
DBUG_PRINT("enter",("files: %u my_file_limit: %u", files, my_file_limit)); files+= MY_FILE_MIN;
files= set_max_open_files(MY_MIN(files, OS_FILE_LIMIT));
if (files <= MY_NFILE)
DBUG_RETURN(files); if (!(tmp= (struct st_my_file_info*) my_malloc(key_memory_my_file_info,
sizeof(*tmp) * files,
MYF(MY_WME))))
DBUG_RETURN(MY_NFILE); /* Copy any initialized files */
memcpy((char*) tmp, (char*) my_file_info,
sizeof(*tmp) * MY_MIN(my_file_limit, files));
memset((tmp + my_file_limit), 0,
MY_MAX((int) (files - my_file_limit), 0) * sizeof(*tmp));
my_free_open_file_info(); /* Free if already allocated */
my_file_info= tmp;
my_file_limit= files;
DBUG_PRINT("exit",("files: %u", files));
DBUG_RETURN(files);
}

相关的常量定义如下:

#ifdef _WIN32
#define MY_FILE_MIN 2048
#else
#define MY_FILE_MIN 0
#endif #ifdef _WIN32
#define MY_NFILE (16384 + MY_FILE_MIN)
#else
#define MY_NFILE 64
#endif #define MY_MIN(a, b) ((a) < (b) ? (a) : (b)) #define OS_FILE_LIMIT UINT_MAX

可见,在 Linux 系统中,MY_MIN(files, OS_FILE_LIMIT)还是等于 files,即 request_open_files。

这段代码里,重点还是调用 set_max_open_files 函数。

下面看看 set_max_open_files 的处理逻辑。

static uint set_max_open_files(uint max_file_limit)
{
struct rlimit rlimit;
uint old_cur;
DBUG_ENTER("set_max_open_files");
DBUG_PRINT("enter",("files: %u", max_file_limit)); if (!getrlimit(RLIMIT_NOFILE,&rlimit))
{
old_cur= (uint) rlimit.rlim_cur;
DBUG_PRINT("info", ("rlim_cur: %u rlim_max: %u",
(uint) rlimit.rlim_cur,
(uint) rlimit.rlim_max));
if (rlimit.rlim_cur == (rlim_t) RLIM_INFINITY)
rlimit.rlim_cur = max_file_limit;
if (rlimit.rlim_cur >= max_file_limit)
DBUG_RETURN(rlimit.rlim_cur); /* purecov: inspected */
rlimit.rlim_cur= rlimit.rlim_max= max_file_limit;
if (setrlimit(RLIMIT_NOFILE, &rlimit))
max_file_limit= old_cur; /* Use original value */
else
{
rlimit.rlim_cur= 0; /* Safety if next call fails */
(void) getrlimit(RLIMIT_NOFILE,&rlimit);
DBUG_PRINT("info", ("rlim_cur: %u", (uint) rlimit.rlim_cur));
if (rlimit.rlim_cur) /* If call didn't fail */
max_file_limit= (uint) rlimit.rlim_cur;
}
}
DBUG_PRINT("exit",("max_file_limit: %u", max_file_limit));
DBUG_RETURN(max_file_limit);
}

这里,使用了两个系统函数:getrlimit(),setrlimit(),分别用来获取和设置系统的资源限制(resource limit)。

#include <sys/resource.h>

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

其中,

  • resource:资源类型。

    可设置的资源类型有:RLIMIT_AS,RLIMIT_CORE,RLIMIT_CPU,RLIMIT_DATA,RLIMIT_FSIZE,RLIMIT_LOCKS,RLIMIT_MEMLOCK,RLIMIT_MSGQUEUE,RLIMIT_NICE,RLIMIT_NOFILE,RLIMIT_NPROC,RLIMIT_RSS,RLIMIT_RTPRIO,RLIMIT_RTTIME,RLIMIT_SIGPENDING,RLIMIT_STACK。

    其中,RLIMIT_NOFILE 代表进程能打开的最大文件描述符数。

  • rlimit:结构体,定义了两个变量。

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

    其中,rlim_cur 代表软限制,rlim_max 代表硬限制。

    注意:资源限制,真正起限制作用的是软限制,硬限制只是限制了软限制可设置的上限。

这两个函数,如果调用成功,则返回 0,反之,则返回-1。

了解完背景知识,接下来看看set_max_open_files具体的处理逻辑。

首先,获取进程的 RLIMIT_NOFILE。在此基础上,

  1. 如果软限制等于 RLIM_INFINITY(无限制),则将 max_file_limit 赋值给软限制。

  2. 如果软限制大于等于 max_file_limit,则返回软限制,并退出函数。

这就意味着,在软限制大于等于 max_file_limit 的情况下:

  1. 软限制等于 RLIM_INFINITY(无限制),返回的是 max_file_limit。

  2. 软限制不是 RLIM_INFINITY,且大于 max_file_limit,则返回软限制。

接下来,就只有一种情况,即软限制小于max_file_limit。此时,会将max_file_limit赋值给软限制和硬限制,并尝试修改进程的RLIMIT_NOFILE。

  1. 如果不能修改成功,则将进程的软限制赋值给 max_file_limit。

  2. 如果能修改成功,则再次获取进程的 RLIMIT_NOFILE,将其赋值给 max_file_limit。这样做,可避免修改实际没有生效的问题。

这就意味着,在软限制小于 max_file_limit 的情况下:

  1. 如果不能修改进程的 RLIMIT_NOFILE,则返回的是软限制。

  2. 如果能修改进程的 RLIMIT_NOFILE,则返回的是 max_file_limit。

什么情况下,能修改成功呢?

  1. mysqld 是在普通用户下启动的,修改后的软限制(即 max_file_limit)小于硬限制。

  2. mysqld 是在 root 用户下启动的或 mysqld 进程有 CAP_SYS_RESOURCE(忽略资源限制)权限。

注意,这里的启动用户指的是启动 mysqld_safe 或 mysqld 的用户,不是运行用户(配置文件中指定的 user)。

既然 max_file_limit 的设置与进程的 RLIMIT_NOFILE 的有关,接下来,我们看看该进程的 RLIMIT_NOFILE。

# cat /proc/26424/limits
Limit Soft Limit Hard Limit Units
...
Max open files 2048 4096 files
...

其中,26424 是进程的 PID。

2048 是软限制,4096 是硬限制。

回到源码,启动用户是 mysql,2048 小于 65536,且 65536 大于 4096,所以不能修改进程的 RLIMIT_NOFILE。故而,最后,我们看到的 open_files_limit 是 2048。

三、进程RLIMIT_NOFILE的决定因素

同样的设置,如果 mysqld 是在 root 用户下启动呢?

[root@node1 ~]# /usr/local/mysql5.7.34/bin/mysqld --defaults-file=/etc/my.cnf &

mysql> select @@open_files_limit,@@table_open_cache,@@max_connections,@@table_definition_cache;
+--------------------+--------------------+-------------------+--------------------------+
| @@open_files_limit | @@table_open_cache | @@max_connections | @@table_definition_cache |
+--------------------+--------------------+-------------------+--------------------------+
| 100000 | 1000 | 2000 | 900 |
+--------------------+--------------------+-------------------+--------------------------+
1 row in set (0.00 sec)

竟然不是 65536,而是 100000。

3.1 启动用户

这个实际上与启动用户有关。用户决定了通过它启动的进程的资源上限,包括文件描述符数。

这里的上限,是在/etc/security/limits.conf 中定义的。如本 Demo 中的配置,

root     soft        nofile       100000
root hard nofile 100000
mysql soft nofile 2048
mysql hard nofile 4096

注意,这里虽然配置的是用户,但实际上限制的是通过用户启动的进程。

一般建议显式设置,如果不设置的话,则默认是 1024。1024,对于大多数应用来说,还是太小了。

用户可自由调整软限制和硬限制的大小,但需遵循以下规则:

  1. 软限制必须小于等于硬限制。

  2. 硬限制可以调小,但不能低于软限制。

除此之外,

  1. 如果是普通用户,对于硬限制的调整是不可逆的,即一旦调小,就不能再调大。

  2. 如果是 root 用户,则没有限制。但不能无限调大,最大值受到/proc/sys/fs/nr_open 的限制。后者决定了单个进程可打开的最大文件描述符数。

3.2 启动脚本

除了启动用户,启动脚本也能限制进程的资源使用。

看下面这个 Demo,同样是在 root 用户下,只不过这次是通过 mysqld_safe 启动。

同样是在 root 用户下,如果是通过 mysqld_safe 启动呢?

[root@node1 ~]# /usr/local/mysql5.7.34/bin/mysqld_safe --defaults-file=/etc/my.cnf &

mysql> select @@open_files_limit,@@table_open_cache,@@max_connections,@@table_definition_cache;
+--------------------+--------------------+-------------------+--------------------------+
| @@open_files_limit | @@table_open_cache | @@max_connections | @@table_definition_cache |
+--------------------+--------------------+-------------------+--------------------------+
| 65536 | 1000 | 2000 | 900 |
+--------------------+--------------------+-------------------+--------------------------+
1 row in set (0.00 sec)

竟然是 65536。

这背后,其实是 mysqld_safe 在“捣鬼”。

USER_OPTION=""
if test -w / -o "$USER" = "root"
then
if test "$user" != "root" -o $SET_USER = 1
then
USER_OPTION="--user=$user"
fi
if test -n "$open_files"
then
ulimit -n $open_files
fi
fi parse_arguments() {
...
--open-files-limit=*) open_files="$val" ;;
--open_files_limit=*) open_files="$val" ;;
...
}

具体来说,如果配置文件或命令行中显式设置了 open_files_limit,则 mysqld_safe 在启动的过程中会通过“ulimit -n $open_files”调整进程的最大文件描述符数。

除了启动脚本,在 CentOS 7 中,如果是通过 systemd 管理进程,还可通过 LimitNOFILE 在进程级别设置文件描述符数的上限。

LimitNOFILE=102400

3.3 小结

进程能打开的最大文件描述符数由启动用户决定。除此之外,启动脚本(包括systemd),能在进程级别设置文件描述符数的上限。

四、Too many open files

文件描述符不够,在 MySQL 中的影响主要有:

  1. 连接创建失败。相关的报错如下:

    [ERROR] Error in accept: Too many open files in system
  2. 查询失败。相关的报错如下:

    [ERROR] /usr/local/mysql5.7.34/bin/mysqld: Can't open file: './sbtest/t4.frm' (errno: 24 - Too many open files)

4.1 常见原因

出现“Too many open files”,常见的原因有两个:

  1. 系统可打开的文件描述符数达到了上限。这里的上限,指的是系统内核的上限,由/proc/sys/fs/file-max 决定。

  2. 进程可打开的文件描述符数达到了上限。

之所以要区分这两种场景,是因为两者的解决方法不一样。

如何判断是哪个原因导致的呢?

  1. 查看系统文件描述符的使用情况。

    cat /proc/sys/fs/file-nr
    2752 0 65536

    输出有三列,如果第一列大于等于第三列,则意味着系统可打开的文件描述符数达到了上限。

    • 第一列:已分配的文件描述符数。
    • 第二列:可用的文件描述符数。
    • 第三列:内核能分配的最大文件描述符数,由/proc/sys/fs/file-max 决定。
  2. /var/log/messages。

    如果系统可打开的文件描述符数达到了上限,/var/log/messages 还会出现以下报错。

    kernel: [8314414.667267] VFS: file-max limit 65536 reached

4.2 解决方法

确定了原因,下面看看解决方法。

4.2.1 针对原因一,系统可使用的文件描述符数达到了上限。

  1. 看看哪些进程打开的文件最多。

    lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr

    输出有两列,第一列是打开的文件的个数,第二列是进程号。

  2. 通过进程号定位具体的进程。

    ps -ef | grep ${PID}
  3. 分析打开文件最多的进程,或 KILL,或重启,或优化。

  4. 如果短期内不能优化解决的,可先临时调大 file-max 的值。

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

    这里修改的是内存值,机器重启就会失效。如果要永久生效,还需修改/etc/sysctl.conf。

    # vim /etc/sysctl.conf
    fs.file-max=100000 # sysctl -p

4.2.2 针对原因二,进程可使用的文件描述符数达到了上限。

  1. 查看进程的最大文件描述符数。

    cat /proc/${PID}/limits | grep "Max open files"
  2. 查看进程当前打开的文件描述符数。

    lsof -p ${PID} | wc -l
  3. 调整进程的最大文件描述符数。

    从 CentOS 6 开始,支持在线调整进程的最大文件描述符数,无需重启进程。

    #CentOS 6
    echo -n "Max open files=102400:102400" > /proc/${PID}/limits #CentOS 7
    prlimit --pid ${PID} --nofile=102400:102400

    注意,CentOS 6 的调整方式在 CentOS 7 中不适用,同样,CentOS 6 中也不支持 prlimit 命令。

    这就意味着,后续MySQL出现“Too many open files”错误,再也不用重启进程了。

如果系统不支持在线调整进程的最大文件描述符数。就只能修改配置,重启实例。具体步骤如下:

  1. 首先查看进程的启动用户。

    ps -ef | grep mysqld

    获取 mysqld 父进程的 ID(PPID),对应输出的第三列。

    基于 PPID 查看 mysqld 的父进程。

    ps -ef | grep ${PPID}

    第一列显示的用户就是启动用户。

  2. 修改启动用户可打开的最大文件描述符数。

    vim /etc/security/limits.conf
  3. 修改 open_files_limit 的配置,重启实例。

无论是在线,还是通过/etc/security/limits.conf,调整进程的最大文件描述符数,在调整的时候,注意以下几点:

  1. 进程的最大文件描述符数不能超过/proc/sys/fs/nr_open 的大小。

  2. 如果修改了/proc/sys/fs/nr_open,需同步修改/proc/sys/fs/file-max,后者代表了内核能分配的最大文件描述符数。

  3. 为了保证配置在系统重启后依然有效,建议同步修改/etc/sysctl.conf。

    # vim /etc/sysctl.conf
    fs.nr_open=100000
    fs.file-max=100000 # sysctl -p

五、查看进程当前打开的文件描述符数

在 MySQL 状态变量中,没有能直观反映文件描述符的指标。

看下面这个 Demo。

open_files_limit 等于 1024,当文件描述符不足,出现“Too many open files”错误时,mysql 状态变量及 lsof 的统计结果如下:

mysql> show global status where variable_name like 'open%' or variable_name='innodb_num_open_files';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| Innodb_num_open_files | 431 |
| Open_files | 2 |
| Open_streams | 0 |
| Open_table_definitions | 615 |
| Open_tables | 578 |
| Opened_files | 1303 |
| Opened_table_definitions | 1260 |
| Opened_tables | 1928 |
+--------------------------+-------+
8 rows in set (0.00 sec) mysql> select @@open_files_limit,@@innodb_open_files;
+--------------------+---------------------+
| @@open_files_limit | @@innodb_open_files |
+--------------------+---------------------+
| 1024 | 431 |
+--------------------+---------------------+
1 row in set (0.01 sec)

其中,

  • Innodb_num_open_files:InnoDB 当前打开的文件数。InnoDB 同时能打开的最大文件数由 innodb_open_files 参数决定,后者默认为-1,基于 table_cache_size 自动调整。

    innodb_open_files 并不是一个硬限制。如果 InnoDB 打开的文件数达到了 innodb_open_files 的限制,则会通过 LRU 算法关闭其它文件。

    if (innobase_open_files < 11) {
    innobase_open_files = 300;
    if (srv_file_per_table && table_cache_size > 300) {
    innobase_open_files = table_cache_size;
    }
    } if (innobase_open_files > (long) open_files_limit) {
    ib::warn() << "innodb_open_files should not be greater"
    " than the open_files_limit.\n";
    if (innobase_open_files > (long) table_cache_size) {
    innobase_open_files = table_cache_size;
    }
    }
  • Open_files:当前打开的文件数。

  • Opened_files:打开过的文件数。

从输出结果来看,这三个变量的值与 open_files_limit(1024)相去甚远,不如 lsof 的准确。

[root@node1 ~]# lsof -p 9020 | wc -l
1054

其中,9020 是进程的 PID。

lsof 同样适用于其它进程的统计。

六、总结

  1. open_files_limit 会取以下三个值中的最大值。

    • limit_1 = 10 + max_connections + table_cache_size * 2。
    • limit_2 = max_connections * 5。
    • limit_3 = open_files_limit ? open_files_limit : 5000。
  2. 如果进程的最大文件描述符数超过 open_files_limit,则实际生效的的是进程的最大文件描述符数。

  3. 如果进程的最大文件描述符数小于 open_files_limit,需区分启动用户。

    3.1 如果启动用户是 root,则实际生效的是 open_files_limit。

    3.2 如果启动用户是普通用户。

    • open_files_limit 小于等于硬限制,则实际生效的是 open_files_limit。
    • open_files_limit 大于硬限制,则实际生效的是进程的最大文件描述符数。
  4. 如果进程是通过 mysqld_safe 启动的,则 mysqld_safe 会基于 open_files_limit 调整进程的最大文件描述符数。

  5. 在源码里,其实还区分了一个场景,即最大文件描述符数为 unlimited。但实际上,在 RHEL 及其衍生版本中,不允许将 nofile 设置为 unlimited。

    # ulimit -n unlimited
    -bash: ulimit: open files: cannot modify limit: Operation not permitted

    虽然允许在/etc/security/limits.conf 文件中将 nofile 设置为 unlimited,但效果等同于 0,此时,相关用户不能创建新的进程,也不允许登录。

    # su - mysql
    su: cannot open session: Permission denied # ssh mysql@192.168.244.10
    Connection to 192.168.244.10 closed.
  6. 在调整进程的最大文件描述符数时,注意:单个进程的最大文件描述符数 <= fs.nr_open <= fs.file-max

  7. 从 CentOS 6 开始,可在线调整进程的最大文件描述符数,无需重启进程。

七、参考资料

https://man7.org/linux/man-pages/man2/getrlimit.2.html

https://www.ibm.com/docs/en/sdk-java-technology/7?topic=rja-system-resource-limits-ulimit-command

从源码角度谈谈MySQL "Too many open files"错误的根本原因的更多相关文章

  1. 从源码角度看MySQL memcached plugin——1. 系统结构和引擎初始化

    本章尝试回答两个问题: 一.memcached plugin与MySQL的关系: 二.MySQL系统如何启动memcached plugin. 1. memcached plugin与MySQL的关系 ...

  2. 从源码角度看MySQL memcached plugin——0.大纲

    本系列文章介绍MySQL memcached plugin插件.剖析已经完成.先把链接弄好,内容会陆续补上. 大纲如下: 系统结构和引擎初始化(已完成) 线程模型和连接的状态机 containers表 ...

  3. 从JDK源码角度看Short

    概况 Java的Short类主要的作用就是对基本类型short进行封装,提供了一些处理short类型的方法,比如short到String类型的转换方法或String类型到short类型的转换方法,当然 ...

  4. 从JDK源码角度看Byte

    Java的Byte类主要的作用就是对基本类型byte进行封装,提供了一些处理byte类型的方法,比如byte到String类型的转换方法或String类型到byte类型的转换方法,当然也包含与其他类型 ...

  5. 从JDK源码角度看Object

    Java的Object是所有其他类的父类,从继承的层次来看它就是最顶层根,所以它也是唯一一个没有父类的类.它包含了对象常用的一些方法,比如getClass.hashCode.equals.clone. ...

  6. 从JDK源码角度看Boolean

    Java的Boolean类主要作用就是对基本类型boolean进行封装,提供了一些处理boolean类型的方法,比如String类型和boolean类型的转换. 主要实现源码如下: public fi ...

  7. 从源码角度深入理解Toast

    Toast这个东西我们在开发中经常用到,使用也很简单,一行代码就能搞定: 1: Toast.makeText(", Toast.LENGTH_LONG).show(); 但是我们经常会遇到这 ...

  8. Android -- 带你从源码角度领悟Dagger2入门到放弃

    1,以前的博客也写了两篇关于Dagger2,但是感觉自己使用的时候还是云里雾里的,更不谈各位来看博客的同学了,所以今天打算和大家再一次的入坑试试,最后一次了,保证最后一次了. 2,接入项目 在项目的G ...

  9. Android -- 带你从源码角度领悟Dagger2入门到放弃(二)

    1,接着我们上一篇继续介绍,在上一篇我们介绍了简单的@Inject和@Component的结合使用,现在我们继续以老师和学生的例子,我们知道学生上课的时候都会有书籍来辅助听课,先来看看我们之前的Stu ...

随机推荐

  1. LATEX如何写多个条件推导式推出一个结论

    用markdown写推导式的时候,不太好写,故做个笔记记录一下,插入 公式块 : \left. \begin{aligned} \left. \begin{aligned} \text{这里可以写文字 ...

  2. AlexeyAB DarkNet YOLOv3框架解析与应用实践(六)

    AlexeyAB DarkNet YOLOv3框架解析与应用实践(六) 1. Tiny Darknet 听过很多人谈论SqueezeNet. SqueezeNet很酷,但它只是优化参数计数.当大多数高 ...

  3. Technology Document Guide of TensorRT

    Technology Document Guide of TensorRT Abstract 本示例支持指南概述了GitHub和产品包中包含的所有受支持的TensorRT 7.2.1示例.Tensor ...

  4. ng : 无法加载文件 C:\Users\szz\AppData\Roaming\npm\ng.ps1,因为在此系统上禁止运行脚本的解决方案

    当安装好Angular CLI后想要查看该版本时在终端键入: ng version 后出现下图的错误提示 解决方案: 在win10 系统中有一个搜索框 输入 Windos PowerShell (一定 ...

  5. java后端知识点梳理——java基础

    面向对象 java三大特性 封装: 将事务封装成一个类,达到解耦,隐藏细节的效果.通过get/set等方法,封装了内部逻辑,并保留了特定的接口与外界联系. 继承: 从一个已知的类中派生出一个新的类,新 ...

  6. Spring:DI依赖注入的几种方式

    据我所学,spring实现依赖注入(DI)的方式分为三大类:基于构造器(构造方法)的依赖注入.基于setter的依赖注入.其他方式(c命名空间.p命名空间等).其中推荐使用setter方法注入,这种注 ...

  7. NX二次开发-获取面的外围边和孔槽边

    函数: UF_MODL_ask_face_loops()  获取面的所有封闭边组合(多组edge) UF_MODL_ask_loop_list_count() 获取loop的数量(面上孔.槽的数量+1 ...

  8. [Azure DevOps] 编译时自动修改版本号

    1. 需求 在使用 Pipeline 自动化 CI/CD 流程的过程中,我还还需要自动修改程序集的版本号.这个功能 EdiWang 和LeoLaw 都写文章讲解过做法.不过我的项目基本都是 .Net ...

  9. 【模板】 RMQ求区间最值

    RMQ RMQ简单来说就是求区间的最大值(最小值) 核心算法:动态规划 RMQ(以下以求最大值为例) F[i,j]表示 从 i 开始 到i+2j -1这个区间中的最大值 状态转移方程 F[i,j]=m ...

  10. SQL Prompt快捷键

    1. DF DELETE FROM  2. ssf SELECT * FROM  3. be BEGIN  END 4. ij INNER JOIN  5. ap ALTER PROCEDURE  6 ...