昨天经历了一次mysql灾难,mysqld打开文件数用光,导致一系列问题的发生。
一开始是页面打不开,观察web服务器,apache进城挂住,显然是连接db出问题了,再看mysql,mysql登入,并没有如以前顺畅的登入显示提示符,而是卡着不动,等了半天,终于进去了。
输入show processlist;thread数正常,几乎没有sql语句在执行;
系统console下top,load正常,这下有点瞎,web和db服务器负担都挺小的啊,怎么就卡住不动了呢???
mysql下输入show global status like 'open%';
显示:
+--------------------------+--------+
| Variable_name | Value |
+--------------------------+--------+
| Open_files | 8190|
| Open_streams | 0 |
| Open_table_definitions | 520 |
| Open_tables | 902 |
| Opened_files | 808671 |
| Opened_table_definitions | 6872 |
| Opened_tables | 7573 |
+--------------------------+--------+
其中Open_files | 8190,终于找到问题,启动设置中open_files_limit为8192
这下原因就明白了,mysqld打开的文件句柄数超出了open_files_limit,而建立db连接都需要新的文件句柄(网络连接也算)。
这时候就有新的疑问,为什么打开了这么多文件,但是几乎没有thread在执行sql语句呢,当时没搞懂,后来问了同事,得到了答案:
show variables like 'table_open_cache';
| table_open_cache | 1024
再看| Open_tables | 902 |
902<1024,所以mysql不会自动回收这些打开的句柄,即使这些句柄对应的thread不在执行任何东西。
解决方案:
set global table_open_cache=800;
配置的不恰当导致了一个没法解决的问题,悲剧啊。
ps:打开了902个table却有8190个files是因为部分表使用了分区,这样打开一个表就需要打开很多文件,下一步需要优化一下分区,把大小为0的分区删除,并且合并较小的分区。