Too many open files
1、数据库error log报错
/usr/local/mysql/bin/mysqld: Can't open file: './rpa_orc_serv/sys_region.frm' (errno: 24 - Too many open files)
[ERROR] Error in accept: Too many open files
2、查看操作系统限制文件打开数
查看用户句柄限制:
ulimit -n
100001
进程使用的文件句柄查看:
lsof -n | grep [pid]
也可以直接查看进程的limits文件
cat /proc/[pid]/limits
修改文件句柄
ulimit -n 65535
这个修改只对当前的session生效,需要更新/etc/security/limits.conf文件
3、确认数据库参数
MySQL> show global variables like '%table_open_cache%';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| table_open_cache | 1024 |
| table_open_cache_instances | 16 |
+----------------------------+-------+
MySQL> show global variables like '%max_connections%';
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| max_connections | 3000 |
+-----------------+-------+
MySQL> show global variables like '%open_files_limit%';
+------------------+--------+
| Variable_name | Value |
+------------------+--------+
| open_files_limit | 100001 |
+------------------+--------+
table_open_cache:是限制mysql开启table的cache file数,一般mysql开一个table就会开启*.frm和 *.ibd等文件,因此,这个至少要表数量的2倍以上。
max_connections:最高连接,连接也是会占用文件句柄的。
open_files_limit:限制打开文件句柄的个数,但是如果系统限制了,这个参数设置比系统限制更大也不会生效的。
4、确认数据库参数状态
MySQL是多线程的,可能在同一时刻有很多的客户端访问某张特定的表。为了能最小化多个客户端在相同表上的不同状态问题,并发会话中访问的每张表都会单独打开。虽然这可能消耗过多的内存,但是通常会提高系统的性能。table_open_cache系统参数是和max_connection相关的。例如200个并发运行的连接,需要指定表缓存的数量至少是200*N,其中N是执行的查询中每个连接涉及到的表最大数量,换句话说,执行10次查询,很可能因为join了很多张表,实际打开的表数量是10的几倍。而且要确保你的操作系统能处理table_open_cache所指定的文件描述符打开的数量。如果table_open_cache太高,MySQL可能会消耗完文件描述符,现象就是拒绝连接或者查询失败。
MySQL会在如下场景关闭一个未使用的表,并将他从表缓存中删除。
1. 当缓存满了,并且一个线程正在尝试打开一个缓存中的表。
2. 当缓存中包含了超过table_open_cache定义的数量,并且缓存中的表不再被任何线程使用。
3. 当我们执行flush tables,或者执行mysqladmin flush-tables以及mysqladmin refresh指令的时候。
当表缓存满了,服务会执行如下过程来确定可用的内存空间,
1. 当前不使用的表会被释放,从最近最少使用的表开始,即采用LRU。
2. 如果打开一张新表但是缓存满了,并且没有其他表能释放,缓存就会临时按需扩容。当缓存处于一个临时扩容状态,表从使用状态改为未使用状态时,就会关闭表,并从缓存中释放。
当你正在用句柄HANDLER tbl_name OPEN打开一张表,会给线程分配一个专用表对象。这个表对象不会被其他线程共享,更不会被关闭,直到线程调用HANDLER tbl_name CLOSE或者线程中断了。只有当这时候,表才会被放回表缓存中(前提是缓存未满)。
当Open_tables值大于table_open_cache值时,每次新的session打开表,有一些无法命中table cache,而不得不重新打开表。这样反应出来的现象就是有大量的线程处于opening tables状态。
MySQL> show global status like 'Open%';
+--------------------------+--------+
| Variable_name | Value |
+--------------------------+--------+
| Open_files | 6 |
| Open_streams | 0 |
| Open_table_definitions | 468 |
| Open_tables | 1024 |
| Opened_files | 2340 |
| Opened_table_definitions | 586 |
| Opened_tables | 101540 |
+--------------------------+--------+
table_open_cache与Open_tables值相等,但是Opend_tables值很大。说明MySQL正在释放缓存的表以容纳新的表,这个过程消耗资源,所以需要加大 table_open_cache的值。
table_open_cache合理值的建议:
Open_tables / Opened_tables >= 0.85
Open_tables / table_open_cache <= 0.95
实际操作过程中,可以把table_open_cache值设置得比Open_tables大一些,然后慢慢增加,逐步调试。调大table_open_cache参数值,减少业务表频繁打开和关闭。至于调整到多少合适,查看MySQL状态参数Open_tables和Opened_tables,当Open_tables接近table_open_cache,并且Opened_tables不会快速增加时,那么此时的table_open_cache值就是一个比较合适的值。table_open_cache 也不是越大越好,毕竟在表多的时候,也需要更多的内存消耗。除了table_open_cache之外,还有两个参数,可以一起关注一下:table_open_cache_instances/table_definition_cache。如果table_open_cache_instances设置过小,在高并发场景下,可能导致MySQL内部线程严重的mutex竞争。
table_open_cache参数表示数据库打开表的缓存数量,即表的高速缓存。每个连接进来,都会至少打开一个表缓存。例如,对于 200 个并行运行的连接,应该让表的缓存至少有 200 × N ,这里 N 是应用可以执行的SQL语句中所需要表的最大数量。此外,还需要为临时表和文件保留一些额外的文件描述符。
当 Mysql 访问一个表时,如果该表在缓存中已经被打开,则可以直接访问缓存;如果还没有被缓存,但是在 Mysql 表缓冲区中还有空间,那么这个表就被打开并放入表缓冲区;如果表缓存满了,则会按照一定的规则将当前未用的表释放,或者临时扩大表缓存来存放,使用表缓存的好处是可以更快速地访问表中的内容。也就是说MySQL每打开一个表,都会读入一些数据到tabe_open_cache缓存中,当mysq在这个缓存中找不到相应的信息时,才会去磁盘上直接读取。
同时,可以考虑设置table_open_cache_instances,5.7默认是16,逻辑是当Open_tables超过(table_open_cache/table_open_cache_instances)时,就会满足条件,加速缓存清理,因此通过增加表缓存分区,应该可以缓解争用,例如2000/16,就会比2000/1更快满足清理的条件。
另外,table_open_cache和open_file_limit存在联动,可以参考,
open_files_limit=2*table_open_cache
临时生效:
MySQL> set global table_open_cache=2048;
sed -i 's/table_open_cache=1024/table_open_cache=2048/g' /etc/my.cnf
本文来自博客园,作者:up~up,转载请注明原文链接:https://www.cnblogs.com/soft-engineer/p/16599108.html