性能優化的常見概念html
吞吐量(TPS, QPS):簡單來講就是每秒鐘完成的事務數或者查詢數。一般吞吐量大代表系統單位時間能處理的請求數越多,因此一般但願TPS越高越好java
響應時間:即從請求發出去到收到系統返回的時間。響應時間通常不取平均值,而是要去掉不穩定的值以後再取均值,好比經常使用的90%響應時間,指的就是去掉了10%不穩定的響應時間以後,剩下90%的穩定的響應時間的均值。從聚類的觀點看,其實就是去掉離羣點。linux
錯誤率:即錯誤請求數與總請求數之比。隨着壓力增長,有可能出現處理請求處理不過來的狀況,這時錯誤數會不斷增長。ios
三者有極大的關聯,任何孤立的數據都不能說明問題。典型的關係是,吞吐量增長時,響應延遲有可能增長,錯誤率也有可能增長。所以,單拿出一個10w的TPS並不能說明問題。shell
性能調優的思路數據庫
通常狀況,調優須要有個前提條件,即不管是用線上的真實流水仍是線下的壓力測試讓問題擴大化,明顯化。瀏覽器
根據這些比較明顯的現象去初判問題,收集證據去驗證初判結果成立,而後分析現象產生的緣由,並嘗試解決問題。性能優化
1.性能摸底測試服務器
對於新上的系統或者是有過較大代碼改動的系統來講,作一次摸底測試仍是頗有必要的。通常來講,指望摸底的測試是一次對單機的壓力測試。壓力測試能夠幫你大概搞清楚系統的極限TPS是多少,在壓力上來時有沒有暴露一些錯誤或者問題,系統大體的資源佔用狀況是什麼,系統可能的性能瓶頸在哪。網絡
以下是一次摸底測試的配置和結果。這是用12000併發用戶對10臺機器壓測的結果,能夠看出,TPS到7w多,平均響應時間爲82ms,錯誤率在2.5%。
從圖中還能夠獲得哪些信息?首先,TPS在後期迅速下落,實際上已經支撐不了如此大的併發量,即進入崩潰區,這裏有幾個可能,一是系統根本承受不了如此大的併發量,二是系統中間有問題致使TPS下跌。其次,隨着時間增加,錯誤率顯著增長,說明系統已經處理不了如此多的請求。結合前面兩點以及相對平穩的平均響應時間,大體能夠推斷系統無法承受如此大的併發。另外,因爲是10臺機器,單臺的TPS大概在7000多,從此的調優能夠以此爲依據。
對於應用的特色,也要在這時候分析出來,即應用可能佔用的資源。好比是CPU密集型應用仍是IO密集型應用(還能夠細分爲是磁盤密集仍是網絡 )
2.定義性能優化的目標
常常聽到人說,作個性能優化,吞吐量越高越好;或者作個性能測試,目標TPS是50000。可實際拿到這個信息,可以作性能測試嗎?這個目標足夠清晰嗎?
事實上,在我看來,未定義清晰的目標去作性能測試都是耍流氓。
性能優化的目標通常是吞吐量達到多少,90%響應時間小於多少,錯誤率小於多少。同時還須要關注其餘的性能指標,cpu使用狀況,內存使用狀況,磁盤使用狀況,帶寬使用狀況等。對於摸底測試已經發現問題的,能夠針對該問題專門優化,好比負載較高,cpu消耗過大,則目標多是TPS,響應時間以及錯誤率不變的狀況降低低CPU負載。或者內存增加過快,gc較爲頻繁,則目標多是找出可能的內存泄露,或者進行相關的jvm內存調優。總之,目標能夠比較靈活調整,但必定要明確。
3.分析
分析的過程較爲靈活,基本上是一千個系統有一千種表現。這裏很難一一說明。僅談談一些常見的方法,工具以及思路。
針對CPU:
針對cpu的監控,其實linux已經提供了兩個比較好用的工具,一個是top,一個是vmstat。關於這兩個命令就不細說了,參考這裏top,vmstat 關於cpu主要關注4個值:us(user), sy(system), wa(wait), id(idle)。理論上他們加起來應該等於100%。而前三個每個值太高都有可能表示存在某些問題。
top
http://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/top.html
vmstat
http://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/vmstat.html
us太高:
a. 代碼問題。好比一個耗時的循環不加sleep,或者在一些cpu密集計算(如xml解析,加解密,加解壓,數據計算)時沒處理好
b. gc頻繁。一個比較容易遺漏的問題就是gc頻繁時us容易太高,由於垃圾回收屬於大量計算的過程。gc頻繁帶來的cpu太高常伴有內存的大量波動,經過內存來判斷並解決該問題更好。
小技巧:如何定位us太高的線程並查看它的狀態。
a. top命令找到消耗us太高的進程pid
b. top -Hp pid找到對應的線程tid
c. printf %x tid轉爲16進制tid16
d. jstack pid | grep -C 20 tid16 便可查到該線程堆棧
sy太高:
a. 上下文切換次數過多。一般是系統內線程數量較多,而且線程常常在切換,因爲系統搶佔相對切換時間和次數比較合理,因此sy太高一般都是主動讓出cpu的狀況,好比sleep或者lock wait, io wait。
wa太高:
a. 等待io的cpu佔比較多。注意與上面狀況的區別,io wait引發的sy太高指的是io不停的wait而後喚醒,由於數量較大,致使上下文切換較多,強調的是動態的過程;而io wait引發的wa太高指的是io wait的線程佔比較多,cpu切換到這個線程是io wait,到那個線程也是io wait,因而總cpu就是wait佔比較高。
id太高:
a. 不少人認爲id高是好的,其實在性能測試中id高說明資源未徹底利用,或者壓測不到位,並非好事。
針對內存:
關於java應用的內存,一般只須要關注jvm內存,但有些特殊狀況也須要關注物理內存。關於jvm內存,常見的工具備jstat, jmap, pidstat, vmstat, top。
jvm內存:
異常gc :
a. 一般gc發生意味着總歸是有一塊區域空間不足而觸發gc。而許多致使異常gc的狀況一般是持有了沒必要要的引用而沒有即時的釋放,好比像cache這樣的地方就容易處理很差致使內存泄露引起異常gc。
b. 有多是程序的行爲是正常的,可是因爲沒有配置對合適的gc參數致使異常gc,這種狀況一般須要調優gc參數或者堆代大小參數。
c. Full gc 發生的狀況:
永久代滿
年老代滿
minor gc晉升到舊生代的平均大小大於舊生代剩餘大小
CMS gc中promotion fail或concurrent mode fail
OOM:
a. OOM常常伴隨着異常gc,之因此單獨拿出來說,是由於它的危害更大一些,異常gc頂可能是收集速度過快或者回收不了內存,可是起碼有個緩衝時間,可是出了OOM問題就大了。至於各類類型的OOM如何區分,如何發生,請參考這裏(http://www.jianshu.com/p/2fdee831ed03),算是總結得比較全面的。對於常見的OOM,基本上能夠一會兒指出問題所在。
b. heap區,對象建立過多或持有太多無效引用(泄露)或者堆內存分配不足。使用jmap找到內存中對象的分佈,使用ps找到相應進程及初始內存配置。
c. stack區, 不正確的遞歸調用。
d. perm區,初始加載包過多,分配內存不足。
e. 堆外內存區,分配ByteBuffer未釋放致使。
針對IO:
IO分爲網絡IO和文件IO,針對網絡IO比較有用的工具備sar(https://linuxstory.org/generate-cpu-memory-io-report-sar-command/),netstat(https://linux.cn/article-2434-1.html),netstat是一個很是牛逼的命令,能夠助於排查不少問題, 針對文件io的工具備pidstat,iostat(http://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/iostat.html)
文件IO:
a. 從技術上來講,對於大文件IO能夠採起的措施是異步批處理,採用異步方式用於削峯並累計buffer,採用批處理可以讓磁盤尋道連續從而更加快速。
網絡IO:
網絡IO的問題較爲複雜,僅舉幾個常見的:
a. 大量TIME_WAIT。根據TCP協議,主動發起關閉鏈接的那一方,關閉了本身這端的鏈接後再收到被動發起關閉的那一方的關閉請求後,會將狀態變爲TIME_WAIT,並等待2MSL, 目的是等待本身的回執發送到對方。若是在服務器上發現大量TIME_WAIT,說明服務器主動斷開了鏈接,什麼狀況下服務器會主動斷開鏈接,極可能是客戶端忘了斷開鏈接,因此一個典型的案例就是jdbc鏈接忘記關閉,則數據庫服務器可能會出現大量的TIME_WAIT狀態。
b. 大量CLOSE_WAIT。CLOSE_WAIT狀態,在收到主動關閉鏈接的一方發出關閉鏈接以後,被動關閉的一方進入CLOSE_WAIT狀態,若是這時候被hang住了沒進行後續關閉,則會出現大量CLOSE_WAIT。啥狀況會被hang住呢,舉幾個例子,好比剛剛的忘記關閉數據庫鏈接,在應用服務器這端,大量的瀏覽器請求進來,因爲沒有鏈接池鏈接被hang住,這時候瀏覽器等待必定時間超時發送關閉鏈接請求,而應用服務器這邊因爲servlet線程被hang住了,天然沒有辦法走第二個關閉回去。所以在應用服務器出現大量CLOSE_WAIT。另外一個例子是httpClient的坑,在調用response.getEntity(); 前都不會作inputStream.close(),若是在調用response.getEntity()前就返回了,就狗帶了。(這個例子能夠參考http://blog.csdn.net/shootyou/article/details/6615051)
4.優化並從新測試驗證
性能調優思路 http://www.voidcn.com/blog/bigtree_3721/article/p-5786972.html
linux下性能監控命令 http://linuxtools-rst.readthedocs.io/zh_CN/latest/advance/index.html
關於JVM CPU資源佔用太高的問題排查 http://my.oschina.net/shipley/blog/520062
java排查工具 http://my.oschina.net/feichexia/blog/196575
jvm參數調優 http://www.cnblogs.com/java-zhao/archive/2016/02/08/5185092.html
java linux系統調優工具 https://www.ibm.com/developerworks/cn/java/j-lo-performance-tuning-practice/
gc優化的一些思路 http://mm.fancymore.com/reading/gc%E4%BC%98%E5%8C%96%E7%9A%84%E4%B8%80%E4%BA%9B%E6%80%9D%E8%B7%AF.html
性能優化的思路和步驟 http://www.uml.org.cn/j2ee/201602013.asp
性能調優攻略 http://coolshell.cn/articles/7490.html
JVM性能調優入門 http://www.jianshu.com/p/c6a04c88900a
JVM性能調優 http://blog.csdn.net/chen77716/article/details/5695893
Tomcat性能優化 https://yq.aliyun.com/articles/38861?utm_campaign=wenzhang&utm_medium=article&utm_source=QQ-qun&2017323&utm_content=m_14698