MySQL open_files_limit相關設置


背景:     
數據庫鏈接不上,報錯:

root@localhost:/var/log/mysql# mysql -uzjy -p -h192.168.1.111 --default-character-set=utf8 -P3306
Enter password: 
ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 0

分析方法:
在這個地方我看不出什么,直接看錯誤日志:

[ERROR] /usr/sbin/mysqld: Can't open file: './java/tt_fte.frm' (errno: 24)
root@localhost:/var/log/mysql# perror 24
OS error code  24:  Too many open files

一看到這里,就覺得需要調整 open_files_limit 參數了(默認最小1024),至此問題解決。雖然問題解決了,但是還沒有弄清楚MySQL打開了多少個文件描述符,打開了哪寫文件描述符號,以及如何預防。怎么了解MySQL打開了多少個文件描述符呢?
知識點:lsof去查看,理解myisam和innodb的文件描述符、OS 的ulimit相關認識。
基於上面的問題,現在來分析(此時數據庫就連不上了,一直報無法打開的錯誤信息)查看MySQL打開的文件:

root@localhost:~# lsof -p 26288 | wc -l
1042

#因為數據庫鏈接不了,所以只能通過系統查看他的文件描述符
root@localhost:~# cat /proc/26288/limits 
Limit                     Soft Limit           Hard Limit           Units     
Max cpu time              unlimited            unlimited            seconds   
Max file size             unlimited            unlimited            bytes     
Max data size             unlimited            unlimited            bytes     
Max stack size            8388608              unlimited            bytes     
Max core file size        0                    unlimited            bytes     
Max resident set          unlimited            unlimited            bytes     
Max processes             79877                79877                processes 
Max open files 1024 4096 files   
Max locked memory         65536                65536                bytes     
Max address space         unlimited            unlimited            bytes     
Max file locks            unlimited            unlimited            locks     
Max pending signals       79877                79877                signals   
Max msgqueue size         819200               819200               bytes     
Max nice priority         0                    0                    
Max realtime priority     0                    0                    
Max realtime timeout      unlimited            unlimited            us   

也可以通過下面的方法查看,下面的方法最為精確
root@localhost:~# ls -lh /proc/26288/fd | wc -l
1024

上面看出,MySQL這時打開的文件描述符1024,已經達到上限,所以再打開的時候就報錯了。修改open_files_limit 參數,設置為2000試試?

root@localhost:~# lsof -p 27732 | wc -l
1053
root@localhost:~# cat /proc/27732/limits 
Limit                     Soft Limit           Hard Limit           Units     
Max cpu time              unlimited            unlimited            seconds   
Max file size             unlimited            unlimited            bytes     
Max data size             unlimited            unlimited            bytes     
Max stack size            8388608              unlimited            bytes     
Max core file size        0                    unlimited            bytes     
Max resident set          unlimited            unlimited            bytes     
Max processes             79877                79877                processes 
Max open files 2000 2000 files    
Max locked memory         65536                65536                bytes     
Max address space         unlimited            unlimited            bytes     
Max file locks            unlimited            unlimited            locks     
Max pending signals       79877                79877                signals   
Max msgqueue size         819200               819200               bytes     
Max nice priority         0                    0                    
Max realtime priority     0                    0                    
Max realtime timeout      unlimited            unlimited            us        
root@localhost:~# ls -lh /proc/27732/fd | wc -l
1035

上面看出,MySQL需要打開的文件描述符1035,小於2000,數據庫正常。到此為止,上面的問題得到解決。想更清楚了解的請繼續看:
查看數據庫的變量:

zjy@localhost : (none) 10:27:19>show global status like 'open%';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| Open_files               | 804   |
| Open_streams             | 0     |
| Open_table_definitions   | 400   |
| Open_tables              | 400   |
| Opened_files             | 6803  |
| Opened_table_definitions | 3861  |
| Opened_tables            | 4315  |
+--------------------------+-------+
7 rows in set (0.00 sec)

