web應用性能優化經驗總結


 常見性能優化要求


     在我經歷的性能優化案例中,常見的問題都是這樣開始的:
     a) 前台訪問很慢,請幫忙分析優化
     b) 用戶對性能很不滿意,再不解決就要投訴
     c) 數據庫負載很重,請幫忙分析一下
     d) XXX功能打開需要1分鍾,請幫忙分析一下。而等我訪問這個功能的時候,可能幾秒鍾就返回;等你滿懷困惑的找到問題提出人員,如果足夠幸運的話,可能他告訴你要選擇什么查詢條件,問題能夠重現;當然另一個可能是他也是轉述用戶的話。
     在接到這些性能優化要求的時候,我都希望能夠了解下面的信息以判斷問題的類型,而通常情況下,我的工作都是在這些信息並不存在的情況下開始的
     a)系統性的問題? 比如CPU利用率,SWAP利用率或者IO過高導致的整體性能下降?
     b)功能性問題? 整體性能良好,個別功能時延很長
     c)新出現問題?什么時候開始的,之前系統有哪些變動?(升級或者管理的資源大量增加)
     d)不規律問題?有時候快,有時候慢,沒有特定規律
     還有性能快慢的衡量標准是什么?原來多少秒,現在多少秒,目標是多少秒?
只有上述問題得到了准確的回答,優化工作才能開始。
     而獲取上述答案的方法就是測量,有可靠的監控工具對用戶的訪問時延,系統的CPU,IO,SWAP進行准確的測量,當系統發生性能瓶頸時,系統當時的狀態,數據庫當時的狀態進行及時的記錄,依賴這些數據才能開始優化。
     案例1,天津客戶曾經有過投訴,系統經常性的出現整體性能下降,幾乎無法訪問的情況,而且發生的時間沒有任何規律。我部署了監控工具,3周后分析數據,發現訪問性能下降之前用戶都執行了某一個歷史告警查詢,而在此之后的數據庫性能曲線也急劇下降。研發人員對此功能優化后,問題再也沒有出現。
     案例2,南京客戶某主機經常崩潰,根據監控工具在崩潰前記錄的進程列表看,是某個程序掛起導致的進程越積越多,資源耗盡而崩潰,對該程序改進后,故障再未發生。
     只所以費這么多筆墨,就是希望能夠讓各位明白,沒有定量的測量,性能優化工作完全是空中樓閣,無法進行。而通過工具的部署和監測,今后我們提出的性能問題可能就是這樣:
     a) 系統整體負載正常,但/nms/res/devicelist_down.jsp目前經常出現35046毫秒的訪問時延,請協助排查一下
     b) 系統SWAP利用率經常會超過50%,這時候系統響應很慢,殺掉GetCGFlux.pl后恢復正常,請分析一下
     c) 或者數據庫服務器目前CPU利用率居高不下,已經持續了一段時間,請分析一下
如果性能優化工作以這樣的方式開始的話,這項工作就會變得輕松有趣得多了。
 
優化分析過程

1. 性能數據收集
     這一步是性能優化的基礎,如果問題系統之前沒有部署監控工具的話,那么就要部署監控工具,收集一段時間的數據后才能開始分析;當然也有例外,幸運的話,性能問題正在發生並且如此顯著,比如某個程序長時間無法掛起,或者某個進程把整台主機的CPU都吃掉,或者某個功能查詢很慢,次次如此。當然這種問題也就很少需要到我這,你就可以直接找開發人員解決了。
     很多情況,問題可能不是那么明顯,也不是那么規律,可能也涉及到系統的多項功能,這個時候,我們就必須要借助於工具來進行數據的收集。
2. 性能數據分析
     如果沒有數據收集,分析工作可能很神秘,完全依賴於專家的個人經驗。以前聽過一個故事,一個工廠的打印機總是莫名其妙的在某個時間出現故障,后來請了一個專家,搬了把椅子坐在打印機附近,幾個星期后,叫工人把地板的某個角修好,之后這個問題再也沒有出現。
     但是有了之前收集的數據,觀察CPU,IO,應用時延,網絡性能等不同指標的曲線,觀察問題出現的時間點,存在問題的功能,任何一個IT業者,都應該具備從這些數據中發現問題的能力。
