這篇文章是關於網站性能優化體驗的,性能優化是一個複雜的話題,牽涉的東西很是多,我只是按照個人理解列出了性能優化整個過程當中須要考慮的種種因素。點到爲止,包含的內容以淺顯的介紹爲主,若是你有看法能告知我那再好不過了。不管如何,但願閱讀它的你有所收穫。html
我眼中的網站性能問題都反映了一個網站的「Availability」(中文叫作可用性,可是這個翻譯也不足夠達意),以往個人認識是,這個網站若是所有或者部分不可用,那是功能問題,可是若是響應慢、負載差,這纔是性能問題;但是後來我逐漸意識到,性能問題涵蓋的範圍更廣,我還無法給出一個準肯定義,可是許多非業務邏輯錯誤引發的網站問題均可能能夠算作性能問題,好比可擴展性差,好比單點故障問題。前端
在網站性能優化的最初階段,也就是所謂的「第一重境界」,作局部的定位、分析和修正,考慮的僅僅是「優化」,這也是初涉性能優化問題的大多數人的認識。在問題發生之後,發現它和業務邏輯沒有太大關係,就開始嘗試尋找問題產生的緣由並加以解決。java
不管是網站無響應仍是響應緩慢,仍是響應曲線異常波動,好比,能夠圍繞CPU的使用問本身這樣幾個問題:程序員
在這些問題中,狀況雖然變幻無窮,簡單地說,CPU的使用是核心,CPU使用率高,說明系統資源被充分利用,可能系統在實實在在地作事,反之,須要尋找其餘瓶頸。經過結合進程、線程的快照,來初步肯定問題的範圍。CPU使用率低的狀況居多並且容易定位,只須要尋找其餘的系統瓶頸;CPU佔用率偏高的問題每每比較不容易定位,雖然也有一些辦法。關於具體性能問題的定位技術,這裏不着過多筆墨,後續有機會詳細介紹。數據庫
對於一個剛開始作性能優化的網站系統,下面的事情不妨都作一作,會有立竿見影的效果:apache
若是你須要系統的指導,不妨參考這張圖(點此下載大圖和mmap文件:Site_Performance_Practice_Road_Map):瀏覽器
從使用的工具上說,性能問題的定位很大程度上是面向操做系統、虛擬機系統的問題定位。從問題定位的時機上說,又能夠分爲:緩存
瞭解到這裏,再給出這樣幾個常見問題定位的場景:安全
第一類:請求無響應,瀏覽器始終處於等待狀態。性能優化
定位方法:kill -3或者jstack先分析線程堆棧,找到當前block的線程。
常見於:外部接口調用無返回或者網絡IO阻塞無響應;死鎖;死循環;……。
第二類:宕機,進程掛掉。
定位方法(這一類問題廣泛比較難定位):
(1)尋找hs_err_pidxxx.log這樣的JVM日誌
(2)使用JVM參數在JVM crash時寫入到dump文件中
(3)catalina.out中尋找最後的日誌
(4)宕機前環境數據採集
常見於:JDK bug(數次遇到過JIT引發的這一類問題);調用dll的問題;……
第三類:請求響應時間長。
定位方法:kill -3或者jstack先分析線程堆棧,看線程大都停留在什麼操做上面,再細化分析。
常見於: 內存不足,可見到連續的Full GC;網絡擁塞;LoadRunner等壓力客戶端瓶頸;數據庫瓶頸,可進一步分析DB快照;……
第四類:TPS低;TPS逐漸下降;TPS振盪幅度過大。
定位方法(這一類問題最多見,定位的方法也最複雜):
首先觀察在壓力增大時,CPU使用率可否上去,若是不能上去,尋找其餘瓶頸:網絡/內存/磁盤/……;CPU
使用率上去了,觀察在無壓力時,是否有背景CPU使用(例若有後臺定時任務線程消耗了大量CPU資源),若是沒有,那能夠嘗試JProfiler等工具結合線程分析、業務分析,尋找熱點。
常見於:其餘業務線程干擾;內存泄露;鏈接句柄用完;緩存命中率低下……
好,暫時說到這裏,下面來看第二重境界。達到這重境界意味着已經可以跳出「過後優化」的侷限了,在設計和編碼的過程中,可以正式和全面地考慮性能的因素,好比:
對於不成熟的團隊,建議能安排有經驗的程序員把關設計文檔和編碼中的性能問題,把常見的問題列出來參考學習。
達到第二重境界還有一個明顯的特徵,就是在軟件流程的前中期就開始作性能目標的論證和性能問題的驗證:
最後是第三重境界。達到這重境界的團隊可以在早期規劃構想階段就將性能做爲一個必備因素包含在內,這可不是隨口說說的經驗的估計,而是要有數據驅動的理論設計,好比作性能建模,根據市場大小、業務量、服務等級等等計算出性能的具體指標,而且在此要求下作合理的架構設計。
這裏涉及的東西有不少,除了數據,還須要有大量的思考,對於一個網站來講,不妨問問以下的問題:
全部的性能問題和其餘一切非功能性問題同樣,都是必定程度上的trade off,因此越優秀的設計者越須要思考,來規劃這些問題的解決方案,在規劃中由於性能問題而涉及到的因素有哪些,太多太多了。
而要解決這樣在規劃中就預料到的性能問題,也有許多內容值得討論,下面列出一些供參考:
要達到第三重境界還要可以預測性能問題。這就須要成熟的監控體系,監控系統的變化,儘快作出反應。
好比國內發生了重大事件,用戶量陡增,監控系統可以及時識別出用戶量監控曲線一個很是明顯的跳躍過程(好比持續事件超過某個值,且曲線斜率超過某個值),發出告警,而且自動擴容來應付潛在的風險。這些,都是創建在常規的業務運營數據收集基礎之上的,而後須要作數據挖掘,給出關鍵點。
再好比互聯網應用「緩存爲王」。對於緩存的設計,甚至很大程度上決定了應用的成敗(若是你頗有錢,靠大量的CDN這種很是規路線的另說,呵呵)。緩存的設計須要考慮到緩存的大小、分級、隊列、命中率計算、生命週期、更新換頁、數據分發、數據一致性和數據持久化等等問題,這些東西每每被不少只重視那些頁面展現效果和功能的人所忽視,但若是你是優秀的設計者,你須要積累這些思考。
Think big。有這樣一個真實的例子,咱們曾經發現頁面模板的OGNL性能不高(兩次反射之故),遂在項目中把大部分OGNL表達式都改爲了EL表達式,花了不少時間精力,性能也確實提升了,可是能提升多少呢?大概只有30%,這是一種細水長流的改進,對系統的破壞性不大,可是收效也不足以使人沾沾自喜,還失去了一些OGNL的靈活性。以後,咱們換了一個思路,從大局入手,給頁面劃分區域,定製緩存框架,引入頁面緩存能力,雖然整套方案有些複雜,可是這種架構上的進化,因爲頁面的生成或者部分生成直接命中了緩存文件,性能一下有了飛躍,提升了600%~800%。這就是Think big,從大處着想,見獲得工程大塊的結構,須要足夠的視野、足夠的經驗和積累,能夠帶來顯著的效果。
一般系統容量的設計都會要求到峯值容量以上,若是是像秒殺、搶購之類對性能要求很是高的系統,每每還存在一個問題:設計了這麼大的容量,平時大部分時間業務量都比較小,這些資源浪費怎麼辦?(題外話:這大概也是Amazon涉足雲存儲和雲計算的初始原因吧)
咱們來看這樣一個在性能驅動下架構變遷發展的例子:
初期,只有簡單的應用服務器和DB服務器分家,使用簡單的Jetty容器,系統的瓶頸在DB側。簡單就是美,網站剛剛運營,能訪問就是王道:
系統在發展中不斷地演化。
有一天發現用戶壓力愈來愈大,終於沒法承受了,系統屢屢到達崩潰的邊緣,在現有硬件和架構條件下很難支撐現有的業務,作出了這樣的改變:
在此次改變中,作了這幾件重要的事情:
網站繼續安安靜靜地發展,悄悄地演化。
終於有一天,用戶訪問量激增,百萬級的PV達到了,WEB2.0業務也增長進來,緩存的命中率愈來愈低,CPU成爲了瓶頸,訪問異常緩慢。這一次,又要動刀了:
這一次的架構重構作了這麼幾件重要的事情:
繼續、繼續……
訪問量增加了幾十倍,集羣的服務器也第一次達到了三位數,系統不穩定,速度從新落下,問題定位也無比困難,一切又開始撲朔迷離起來。
這一次,不可避免地又作了架構上的調整,首要的目標,是以隔離解耦的方式增長系統穩定性,同時,更便於產品化管理:
最後要說的是,如你所見,性能因素是一個網站系統發展的其中一個重要推進力,再細緻的思考也難以兼容那麼多未知的場景,不妨多在擴展性和兼容性上下下功夫,避免網站冷清痛苦,網站大熱更痛苦。