从源码角度谈谈open_files_limit的生成逻辑及”Too many open files”的解决思路

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

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

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

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

配置文件中的配置。

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

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

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

vim mysql-5.7.34/sql/mysqld.cc

其中:

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

下面看看 adjust_related_options 的处理逻辑

其中,

  • 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 的取值逻辑

其中,

  • 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 的取值逻辑

其中,

  • 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 的取值逻辑

同样,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 的取值逻辑

因为是最先调整的参数,所以,这里的 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 的处理逻辑。

相关的常量定义如下:

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

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

下面看看 set_max_open_files 的处理逻辑。

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

其中,

  • 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。在此基础上,

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

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

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

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

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

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

其中,26424 是进程的 PID。

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

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

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

竟然不是 65536,而是 100000。

3.1 启动用户

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

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

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

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

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

除此之外,

3.2 启动脚本

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

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

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

竟然是 65536。

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

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

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

3.3 小结

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

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

4.1 常见原因

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

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

4.2 解决方法

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

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

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

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

看下面这个 Demo。

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

其中,

  • 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 的准确。

其中,9020 是进程的 PID。

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

Original: https://www.cnblogs.com/ivictor/p/14900930.html
Author: iVictor
Title: 从源码角度谈谈open_files_limit的生成逻辑及”Too many open files”的解决思路

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/599401/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Fork/Join框架

    我们要使用ForkJoin框架,必须首先创建一个ForkJoin任务。它提供在任务中执行 fork()和 join() 操作的机制,通常情况下我们不需要直接继承ForkJoinTa…

    数据库 2023年6月14日
    079
  • 今日🎸吉他练到这儿

    本文来自博客园,作者:ukyo–BlackJesus,转载请注明原文链接:https://www.cnblogs.com/ukzq/p/16750421.html Or…

    数据库 2023年6月11日
    098
  • Android Studio更改SDK、Gradle以及模拟器默认下载位置

    版本:Android Studio Chipmunk | 2021.2.1 Patch 2时间:2022年9月1日 1、更改SDK位置 找到 File -> Settings…

    数据库 2023年6月16日
    091
  • [spring]spring详细总结

    spring 1.spring简介 Spring框架是一个开源的应用程序框架,是针对bean的生命周期进行管理的轻量级容器。 Spring解决了开发者在J2EE开发中遇到的许多常见…

    数据库 2023年6月16日
    062
  • AJAX(Web数据交互方式)

    使用 Ajax 技术网页应用能够快速地将增量更新呈现在用户界面上,而不需要重载(刷新)整个页面,这使得程序能够更快地回应用户的操作。 AJAX 一. 什么是 AJAX? AJAX …

    数据库 2023年6月11日
    0104
  • python-图片文字识别

    两种方法 1. 第一种方法 from PIL import Image import pytesseract import re #&#x5BFC;&#x5165;…

    数据库 2023年6月14日
    075
  • NopCommerce学习:MSSQL 2005 排序规则导致中文编码错误

    这两天学习电子商务开源项目NopCommerce,她的确做的很好,在电子商务开源项目中应该算是很棒的. 官方站点: http://www.nopcommerce.com/ 中文社区…

    数据库 2023年6月11日
    085
  • Linux 系统安装RocketMQ

    准备工作 1.去官网下载一个安装包 1.解压 unzip rocketmq-all-4.9.0-bin-release.zip -d /download/compress/ 2.进…

    数据库 2023年6月6日
    087
  • 一文读懂Redis

    Redis与NoSQL概述 Nosql的优势 使用nosql解决cpu与内存压力 使用nosql解决I/O压力 Nosql数据库的概述 NoSql= Not Only SQL 采用…

    数据库 2023年6月6日
    0106
  • 2010最危险的编程错误(转)

    网络无处不在的今天,安全问题日益严峻,攻击事件层出不穷,应该说,软件系统中代码存在安全漏洞是主要的祸因之一。而这实际上反映了软件开发人员在编程的安全性方面缺乏必要的培训和常识。 由…

    数据库 2023年6月11日
    097
  • 管理控制台权限控制

    本文讨论一种常见的访问控制方法: [En] This article discusses a common way of access control: 数据授权: 角色 + 接口…

    数据库 2023年5月24日
    074
  • CentOS 7 Golang 安装

    可去官网下载tar包,这里提供一个1.16的安装地址: curl -#LO https://studygolang.com/dl/golang/go1.16.linux-amd64…

    数据库 2023年6月9日
    0119
  • Rocksdb Compaction原理

    compaction主要包括两类:将内存中imutable 转储到磁盘上sst的过程称之为flush或者minor compaction;磁盘上的sst文件从低层向高层转储的过程称…

    数据库 2023年6月9日
    095
  • 如何识别 SQL Server 的版本

    本文介绍如何识别当前的Microsoft SQL Server 版本号和相应的产品或Service Pack 级别。同时介绍如何识别正在使用的SQL Server 具体版本。 如何…

    数据库 2023年6月11日
    083
  • Geoserver对发布的数据源进行金字塔切片

    一、建立切片数据源1.1建立工作区 1.2添加数据我这里是老师给的高清卫星地图数据,格式为tif工作区选择之前建立的工作区,浏览那里选择对应的文件 1.3建立切片源的图层这里建立的…

    数据库 2023年6月6日
    096
  • 慢查询SQL排查

    转载请注明出处❤️ 作者:测试蔡坨坨 原文链接:caituotuo.top/c56bd0c5.html 你好,我是测试蔡坨坨。 在往期文章中,我们聊过数据库基础知识,可参考「数据库…

    数据库 2023年5月24日
    089
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球