例如某台采集機SYSLOG處理經常出現會滯后的情況。而這台機器的網絡丟包是這個樣子的,那么問題是不是顯而易見?
再比如有一個巡檢功能,數據某個時段總是大量入庫失敗,那你看到數據庫CPU和連接數在這個時段是這樣的,數據庫連接數增加,CPU空閑率為0,那么是不是問題也很明顯了。

3. 實施優化工作
     這一步主要是針對之前發現的問題,采取措施。可能是系統維護人員調整采集負載,讓負荷更均勻;或者調整主機或數據庫參數;當然更多的可能是程序需要優化
4. 評估優化效果
     譬如上述第二個例子,采取優化措施后,無論是網絡連接數還是數據庫主機負載,都已經很平穩,而問題也不再出現。
如果沒有達到,則不斷重復上述四步,繼續優化。
 
 
我的工具箱

這個工具箱是我常用的性能分析工具,曾協助我解決了很多的性能優化難題
a) web訪問時延監控工具AssayFilter
     部署在主應用上
     部署后可以在resin/logs/AssayFilter.log里面看到訪問時間,訪問的用戶,訪問的URL,時延毫秒,來源IP,據此我們就可以將用戶的感知定量化,數據化
     20150227094607 zengguojin /nms/res/devicelist_down.jsp 309356 219.159.77.116 ms
     20150209113913 zengguojin /nms/res/devicelist_down.jsp 383042 219.159.77.116 ms
     從這兩條數據里我們可以知道這個用戶在訪問這個功能時候遭遇過多次等待300多秒的情況,他又會有怎樣的滿意度呢?
     針對這個工具可能有人懷疑是否准確,是否統計時延過高是網絡延遲導致。這里解釋一下他的工作機制,
如下圖:     AssayFilter作為一個攔截器,統計的是訪問請求進入resin之后和應答離開resin之前的時長,訪問時延=resin處理時長+主應用到數據庫網絡時延+oracle的SQL執行時長
    主應用到數據庫都在一個交換機上,所以主應用到數據庫網絡時延可以忽略不計。
                                        [圖1]
 
     所以,這個工具完全避免了網絡延遲對訪問時延統計的影響,讓我們的精力完全聚焦在WEB應用自身的性能上.
b) 主機監控探針wd_probe
     部署在主機上
     這個監控探針除了能起到主機告警通知的作用,也是一個我依賴的性能分析工具,他能夠記錄各個時間點的CPU,SWAP,磁盤IO,網絡性能,進程數量,網絡連接數量的性能數據,當CPU超過預設閥值時會輸出系統當時的進程快照用於事后的分析。
     在探針主目錄的data/perf下有性能數據,在data/tmp下有系統進程快照
c) 數據庫超長SQL收集工具
     部署在主應用上,可以在cron里每分鍾執行一次
     這個程序會不斷捕捉執行時間超過6秒的sql,記錄進 /tmp/sql.csv文件中,運行結果如下:
     從發起端看可分為兩類,通常從APP發起的JDBC程序就是用戶前台訪問執行的SQL,而這種SQL執行時間超過6秒就是我們需要優化的SQL.
 
