來源:
前些天說了一下如何修復損壞的MyISAM表,可惜只會修復並不能脫離被動的境地,只有查明了故障原因才會一勞永逸。
如果數據庫服務非正常關閉(比如說進程被殺,服務器斷電等等),並且此時恰好正在更新MyISAM表,那么發生損壞的概率就比較大。今天我要說的是另一種情況:頻繁的打開關閉MyISAM表文件造成MyISAM表損壞。
什么時候會出現頻繁的打開關閉MyISAM表文件的情況呢?
先查看當前系統的table_cache設置,它的作用就是緩存表文件描述符,降低打開關閉表的頻率,如果這個參數設置得過小,那么很快就會被占滿,再有新請求過來的時候,就不得不關閉一些已打開的表以便為新請求騰出空間,從而出現頻繁的打開關閉MyISAM表文件的情況:
mysql> show variables like 'table%';
再查看當前系統的打開表的情況:
mysql> show status like 'open%';
有兩項關鍵的結果:Open_tables和Opened_tables,他們的名字類似,其含義的區別在於:
Open_tables:表示當前打開的表數目。
Opened_tables:表示累計已經打開的表數目。
那么如何判斷table_cache是否設置合理呢?其判斷尺度如下:
如果Opened_tables遠大於Open_tables,並且Open_tables很接近table_cache,那么就說明table_cache偏小。
還要注意設置操作系統的參數,因為即便你把table_cache設置得很大,一旦超過了操作系統的限制也沒用,可以按如下方法查詢當前值:
ulimit -n
設置方法也很簡單,比如設置成8k,可以這樣:
vi /etc/security/limits.conf
* hard nofile 8192
* soft nofile 8192
這樣設定比在/etc/rc.local里設定ulimit -n 8192更合理一些(參考鏈接)。
MySQL運行穩定后,查看open_files_limit參數:
mysql> show variables like '%open%';
在大量使用MyISAM的環境里,應該保證open_files_limit表類型至少是table_cache的二到三倍,這是因為每個MyISAM表都包括三個文件:一個表定義文件,一個表索引文件,一個表數據文件,詳細介紹可以參考文檔。而在Innodb的環境里,一個表只有一個文件,明白這些基本知識對解決問題很有幫助。
具體的數據庫文件打開情況可以用lsof來查看:
lsof | grep MYI 或者 lsof | grep MYD
可以發現索引文件描述符是客戶端共享的,數據文件則不是,你可以這樣確認這一點:
lsof | egrep -i 'myd|myi' | awk '{++state[$NF]} END {for(key in state) print state[key], "\t", key}' | sort -nr
為了保險點,或許還要查查內核的相關參數,比如fs.file-max,這些細節往往會影響到MySQL:
sysctl -a | grep "file"
注意到以上這些因素,問題差不多就能解決了。不過還要注意一點,table cache不是越大越好:
http://www.freshbooks.com/blog/2008/09/09/now-were-flying/
http://www.mysqlperformanceblog.com/2009/11/16/table_cache-negative-scalability/
http://www.mysqlperformanceblog.com/2009/11/26/more-on-table_cache/
BTW:如果你比較懶惰,也可以用MySQL Performance Tuning Primer Script來判斷參數是否合理
把table_cache適當調小mysql能更快地工作
在我們的意識里,通常增大table_cache,盡量使打開的表句柄在緩存中,mysql能更快地響應操作,但是當我增大table_cache后,cpu增大了很多,查資料發現,table_cache並不是越大越好,因為mysql只有一個全局鎖來控制打開和關閉表,也就是說無論有多少個線程在並行執行,只有一個線程可以打開或關閉表,這也就會出現很多死鎖,別的線程等待那個全局鎖,相應地增加了cpu的消耗,延長了其他鏈接線程執行sql的時間,降低系統性能,所以在保證table_cache夠用的情況下,盡量保持table_cache足夠小,但是這個度怎么把握,我也沒有一定的尺度,還得再學習。
參考資料: