mysql版本: 5.7.x
/etc/security/limits.conf
* soft nproc 65535
* hard nproc 65535
* soft nofile 65536
* hard nofile 65536
mysql参数文件:
open_files_limit = 63000
table_open_cache = 16000
innodb_open_files = 65535
max_connections = 2000
先别管这参数是否合理.(合理的话就不会遇到这个问题了-_-)
注:mysql的启动参数是有加 --user=mysql
的
使用 /ect/rc.local
设置的开机自启.(未配置服务).
mysql开机自启后,使用 show global variables like '%open%';
查询open_file
相关的参数
注: 开机自启是使用root启动的, mysqld_safe的用户是root 是正常的, mysqld的用户是mysql也是正常.
innodb_open_files = 16000 不正常 我们设置的是63000
open_files_limit = 63000 正常
我们使用 mysql 重启mysqld进程后 再次查看参数
innodb_open_files = 65535 正常(其实也不正常)
open_files_limit = 65536 不正常(我们设置的63000)
innodb_open_files 是在同一时刻能打开的innodb文件最大数量
open_files_limit 是mysql打开的最大文件数限制
以前有分析过 mysql启动流程: https://cloud.tencent.com/developer/article/2123456 所以我们可以快速锁定文件 sql/mysqld.cc
如果没看过的话, 可以使用 grep -r keyword mysqld_source_dir
来找相关函数. 然后使用gdb之类的来验证.
我们查看源码文件 sql/mysqld.cc
的void adjust_open_files_limit(ulong *requested_open_files)
中有如下记录
limit_1= 10 + max_connections + table_cache_size * 2;
limit_2= max_connections * 5;
limit_3= open_files_limit ? open_files_limit : 5000;
request_open_files= max<ulong>(max<ulong>(limit_1, limit_2), limit_3);
effective_open_files= my_set_max_open_files(request_open_files);
请求的打开文件数量为 那三个值中的最大值, 即 request_open_files = 63000
有效打开文件 来自my_set_max_open_file
s函数. 我们查看源码 mysys/my_file.c
注:
include/my_global.h:#define MY_FILE_MIN 2048
/usr/include/limits.h #define UINT_MAX 4294967295U
include/my_global.h:#define OS_FILE_LIMIT UINT_MAX
uint my_set_max_open_files(uint files)
{
...
files+= MY_FILE_MIN;
files= set_max_open_files(MY_MIN(files, OS_FILE_LIMIT));
...
}
files 取set_max_open_files的值, 那我们就再看下mysys/my_file.c
set_max_open_files吧 (各种套娃...)
#if defined(HAVE_GETRLIMIT)
static uint set_max_open_files(uint 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;
}
}
#else
static uint set_max_open_files(uint max_file_limit)
{
/* We don't know the limit. Return best guess */
return MY_MIN(max_file_limit, OS_FILE_LIMIT);
}
#endif
看起来有点长, 没关系, 我们一点点看
如果为做资源限制, 就返回OS_FILE_LIMIT和max_file_limit的最小值. 我们的环境 OS_FILE_LIMIT (4294967295) 是大于MY_MIN(files, OS_FILE_LIMIT) 2048的 所以返回2048
如果有做资源限制, 那就复杂了, 先获取资源限制值, 可以用Python模拟
还是看代码吧
先保存 资源软限制rlimit.rlim_cur 后面要对这个值做修改.
我们主要看setrlimit(RLIMIT_NOFILE, &rlimit)
如果执行成功(root), 那么max_file_limit 就是修改前的软限制. 如果执行失败(mysql)就是当前的软限制
也就是如果是root账号启动 就是以my.cnf
文件里面的值为准, 如果是mysql启动的 就可能是 ulimit -n
看到的那个值
现在再来看看innodb_open_files吧. 这个就简单多了.
storage/innobase/handler/ha_innodb.cc
if (innobase_open_files < 10) {
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;
}
}
如果小于10 ,就取300
如果 大于 open_files_limit 并且大于table_cache_size 就告警. 并取table_cache_size
那个告警也能再error_log里面找到
感兴趣的可以使用gdb去调试下, 参考mysql启动流程的那个gdb过程就行. 我这里就直接验证了.
root启动: open_files_limit 取 my.cnf文件的63000
但innodb_open_files是65535 大于 63000 且大于 16000 所以innodb_open_files取值为 16000
均符合要求
mysql启动: open_files_limit 取软限制65536
innodb_open_files小于open_files_limit 不变
均符合要求.
open_files_limit
: 如果是root账号启动 以my.cnf
文件里面的值为准, 如果是mysql启动, 就可能是 ulimit -n
看到的那个值innodb_open_files
: 如果它大于open_files_limit且大于table_open_cache 则取值table_open_cache
ulimit -n
的值. 取其小的值.(root和mysql都是在这样)show global status
相关的值来判断.题外话: 涉及到代码相关的问题, 看起来就会非常枯燥. 但正是这一点点的枯燥才能构成一个好用的程序. 比如之前解析ibd文件的时候, 看到那一堆数据类型, 存储方式都还不一样, 一点点从源码和注释里面薅出来, 看起来虽然枯燥, 但一旦全部整理出来了, 就很有成就感, 成就感会促使你去继续完善这个程序.
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。