perl@unknown (TNS V1-V3) 2015/3/27 12:37 fuuk7dbrmsk47 2158 214293 select probeid,cfgfiledir,cfgfilename,to_char(lastgottime,'YYYYMMDDHH24MISS'),resid from cfgfilelist
JDBC Thin Client@pon-gx-app 2015/3/26 7:29 db6b71unjzah1 9 5      INSERT INTO RCHECKRESGROUPRES (PLANID,GROUPID,RESID,IPADDRESSA,RESNAME,NODECODE,NODENAME,NODEFULLCODE,
 
系統基礎問題檢查

1.  主機基礎故障問題
     磁盤空間是否空閑為0?
     SWAP利用率是否超過40%?
     CPU利用率是否長時間超過85%?
     網絡是否持續丟包?
     工作磁盤IO的利用率是否持續100%?
     上述狀況通常意味着系統有較嚴重問題,需要進一步從程序或者數據庫上查找原因。
2. resin的JVM檢查
Web應用的前台程序jsp和class都是運行在resin的JVM里,JVM(Java虛擬機)類似於oracle數據庫,jsp和class類似於SQL,都可以看作一個系統軟件,那么僅僅是看java進程在不在,前台能不能訪問是不夠的。就像沒有sqlplus,PLSQL我們就無法維護數據庫,同樣的JVM也有相應的維護工具,,都在JAVA_HOME/bin下
a. 查看JVM的內存占用情況
     jstat -gcutil <pid> 3s 5       
     這條命令間隔3秒鍾查看JVM的內存利用率,取樣5次,
     S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT  
  0.00  98.51  44.95  39.41  63.43      9    0.070     2    0.195    0.266
     永久內存區利用率63.43%, Elden和old區分別是44.95%和39.41%
b. 查看JVM的堆棧調用情況
     jstack <pid>
     這條命令把當前JVM里所有的線程調用堆棧輸出。在前台訪問無響應的時候,排查故障根源時特別有用。
上述Thread-831被38f06e88的線程所阻塞,而根據調用堆棧,可以准確的定位到執行程序,進行排查。
c. 查看錯誤日志是否有內存溢出錯誤
     日志在resin/logs/error.log或者resin/log/jvm-default.log
     如果有java.lang.OutOfMemoryError: PermGen space 說明JVM的永久內存區不足
                -XX:MaxPermSize=256m     可根據永久內存區利用率調整到256M
               java.lang.OutOfMemoryError說明JVM的堆內存不足
               -Xmx2048m -Xms2048m     把堆內存調大到2048G
     如果把Xmx加到2G,仍然會出現上述錯誤,那可能是有內存泄漏,需要開發人員排查
 
3.  數據庫檢查
oracle排查比較復雜,我只能從兩方面簡單舉幾個例子。
a)  系統參數層面優化
     1) sga是否充分利用了系統內存,sga可以配系統內存的一半. 而我遇到過主機64G內存,sga_target設置為5G
     2) db_cache_size最好在sga_target-3G,因為我們的程序很多沒有使用綁定變量,如果不設置db_cache_size,則漸漸的SGA都有被share_pool占用的趨勢,數據被緩存的越來越少,獲取數據需要從磁盤讀取,這樣整體性能肯定會下降。
      3) shared_servers設置為0,讓數據庫運行在專有模式而不是共享服務器模式
    雖然系統參數調整會在整體上帶來一定的性能改善,但相比於糟糕的SQL或者程序設計以及失效的索引和過期的統計數據對性能起到的作用,還是很有限的。
b)  應用優化層面
     1) 定位問題SQL
         這個SQL能夠列出數據庫當前正在執行的所有SQL,
select distinct s.sid,s.serial#,s.blocking_session,p.spid PID,to_char(s.logon_time,'YYYY-MM-DD HH24:MI:SS') logontime ,
substr(s.machine,1,15) smachine,substr(s.program,1,20) sprogram,q.sql_id,substr(q.sql_text,1,200) sql from v$sql q,v$session s,v$process p
where q.hash_value=s.sql_hash_value and q.address=s.sql_address  and p.addr=s.paddr
         基於兩個判斷標准我們能很快的找到問題SQL
        第一種是某個進程執行的SQL占用的CPU非常高,CPU利用率從Top命令獲得,進程ID即PID
        第二種是某類進程執行的SQL非常多,單個CPU不高,但合並起來就非常高了。
        針對SQL就可以找支撐人員進一步判斷是否需要找開發人員優化。
     2) 是否存在session被其他session阻塞的情況
          查看上一SQL結果的blocking_session字段,如果被阻塞的進程都被某一會話鎖定,需要把該session殺掉
          alter system kill session 'sid,serail#';
          遇到過幾次系統非常慢的情況,經查看都是開發或者維護用plsql把某表鎖住,導致相關會話都被阻塞
     3) 對該SQL所涉及的表進行表分析,更新其統計信息
 
性能優化非常精深,很多東西我也在學習,這篇文字,供大家分享。
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM