天天看點

從系統到web一層一層分析系統變卡的原因

從系統到web一層一層分析系統變卡的原因

現象:

兩周前不同客戶回報了幾次,狀态燈變紅,使用者的一切操作就很慢了,狀态燈是用于對狀态的标記,當正常傳回的時候是綠燈,非正常情況下則是紅燈。有些是涉密使用者無法檢視,非涉密使用者的就隻有一會,等會兒就消失了,無法正常跟蹤,無法很好重制,支援回報的也是,ie有問題。

過程:

我們的同僚都跟蹤了幾次,由于不是很好重制,是以不太好排查,并且根據回報的情況,每次IE都出現問題,firefox有時候出現問題。

系統資源情況:

top檢視如下,可以從top圖中看出,cpu基本可以忽略不計,記憶體還有200M左右,交換分區基本上沒怎麼用,基本可用,再加上buffer(用來存儲)和cache(用來存從記憶體讀取的),記憶體是沒有問題的(可用記憶體=free + buffers + cached),如果出了記憶體不夠的問題, demsg也可看出。

再檢視io也是正常的,系統情況一切正常;但是也能看到幾個python服務程式占用的記憶體很高,apache程序的記憶體在一直上升,可能是記憶體洩漏可能是請求在增加緩存增加。幾個小竅門,M按記憶體排序,P按cpu排序。

從系統到web一層一層分析系統變卡的原因

Postgresql:

轉到資料庫,檢視資料庫的狀态主要是兩個表,一個是pg_stat_activity,表示活動狀态,一個是pg_locks,表示資料庫的鎖狀态。一個是連接配接數挺少的,檢視鎖表和上鎖的表,隻有excluselock和accessshare模式的,excluselock隻能讀,但是沒有針對表的,插入表的資料也正常,可簡單實用這個方式測試selectt.relname,l.locktype,page ,pid,mode,granted from pg_locks l, pg_stat_all_tablest where l.relation=t.relid order by relation asc;結果如下圖:

從系統到web一層一層分析系統變卡的原因

當然也可變更一個字段插入,用于測試表的狀态,如插入task表:insert into task(name) select 'bb' from task limit1;

找出lock及執行的語句:selectl.pid,l.mode,sa.procpid,sa.current_query from pg_locks l inner joinpg_stat_activity sa on l.pid=sa.procpid;

Apache:

轉移到apache,通過httpd –s或者apache -s可以看出其工作方式是prefork模式,這種模式就會每個連接配接建立一個程序,通過如下的配置一路了然,最大連接配接數能達到150,根據ps -elf|grep :443來檢視,遠沒達到這個數。将MaxRequestPerchild改為非0,避免記憶體洩漏,另外沒請求的時候降低資源占用。

從系統到web一層一層分析系統變卡的原因

系統一切正常,隻能是代碼的問題或者是浏覽器的問題,這個時候請求使用者遠端協助,看到ie卡住了,firefox一切正常,不管怎麼操作都是正常的,按照常理來說應該是浏覽器的問題,于是将關注重點轉向IE,在網上也看到不少分析IE在ssl狀态卡的情況。

于是修改apache的配置,加上對IE的适配,關閉ssl的确認連接配接的發送(apache配置:BrowserMatch ".*MSIE [6-9]\..*" ssl-unclean-shutdown)。重新開機後半天都是正常的,以為就此解決了,可是一天後使用者回報不正常了,這個時候不正常的是firefox,在網上也沒搜到相關理論,反正不管是firefox還是IE,不管怎麼改,總有一個浏覽器是卡死狀态的,後來無意中看到使用者還有搜狗浏覽器,也啟動起,重新開機服務後觀察,這個時候搜狗也卡住了,我就懷疑不是浏覽器的關系,于是轉向代碼。

檢視通路日志,發現有分布式的請求和狀态欄的請求,為了分析友善,于是去掉了分布式連接配接,發現這些請求還有,那就隻有派出iptables了,将這些請求都幹掉,幹掉這些請求後還有問題,于是鎖定到狀态欄的請求代碼。

無意之中,看到請求的代碼都變成了對下圖中紅色的請求。

從系統到web一層一層分析系統變卡的原因

于是檢視那塊的代碼,這個周期性的請求是每隔30s發送一次的,并且是累積的,第一次請求是擷取系統狀态和更新包狀态,後面的則是隻請求系統狀态,與網絡無關,到了120次之後再請求一次系統狀态和更新包。但是使用者的網絡環境比較複雜,導緻請求更新包程式總不能正常結束,這樣計數器就沒有增加還一直在第一次,如此就進入了一個死循環,再加上js解析引擎處理的單線程特性,導緻其他請求被阻塞或者很久才能得到相應。在失敗和異常下都加上計數器,避免進入死循環,另外将setInterval改為setTimeout,這樣隻有請求結束了才會有下一次請求,不會導緻請求累積效應。具體相關函數如下:

下圖是ajax的處理請求的過程:

從系統到web一層一層分析系統變卡的原因

比較代碼如下:就是在異常和失敗情況下都給times計數器加一,避免進入死循環,另外就是setInterval改成setTimeout。

從系統到web一層一層分析系統變卡的原因

總結:

1,學會分離問題,将這些糾纏在一起的問題分離開來,一個一個突破,比如說分離系統,apache,postgresql的影響,比如說分離分布式和周期性狀态欄請求。隻從一個地方入手,這樣才能輕車上陣。

2,對于依賴延時來處理的邏輯一定要小心,很多時候不是預期,比如說遇到網絡延時,遇到系統資源瓶頸都會出現在意想不到的問題。

參考連結: