一次B S架構系統的調優實踐

2021-09-05 11:54:52 字數 2685 閱讀 6381

需調優的系統採用b/s架構,apache2+php5.6+thinkphp3.2 +mysql5.6+redis

系統部署時web伺服器與mysql資料庫伺服器是分開的兩台虛擬機器,都是windows server 2008作業系統。

開始時懷疑apache伺服器併發壓力大,開啟伺服器檢視,硬體沒有什麼壓力,16g記憶體占用1/8左右,cpu占用10%以下。檢查伺服器連線數 40個左右,沒有什麼併發壓力。

apache+php開始用的是預設的php_mod方式,後來改為用fcgid(fast cgi)方式,用loadrunner做簡單壓力測試,承受併發的能力有所增強,但頁面卡慢現象沒有改善。

經以上檢查初步排除硬體資源不足與web伺服器壓力過大的原因。

觀察瀏覽器頁面出現的卡慢現象,用瀏覽器自帶的開發者工具,發現靜態資源的載入時間都是ms級,但php的載入在卡慢時,waiting(ttfb)時間會達到幾十秒甚至幾分鐘,卡慢現象非常嚴重,卡慢的原因是php執行時間太長。開發時沒有出現這種情況,但在上線時卻出現了,說明還是有併發衝突。

在觀察mysql資料庫伺服器的資源情況時發現cpu占用很低,記憶體占用很低,磁碟i/o速率也不高。但「磁碟最長活動時間」卻長時間保持在100% ,初步分析有大量的小的隨機讀寫。懷疑mysql資料庫的執行有問題。於是開啟mysql的慢查詢日誌,慢查詢的門檻時間設定為2s(備註:mysql預設未開啟慢查詢日誌,開啟慢查詢日誌的方法在網上很容易找到)

在慢查詢日誌中果然發現了大量的慢查詢語句,有select語句、insert 語句和update語句,很多語句的查詢時間為幾十秒至上百秒。由此工作重點轉向了如何解決這些慢查詢。

對innodb來說,select語句不應該鎖表,為什麼會出現慢查詢呢?

經與開發人員溝通,可分為幾類情況進行處理

1 開發人員為了產生唯一的流水號,採用了 select max(***) from *** for update 的方式,這樣一來就形成了表鎖,與開發人員溝通後流水號用redis產生,去掉了所有的select … for update語句;

2 按理說update 與 insert 都應是很快的,但在慢查詢日誌中出現了update 語句查詢時間上百秒,檢查資料行上億條,一開始真是百思不得其解,後與開發人員深度溝通才找到原因。原來開發人員為了提高查詢效率,做了偽物化檢視處理,在update與insert時加上了觸發器,在觸發器中呼叫儲存過程,儲存過程中查詢乙個很複雜的檢視後,刪除過時的資料,插入新的資料到偽物化檢視。由於查詢語句未做優化,導致查詢時間很長,從而引起update語句的執行時間超長,檢查資料行數超多。經優化相應的查詢語句,並且優化了觸發條件,避免不必要的觸發器呼叫。update與insert的執行時間回到了1s以內。

3 複雜的select語句,由於查詢的是層層巢狀的檢視,每層檢視中又經常出現left join等,導至大量的全表掃瞄,查詢複雜度很高。對這一類select語句,只能在分析業務的基礎上做優化,優化的基本原則是早過濾,晚連線,避免查詢不必要的資料,避免不必要的連線;盡量使用索引,避免全表掃瞄。這類工作只能具體問題具體分析,在實踐中摸索經驗。經調優後,查詢時間都減少到ms級甚至更低。

經過以上調優後,資料庫i/o壓力明顯減小,慢查詢日誌中相應的慢查詢語句消失。

在調優過程中還有幾件值得記錄的事情

2.在慢查詢日誌中發現了大量的 show columns from ,經分析這是thinkphp造成的,應設定db_fields_cache=true ,這樣就不會頻繁地呼叫 show columns from。

按理說show columns from執行也很快,為什麼會出現在慢查詢日誌中呢?原來開發人員為了檢查使用者的許可權,在控制器的基類中執行了對user表的查詢,導致大量的select * from user …操作,而在沒有設定db_fields_cache=true情況下導致了大量的 show columns from user, 經實驗大量併發的show columns from 會導致一些語句在 opening tables階段阻塞,時間可以長達30s以上。為此開啟了mysql的查詢快取,使得大量重複的select * from user …查詢可以從快取中取值(備註:mysql的查詢快取並不是越大越好,太大了由於其上的全域性鎖可能會導致update ,insert 語句變慢,甚至會使得相應的select 語句在sending data 階段阻塞)

需要補充說明的是設定db_fields_cache=true後,如果以後資料表字段發生了變化,部署時要注意清除過時的快取。

4.考慮到mysql伺服器的i/o負擔重,可以針對mysql的一些記憶體引數做調整,原則就是盡量地通過快取減少對磁碟的讀寫。記憶體引數的設定網上相關文獻很多,這裡就不再詳細說明。

5.頁面的卡慢除了後台php與mysql的原因外,前端的瀏覽器上的js**如果不夠優化,也可能導致卡慢,這個問題打算以後專門說明。

6.瀏覽器與後台伺服器的連線數有限制,因此在乙個頁面上有很多ajax在請求時,可能會有阻塞的現象發生,開啟瀏覽器的開發者工具時應該看到stalled 時間很長而不是waiting時間很長。有乙個小現象也值得記錄一下。由於php的會話資料預設儲存在檔案中(備註:不同的會話id對應不同的檔案),而在讀寫會話相關的檔案時會加檔案鎖,thinkphp的控制器方法缺省會開啟會話,如果這個控制器方法執行時間很長,如果不主動提交會話,則在控制器方法執行完成後才會自動提交會話。在這個過程中檔案鎖會一直存在並阻塞對同乙個會話檔案的操作。因此同乙個使用者在用多個ajax請求或者在同乙個瀏覽器中開啟了多個頁面時可能會出現卡頓現象。這種卡頓是由於瀏覽器的連線數限制或者會話相關操作的檔案鎖造成的,與mysql無關,在調優時應注意區分是前端原因造成的,還是後端原因造成的卡慢。

一次oracle調優經歷

修改oracle archive mode需要注意的地方 當時沒有記錄下具體的東西。現在寫一下 我的測試機經常死。win2k oracle 92 1 檢視alert sid.log 日誌。沒發現問題。2 為資料庫做statspace,峰值大約在早10點和下午3點左右。做了兩個statspace。看,...

MYSQL一次調優經驗

前言 這是最近剛發生在公司的一次應用系統的mysql調優過程,事情的過程是這樣的 公司的乙個銷售系統,用的是mysql資料庫,在元旦的前夕突然就宕機了。差不多導致業務系統4個小時左右使用有問題 因為這個系統乙方公司尚未完全交付,所以資料庫的運維的工作,作為甲方也還未交接到我的手上,這個事情也是元旦過...

一次redis調優的過程

記錄一次redis調優的過程,這次事故主要是測試組人員那邊 在給我們測試的時候發現的,有個介面返回資料特別慢,之後我們就去排查問題,結果就發現了是 redis的延遲問題。那究竟是怎麼回事呢?請看下面 介面返回特別慢,檢視了伺服器列印的日誌,發現是redis的問題 根據日誌的提示,找到 中用到redi...