開發的系統中出現大量資料庫sleep狀態的空連接,同時透過Log發現系統中透過php的curl請求第三方API介面的回饋出現大量異常,不由得把2者連結起來分析原因。日誌反應第三方介面回應緩慢,且結果為空,原因不明,但是能想像到php發出curl請求後一直等待連線返回,等待過程中資料庫連線開始sleep,直到curl超時,進程執行完畢資料庫連結得以釋放。
1. php+mysql+memcache實戰型技術測試
出兩個變態的題目,題目很變態,但是都是實戰中遇到的真實案例,
1:我寫一個程序,既要使用mysql也要使用memcache,
第一行是mysql_connect,第二行是memcache_connect
換過來寫,第一行是memcache_connect,第二行是mysql_connect
caoz發現實務上這兩種寫法有很大的差別,差別在哪裡?
2:我寫一個程序,使用了mysql,產生了一個頁面最後用echo $html; 輸出
一種寫法是
mysql_close();
echo $html;
另一種是
echo $html;
mysql_close();
caoz發現實務上這兩種差異很大,差別在哪裡?
兩個全是實踐中發現並調整的案例。
caoz寫程式不是追求BT的人,caoz經常和工程師強調,不追求極端的技術體現或技術炫耀,所以,如果讀者認為這裡的題目是為了所謂的諸如某個寫法比某個寫法資源開銷小一點或其他什麼,那麼這真不是caoz的本意。
這兩題都是在真實營運環境中遇到的典型案例,典型在哪裡呢?就是當你遇到一個系統故障的時候,你怎麼分析,怎麼思考,怎麼判斷多種關聯因素的影響,所以這個題目答出答不出並不重要,重要的是怎麼思考系統彼此的關係。
一個典型的系統故障是, mysql 連接過多,或者說too many connections,這個問題困擾了我們很久,如果這是因為索引導致的,或者因為數據並發請求導致的,定位到原因並不複雜,但是當上述問題解決後,詭異的現象發生了,資料庫幾乎沒有壓力,沒有阻塞進程,沒有慢查詢,但是mysql連接很多,而且都是sleep連接。此時,webserver的連結也很多,換句話說,因為php執行阻塞,導致mysql連結無法迅速釋放,那麼,php為什麼會阻塞? 逐一斷點分析發現,原來echo耽誤了最多時間。
這個事情讓caoz漲了點經驗,之前從來不會認為echo是一個時間阻塞點(如果你在本機測試,你會認為其時間延遲幾乎是0),但是實例跟踪發現, echo實際上在我們的工作環境中,代表的網路傳輸的過程,換言之,會因為路由,頻寬的因素而等待,而此時,mysql的連結還在那裡沒有釋放,是的,看到題目每個人都會想到,mysql_close要放在echo後面,但為什麼echo會耽誤時間,很少人會想到。當然,這也跟工作環境有關,caoz只知道我們配置的webserver會有這種情況,是不是存在其他的配置模式,caoz沒有實測,不敢亂說,但是這裡的經驗是,mysql_close放到echo前面,大量的sleep連結會迅速減少。
echo並不耗費太多系統資源,但是會等待網路傳輸,在高並發的網路環境下,注意這一點對資料庫很有好處。
這個問題解決後,mysql健康了很多,但是偶然還會出現鏈接過多的問題,又困擾了很久,直到有一天,根據用戶反饋的一些錯誤信息,發現memcached伺服器有不穩定因素,原來是memcached流量過高產生阻塞,php進程等待鏈接,導致mysql鏈接大量等待,這是第一個題目的由來,其實這個題目本身沒有標準答案,但是應該有一個意識,當你在一個腳本中同時啟動A,B兩個鏈接,那麼如果你不能保證這兩個鏈接是必然可靠的(通常是無法保障的),那麼後者一旦阻塞,就會導致前者大量鏈接等待,而前者阻塞,通常不會影響後者。所以,這個答案取決於,哪個連結對你的應用程式更重要,以及哪個連結有更大的並發支撐性。
兩題說到底就是一個意思,當遇到系統問題和故障的時候,多想想一些關聯的因素影響,多思考整個架構響應先後過程的邏輯,資料庫連接過多,不一定是資料庫造成的,web連結過多,也不一定要去優化webserver,關聯因素可能才是根源,解決了根源,表象才會徹底解決。
2. 減少MySQL的Sleep流程有效方法
1,通常來說,MySQL出現大量Sleep進程是因為採用的PHP的MySQL長鏈接數據庫方式,即使用了mysql_pconnect來打開鏈接數據庫,解決辦法就是使用“短”鏈接,即mysql_connect函數。
2,在使用mysql_connect短連結方式開啟資料庫,每個頁面在開啟資料庫後,執行SQL完成,當頁面腳本結束的時候,這個MySQL連線會自動關閉並且釋放記憶體。但仍出現大量Sleep進程,可以看看網站是否有以下幾個方面的問題。
A,硬碟上存在大量的靜態文件,或者WEB伺服器負荷太重,在處理HTTP請求響應變得太慢,這樣也有可能導致出現大量Sleep進程,解決方法適當調整WEB服務參數和文件,一味的靜態或快取化網頁內容並不是靈丹妙藥。
B,在網頁腳本中,有些計算和應用可能非常耗時,例如在0秒的時候打開資料庫執行完一段SQL程式碼後,網頁腳本隨即花了20秒鐘進行一段複雜的運算,或者是require了一個龐大的PHP檔案(例如含有幾千個違規關鍵字的過濾函數),哪麼這個時候在MySQL後台看到的進程中,這個20秒的過程MySQL並沒有做任何事情了,一直處於Sleep狀態,直到這個頁面執行完畢或達到wait_timeout值(被強行關閉),優化網頁腳本,盡量讓程式快速運行,或者在執行這段耗時的運行過程中,執行mysql_close把當前MySQL連結強行關閉。
C,在採集站中,MySQL中大量的Sleep進程這類現象尤其明顯(例如許多網友問DeDeCMS的MySQL中出現大量Sleep),因為大部的採集器頁面在運作過程中,事先打開了一個MySQL連結(可能是為了驗證使用者權限等),然後開始使用file_get_contents之類的操作去取得一個遠端的網頁內容,如果這個遠端的網站存取速度太慢,例如花了10秒時間才把網頁取回,哪麼目前採集腳本程式就一直阻塞在這裡,而且MySQL啥事也沒幹,一直處於Sleep狀態。解決方法同上,在發出file_get_contents採集遠端網頁的時候,使用mysql_close強行關閉 MySQL的連接,等採集完成在適當需要的時候再重新mysql_connect即可。
以上是如何減少php與mysql中的sleep的空連線進程的詳細內容。更多資訊請關注PHP中文網其他相關文章!