zjy@localhost : (none) 10:31:11>show global variables like 'open%';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| open_files_limit | 2000  |
+------------------+-------+
1 row in set (0.00 sec)

zjy@localhost : (none) 10:39:03>show global variables like 'table_open_cache';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| table_open_cache | 400   |
+------------------+-------+
1 row in set (0.00 sec)

在MySQL 5.1.3之后,還添加了2個狀態值:Open_table_definitions和Opened_table_definitions。這2個值代表的意思如下:
Open_table_definitions  :代表當前緩存了多少.frm文件。
Opened_table_definitions:代表自從MySQL啟動后,緩存了.frm文件的數量。 需要注意的是.frm文件是MySQL用於存放表結構的文件,對應myisam和innodb存儲引擎都必須有的,可以通過show open tables 查看 這2個變量的值。

說到這里主要關注的參數還是:table_open_cache 其作用是:從MySQL5.1.3 開始改為table_open_cache,所有線程所打開表的數量, 增加此值就增加了mysqld所需要的文件描述符的數量.它的作用就是緩存表文件描述符,降低打開關閉表的頻率, 如果這個參數設置得過小,那么很快就會被占滿,再有新請求過來的時候,就不得不關閉一些已打開的表以便為新請求騰出空間,從而出現頻繁的打開關閉MyISAM表文件的情況,而INNODB表的打開 不受這個參數控制,而是放到其數據字典當中,即在ibd中

查看打開的各個文件描述符是什么:大部分都是MYI,MYD,IBD文件。

root@localhost:/proc/27732/fd# ls -lh | grep MYI | wc -l
400
root@localhost:/proc/27732/fd# ls -lh | grep MYD | wc -l
400
root@localhost:/proc/27732/fd# ls -lh | grep ibd | wc -l
215
root@localhost:/proc/27732/fd# lsof | grep /var/lib/mysql | grep MYI | wc -l
400
root@localhost:/proc/27732/fd# lsof | grep /var/lib/mysql | grep MYD | wc -l
400
root@localhost:/proc/27732/fd# lsof | grep /var/lib/mysql | grep '\.ibd' | wc -l
214

上面看到400,是否和table_open_cache有關?經過測試得出:MySQL變量 Open_tables 打開了 table_open_cache的數目,和lsof中的MYI和MYD數目對應(MYISAM)。
即  Open_tables  <=  table_open_cache要是Open_tables 和 table_open_cache 一樣,表示MySQL已經用完了表緩存,可以適當的調大。
214是什么意思?是不是INNODB表?經驗證確認:

zjy@localhost : (none) 10:43:54>select count(*) from information_schema.tables where ENGINE='innodb';
+----------+
| count(*) |
+----------+
|      214 |
+----------+
1 row in set (0.05 sec)

從上面的信息中得出:

open_files_limit = table_open_cache*2 + innodb表

把上面的數字帶進去:

open_files_limit = 400*2 + 214 = 1014 

結果為1014 要小於默認的1024,為什么默認時候1024報錯呢,那除這些外還包含什么?

