以前我一直認為,當php的頁面執行結束時,會自動釋放掉一切。相信很多人都跟我想的一樣。但事實證明並不是這樣。比如session就不會隨著頁面執行完畢而釋放。
php的記憶體回收機制,其實只針對於php本身。對於mysql,php沒權利去自動去釋放它的東西。如果你在頁面執行完畢前不調用mysql_close(),那麼mysql那邊是不會關閉這個串連的。如果你是用的是pconnect方式,即使你在頁面執行完畢前調用mysql_close(),也無法另mysql關閉這個串連。
也許在負載低的情況下,你感受不到有何不妥。下面我就來解釋這兩天我觀察出的現象:
在php中使用pconnect方式建立串連,然後到mysql用戶端下執行show processlist;如果你的負載到一定程度的話,你可以看到很多sleep的進程,這些進程就是人們常說的死串連,它們會一直保持sleep,直到my.cnf裡面設定的wait_timeout這個參數值的時間到了,mysql才會自己殺死它。在殺死它的時候,mysql還會在error-log裡面記錄一條Aborted connection xxx to db: 'xxx' user: 'xxx' host: 'xxx'的日誌,用google翻譯一下,會得到一個相當強悍的解釋"胎死腹中的串連"!
那麼造成sleep的原因,有三個,下面是mysql手冊給出的解釋:
1.用戶端程式在退出之前沒有調用mysql_close().
2.用戶端sleep的時間在wait_timeout或interactive_timeout規定的秒內沒有發出任何請求到伺服器.
3.用戶端程式在結束之前向伺服器發送了請求還沒得到返回結果就結束掉了.
上面是我根據google的翻譯改了下,可能有某些地方翻譯的不準確。原文請見下面:
1 The client program did not call mysql_close() before exiting.
2 The client had been sleeping more than wait_timeout or interactive_timeout seconds without issuing any requests to the server.
3 The client program ended abruptly in the middle of a data transfer
如果你的sleep進程數在同一時間內過多,再加上其他狀態的串連,總數超過了max_connection的值,那mysql除了root使用者外,就無法再繼續處理任何請求無法與任何請求建立串連或者直接down了。所以,這個問題在大負載的情況下還是相當嚴重的。如果發現你的mysql有很多死串連存在,首先要先檢查你的程式是否使用的是pconnect的方式,其次,檢查在頁面執行完畢前是否及時調用了mysql_close(),
還有一個辦法,你可以在my.cnf裡面加上wait_timeout和interactive_timeout,把他們的值設的小一些,預設情況下wait_timeout的值是8小時的時間,你可以改成1個小時,或半個小時。這樣mysql會更快的殺死死串連。防止串連總數超過max_connection的值。或者把max_connection的值設定的更大,不過這樣顯然不妥,串連的數量越多,對你伺服器的壓力越大。實際上那些串連都是冗餘的,把它們儘快殺死才是上策。
以前總是說,在使用php串連mysql的時候,盡量不要使用pconnect的方式,看完我上面所說的那些,應該可以明白為什麼了吧,因為我們使用php大多數情況下都是做web開發,web開發是面向多使用者,那麼使用者的數量與mysql串連數是成正比的。使用pconnect的方式,即使你的調用mysql_close()也是無法釋放資料庫連接的,那麼mysql中的死串連的數量就會越來越多了。
我認為,只有當你的應用屬於那種點對點方式,或者你能保證串連數量很少的情況,才有必要去採用pconnect的方式,因為串連數量少,那麼讓它一直處於串連狀態,避免了重複開啟關閉的過程。這樣可能會比傳統方式更好一些。
至於何時該去調用mysql_close(),最正確的做法是如果下面不再執行mysql的操作了,在你上一次執行完mysql操作後,立刻就調用mysql_close()。這才是最正確的做法,並不是總要把mysql_close()寫在頁面最後一行就可以了。