有時候,我們會遇到類似下面的報錯資訊:
.....
[ERROR] /usr/local/mysql/bin/mysqld: Can't open file: './yejr/access.frm' (errno: 24)
[ERROR] /usr/local/mysql/bin/mysqld: Can't open file: './yejr/accesslog.frm' (errno: 24)
......
[ERROR] Error in accept: Too many open files
....
提示資訊很明顯,打開檔案數達到上限了,需要提高上限,或者釋放部分已打開的表檔案描述符。
在MySQL中,有幾個地方會存在檔案描述符限制:
1、在Server層,整個mysqld執行個體打開檔案總數超過使用者程序級的檔案數限制,需要檢查核心 fs.file-max 限制、程序級限制 ulimit -n 及MySQL中的 open-files-limit 選項,是否有某一個超限了。任何一個條件超限了,就會抛出錯誤。
2、雖然Server層總檔案數沒有超,但InnoDB層也有限制,所有InnoDB相關檔案打開總數不能超過 innodb-open-files 選項限制。否則的話,會先把最早打開的InnoDB檔案描述符關閉,才能打開新的檔案,但不會抛出錯誤,隻有告警資訊。
相應地,如果提示超出限制,則可以使用下面方法提高上限:
1、首先,提高核心級總的限制。執行:sysctl -w fs.file-max=3264018;
2、其次,提高核心對使用者程序級的打開檔案數限制。執行:ulimit -n 204800;
3、最後,适當提高MySQL層的幾個參數:open-files-limit、innodb-open-files、table-open-cache、table-definition-cache。
關于前面兩個限制網上可以找到很多詳細解釋,我就不多說了,重點來說下MySQL相關的4個選項。
1、open-files-limit
它限制了mysqld程序可持有的最大打開檔案數,相當于是一個小區的總電閘,一旦超限,小區裡所有住戶都得停電。
5.6.7(含)以前,預設值0,最大和OS核心限制有關;
5.6.8(含)以後,預設值會自動計算,最大和OS核心限制有關。
在5.6.8及以後,其自動計算的幾個限制規則見下,哪個計算結果最大就以哪個為上限:
1) 10 + max_connections + (table_open_cache * 2)
2) max_connections * 5
3) open_files_limit value specified at startup, 5000 if none
2、innodb-open-files
限制InnoDB引擎中表空間檔案最大打開的數量,相當于自己家中電箱裡的某個電路保險,該電路短路的話,會自動跳閘,而不會影響其他電路,去掉短路源後重新按上去就可以使用。
其值最低20,預設400,隻計算了包含ibdata*、ib_logfile*、*.ibd 等三類檔案,redo log不計算在内,5.6以後可獨立undo log,我還未進行測試,應該也不會被計算在内,有興趣的朋友可驗證下。
3、table-definition-cache
該cache用于緩存 .frm 檔案,該選項也預示着 .frm 檔案同時可打開最大數量。
5.6.7 以前預設值400;
5.6.7 之後是自動計算的,且最低為400,自動計算公式:400 + (table-open-cache / 2)。
對InnoDB而言,該選項隻是軟性限制,如果超過限制了,則會根據LRU原則,把舊的條目删除,加入新的條目。
此外,innodb-open-files 也控制着最大可打開的表數量,和 table-definition-cache 都起到限制作用,以其中較大的為準。如果沒配置限制,則通常選擇 table-definition-cache 作為上限,因為它的預設值是 200,比較大。
4、table-open-cache
該cache用于緩存各種所有資料表檔案描述符。
5.6.7 以前,預設值400,範圍:1 - 524288;
5.6.8 - 5.6.11,預設值2000,範圍:1 - 524288;
5.6.12以後,預設值2000(且能自動計算),範圍:1 - 524288。
補充說明1:關于如何計算表檔案描述符的建議:
table-open-cache 通常和 max-connections 有關系,建議設定為 max_connections * N,N的值為平均每個查詢中可能總共會用到的表數量,同時也要兼顧可能會産生臨時表。
補充說明2:MySQL會在下列幾種情況把表從table cache中删掉:
1、table cache已滿,并且正要打開一個新表時;
2、table cache中的條目數超過 table_open_cache 設定值,并且有某些表已經長時間未通路了;
3、執行重新整理表操作時,例如執行 FLUSH TABLES,或者 mysqladmin flush-tables 或 mysqladmin refresh
補充說明3:MySQL采用下述方法來配置設定table cache:
1、目前沒在用的表會被釋放掉,從最近最少使用的表開始;
2、當要打開一個新表,目前的cache也滿了且無法釋放任何一個表時,table cache會臨時加大,臨時加大的table cache中的表不用了之後,會被立刻釋放掉。