root@localhost:/proc/27732/fd# ls -lh | grep -v  MYI | grep -v MYD | grep -v "\.ibd" | wc -l 
23
#注意這個出現的數目不是固定的,有隨機性。包含了各種日志、共享表空間、socket文件等信息。
View Code
root@localhost:/proc/27732/fd# ls -lh | grep -v  MYI | grep -v MYD | grep -v "\.ibd"
total 0
lrwx------ 1 root root 64 Jan 30 22:29 0 -> /dev/null
l-wx------ 1 root root 64 Jan 30 22:29 1 -> /var/log/mysql/mysql.err
lrwx------ 1 root root 64 Jan 30 22:29 10 -> socket:[795955]
lrwx------ 1 root root 64 Jan 30 22:29 11 -> /tmp/ibKm37iF (deleted)
lrwx------ 1 root root 64 Jan 30 22:29 12 -> socket:[795956]
lrwx------ 1 root root 64 Jan 30 22:29 13 -> socket:[800403]
lrwx------ 1 root root 64 Jan 30 22:29 17 -> /var/lib/lxc/localhost/rootfs.hold
l-wx------ 1 root root 64 Jan 30 22:29 2 -> /var/log/mysql/mysql.err
lrwx------ 1 root root 64 Jan 30 22:29 3 -> /var/lib/mysql/ibdata1
lrwx------ 1 root root 64 Jan 30 22:29 31 -> /var/lib/mysql/master.info
lrwx------ 1 root root 64 Jan 30 22:29 32 -> /var/lib/mysql/mysqld-relay-bin.index
lrwx------ 1 root root 64 Jan 30 22:29 33 -> /var/lib/mysql/relay-log.info
lrwx------ 1 root root 64 Jan 30 22:29 34 -> /var/lib/mysql/mysqld-relay-bin.000123
lrwx------ 1 root root 64 Jan 30 22:29 37 -> socket:[795961]
lrwx------ 1 root root 64 Jan 30 22:29 4 -> /tmp/ibse5AFw (deleted)
lrwx------ 1 root root 64 Jan 30 22:29 5 -> /tmp/ibBAQlVN (deleted)
lrwx------ 1 root root 64 Jan 30 22:29 6 -> /tmp/ibxpP6a5 (deleted)
lrwx------ 1 root root 64 Jan 30 22:39 624 -> socket:[800541]
lrwx------ 1 root root 64 Jan 30 22:39 625 -> socket:[800542]
lrwx------ 1 root root 64 Jan 30 22:29 7 -> /tmp/ib9dUH3m (deleted)
lrwx------ 1 root root 64 Jan 30 22:29 8 -> /var/lib/mysql/ib_logfile0
lrwx------ 1 root root 64 Jan 30 22:29 9 -> /var/lib/mysql/ib_logfile1

最后結果:

open_files = 400*2 + 214 + 23(隨機) = 1037

得到了最后的打開文件描述符的結果為1037,那把 open_files_limit 設置成1037看看會是什么情況?理論上不能創建表了,重啟之后但是數據庫正常,那創建一張INNODB表試試?
可以創建4張表,(和上面說的隨機性有關系,因為此時的數據不是23了。)到創建第5張表的時候:

zjy@localhost : zhoujy 11:03:24>create table idx_mer5(id int,name varchar(10),name1 varchar(10),address varchar(30))engine =innodb;
ERROR 23 (HY000): Out of resources when opening file './zhoujy/' (Errcode: 24)

數據庫直接報錯,無法創建表,此時重啟數據庫,又會出現和本文開頭的錯誤信息,因為此時會多了(ls -lh | grep -v  MYI | grep -v MYD | grep -v CSV | grep -v "\.ibd")的內容。找到問題出現的原因了。解決辦法是:
1,在不修改open_files_limit下把table_open_cache參數調小。

2,修改open_files_limit,至少設置成上面的這個公式。

總結:

在Mysql數據庫中,想知道Mysql打開了多少張表,用:

root@localhost >show global status like 'open%';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| Open_files               | 351   |
| Open_streams             | 0     |
| Open_table_definitions   | 305   |
| Open_tables              | 305   |
| Opened_files             | 996   |
| Opened_table_definitions | 403   |
| Opened_tables            | 1227  |
+--------------------------+-------+
7 rows in set (0.00 sec)

具體打開了哪些表:
root@localhost >show open tables;

 打開了多少文件描述符,用:

root@zhoujy:~# pidof mysqld
19068
root@zhoujy:~# cd /proc/19068/fd
#總的文件描述符: root@zhoujy:
/proc/19068/fd# ls -lh | wc -l 498 #MyISAM描述符: root@zhoujy:/proc/19068/fd# ls -lh | grep 'MYD' | wc -l 172 #CSV描述符: root@zhoujy:/proc/19068/fd# ls -lh | grep 'CSV' | wc -l 2 #Innodb描述符: root@zhoujy:/proc/19068/fd# ls -lh | grep '\.ibd' | wc -l 131

