[MySQLFAQ]系列–mysql如何計算開啟檔案數

科技小先鋒發表於2017-11-16

一、試驗

從手冊的”6.4.8. How MySQL Opens and Closes Tables”可以瞭解到,每開啟一個MyISAM表,就需要使用2個檔案描述符,我們們來驗證一下。

1. 重啟mysqld
/etc/init.d/mysql restart
2. 看看開啟了幾個檔案
lsof | grep /home/mysql
...
mysqld    24349 mysql    5u     unix 0x000001041e8de040             4244009 /home/mysql/mysql.sock
mysqld    24349 mysql    6u      REG               8,33     2048   30425188 /home/mysql/mysql/host.MYI
mysqld    24349 mysql    7u      REG               8,33        0   30425189 /home/mysql/mysql/host.MYD
mysqld    24349 mysql    8u      REG               8,33     2048   30425153 /home/mysql/mysql/user.MYI
mysqld    24349 mysql    9u      REG               8,33      892   30425155 /home/mysql/mysql/user.MYD
mysqld    24349 mysql   10u      REG               8,33     5120   30425126 /home/mysql/mysql/db.MYI
mysqld    24349 mysql   11u      REG               8,33     3080   30425148 /home/mysql/mysql/db.MYD
mysqld    24349 mysql   12u      REG               8,33     4096   30425154 /home/mysql/mysql/tables_priv.MYI
mysqld    24349 mysql   13u      REG               8,33        0   30425157 /home/mysql/mysql/tables_priv.MYD
mysqld    24349 mysql   14u      REG               8,33     4096   30425143 /home/mysql/mysql/columns_priv.MYI
mysqld    24349 mysql   15u      REG               8,33        0   30425156 /home/mysql/mysql/columns_priv.MYD
mysqld    24349 mysql   16u      REG               8,33     4096   30425127 /home/mysql/mysql/procs_priv.MYI
mysqld    24349 mysql   17u      REG               8,33        0   30425136 /home/mysql/mysql/procs_priv.MYD
mysqld    24349 mysql   18u      REG               8,33     1024   30425173 /home/mysql/mysql/servers.MYI
mysqld    24349 mysql   19u      REG               8,33        0   30425174 /home/mysql/mysql/servers.MYD
mysqld    24349 mysql   20u      REG               8,33     2048   30425182 /home/mysql/mysql/event.MYI
mysqld    24349 mysql   21u      REG               8,33        0   30425183 /home/mysql/mysql/event.MYD
...
可以看到,總共開啟了8個表,每個表分別有2個檔案描述符,看來沒錯。
3. 再來看 status 結果
mysql>show global status like `open_%`;
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| Open_files             | 17    |
| Open_streams           | 0     |
| Open_table_definitions | 15    |
| Open_tables            | 8     |
| Opened_files           | 52    |
| Opened_tables          | 15    |
+------------------------+-------+
4. flush tables 後再看看
mysql>flush tables;
mysql> show global status like `open_%`;
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| Open_files             | 1     |
| Open_streams           | 0     |
| Open_table_definitions | 0     |
| Open_tables            | 0     |
| Opened_files           | 52    |
| Opened_tables          | 15    |
+------------------------+-------+
lsof | grep /home/mysql
...
mysqld    24349 mysql    5u     unix 0x000001041e8de040             4244009 /home/mysql/mysql.sock
mysqld    24349 mysql   22u     unix 0x00000102378ff980             4244128 /home/mysql/mysql.sock
...
可以看到,flush 之後,所有的檔案描述符都釋放了。

通過測試可以得知,另一個開啟的檔案描述符是 slow query log所用。

如果是有大量的 MyISAM 表,那麼就需要特別注意開啟檔案數是否會超出限制了。

二、原理

接下來仔細瞭解下這個最大檔案數相關的引數:
table_cache (新版本改成了 table_open_cache)  The number of cached open tables.
open_files_limit  If this is not 0, then mysqld will use this value to reserve file descriptors to use with setrlimit(). 
If this value is 0 then mysqld will reserve max_connections*5 or max_connections + table_cache*2 (whichever is larger) 
number of files.
如果 open_files_limit 不是設定為 0,則以 setrlimit() 函式計算後的結果為準,如果設定為 0,則實際值是 max_connections*5 或 max_connections + table_cache*2 中的最大者。

因此,想要解決開啟檔案數超限的問題,還需要綜合系統核心限制(ulimit -n),mysqld自身限制(open_files_limit),以及表快取數(table_open_cache)等多方面因素。

不過,實際測試中,發現卻不是這樣的,open_files_limit採用了核心的最大限制,而非上面的計算結果。
1. 檢視核心限制
ulimit -n
65535
2. 修改 my.cnf 限制
vi /etc/my.cnf
...
open_files_limit = 10000
...
3. 重啟 mysqld
/etc/init.d/mysql restart
4. 檢視結果
mysql>show global variables like `%open%`;
| open_files_limit  | 65535 |
| table_open_cache  | 1000  |
5. 不設定 open_files_limit 看看
vi /etc/my.cnf
...
#open_files_limit = 10000
...
重啟
/etc/init.d/mysql restart
檢視
mysql>show global variables like `%open%`;
| open_files_limit  | 65535 |
| table_open_cache  | 1000  |
而這個時候,按計算公式結果如下:
| max_connections    | 100   |
| table_open_cache            | 1000      |
來計算一下:
max_open_files_1 = max_connections + table_cache * 2 = 100 + 1000 * 2 = 2100
max_open_files_2 = max_connections*5 = 100 * 5 = 500
6. 修改 ulimit 試試看:
unlimit -n 5000
vi /etc/my.cnf
...
open_files_limit = 10000
...
/etc/init.d/mysql restart
mysql>show global variables like `%open%`;
| open_files_limit  | 10000 |
| table_open_cache  | 1000  |
open_files_limit 比核心最大限制數還大,因此以 open_files_limit 為準。
vi /etc/my.cnf
...
#open_files_limit = 10000
...
/etc/init.d/mysql restart
mysql>show global variables like `%open%`;
| open_files_limit  | 5000  |
| table_open_cache  | 1000  |
看到了,變成了新的核心最大限制
看到了吧,結果完全跟文件描述的以及mysql原始碼中寫的不一樣,看來預編譯版本有些地方不太可靠啊 ?
以上測試在mysql 5.1.23-rc(預編譯), mysql-5.1.24-rc(自編譯) 以及 5.0.45(預編譯) 均一樣。
uname -a
Linux s1.yejr.com 2.6.9-55.ELsmp #1 SMP Fri Apr 20 16:36:54 EDT 2007 x86_64 x86_64 x86_64 GNU/Linux
mysql> select version();
+---------------+
| version()     |
+---------------+
| 5.1.23-rc-log | 
+---------------+


相關文章