要是此時的【
文件描述符】的總數 和 open_files_limit 一樣,在新建表的時候就會導致數據庫報打不開表的錯誤信息。

知識點:

       MyISAM和CSV表打開時占用2個文件描述符,Innodb則需要1個文件描述符。一些日志信息(relay log,binlog,error-log等)也需要文件描述符。table_open_cache對MyISAM有效,對Innodb無效。當運行 flush tables 關閉表的時候,只對MyISAM表有效,即關閉MISAM表的文件描述符,Innodb表也會關閉,但是文件描述符不會關。
       當表都是MyISAM,在極端的情況下,table_open_cache數目的表全部被打開(512張)就會占用掉1024個文件描述符。而open_files_limit是1024的話,就會出現報錯的情況(本文例子的情況)。所以
如果是有大量的 MyISAM 表,那么就需要特別注意打開文件數是否會超出限制了。
       總之,確實設置open_files_limit的時候,先要知道table_open_cache 為多少,再加上inodb表的數目和一些日志的數目。
上面的結果和系統的ulimit沒有關系(ubuntu默認apt下來的實例),要是不是默認安裝的實例呢?請繼續看:
       在測試中發現,設置OS的文件描述符(/etc/security/limits.conf)
值是無效的,即MySQL啟動后open_files_limit始終以my.cnf中設置的參數open_files_limit為准。(版本MySQL5.5.29 ubuntu0.12.04.1),而在非Ubuntu中是按照他們(os和mysql)哪個最高用哪個的方法,通過 cat /proc/10415/limits 查看,依然都是數據庫配置文件(open_files_limit)中設置的值。懷疑是ubuntu定制mysql的問題(apt下來的mysql)

而用mysqld_safe開啟的實例(非apt-get install 安裝),則按照下面的規則:

默認設置的open_files_limit 比其他相關的參數都大。[max_connections*5和10+max_connections+table_cache_size*2 大]

一:
1:ulimit -n 65535
2:修改 my.cnf 限制
open_files_limit = 10000
3:重啟 mysql
4:show global variables like '%open%';
| open_files_limit | 10000 |

二:
注釋 open_files_limit
| open_files_limit | 65535 

三:
1:ulimit -n 5000
2:修改 my.cnf 限制
open_files_limit = 10000
3:重啟 mysql
4:show global variables like '%open%';
| open_files_limit | 10000 

四:
注釋 open_files_limit
| open_files_limit | 5000 

這里總結一句話:當open_files_limit沒有被配置的時候,比較max_connections*5和ulimit -n的值,哪個大用哪個,當open_file_limit被配置的時候,
比較open_files_limit
和max_connections*5的值,哪個大用哪個。

 注意:open_files_limit 大小和 max_connections*5需要比較,那個最大就用那個值來設置open_files_limit 。【比較open_files_limit,max_connections*5和10+max_connections+table_cache_size*2中最大值】

--my.cnf--
open_files_limit = 5000
max_connections = 1024

mysql> show global  variables like '%open%';
+-------------------+----------+
| Variable_name     | Value    |
+-------------------+----------+
| open_files_limit  | 5120     |   #1024*5 > 5000
+-------------------+----------+
View Code
vi /etc/security/limits.conf

mysql            soft    nofile          65536
mysql            hard    nofile          65536

總結:
      
所以在配置open_files_limit的時候,設置多大合適,需要知道具體的表數目和類型等,具體情況需要自己分析。沒有配置的則需要注意配置OS的ulimit(啟動前設置)和max_connections的大小。而用apt-get 下來的mysql實例則都是按照open_files_limit和max_connections 來比較設置的,和OS的ulimit無關。

########2016-08-12更新########

怎么計算打開文件數

########2020-04-08更新########

MySQL大量線程處於Opening tables的問題分析

 

相關資料:

Mysql如何打開文件數
MySQL打開的文件描述符限制
關於table cache的相關參數


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM