1.優(yōu)化思路
做優(yōu)化首先要知道從哪里入手荞估,也就是要知道系統(tǒng)的瓶頸在哪里貌笨。一個請求會消耗很多資源:CPU弱判、內(nèi)存、網(wǎng)絡锥惋、磁盤等裕循。這些資源中總會有一個到達瓶頸,只有優(yōu)化最先到達瓶頸的資源才會產(chǎn)生效果净刮。
壓測工具
Java有兩個經(jīng)典的代碼熱點分析工具:JProfiler和Yourkit
Apache ab壓測工具
發(fā)現(xiàn)瓶頸
Jstack剥哑,可以看看當前的Java線程
壓測請求不是本機,要注意TCP連接數(shù)淹父,可以使用netstat命令
檢查網(wǎng)卡是否達到了瓶頸
I/O也可能成為瓶頸
2.影響性能的因素
所謂提升性能株婴,通常意義上就是提升系統(tǒng)的QPS,即提升系統(tǒng)的吞吐量暑认。
要提升系統(tǒng)的QPS困介,首先要了解QPS與RT的關系。
QPS與性能的關系
影響線程數(shù)量的兩個主要因素是CPU數(shù)量和線程等待時間蘸际。
對于大部分的Web系統(tǒng)座哩,RT(response tiime)一般由CPU執(zhí)行時間和線程等待時間(遠程RPC調(diào)用、I/O等待粮彤、sleep根穷、wait等)組成姜骡。
減少CPU的執(zhí)行時間對QPS有實質(zhì)的提升,減少線程的等待時間對QPS提升不明顯屿良。
設置最佳線程數(shù)
所謂最佳線程數(shù)是指消耗完服務器的瓶頸資源的一個臨界線程數(shù)量圈澈。
最佳線程數(shù)=[(線程等待時間+線程CPU時間)/線程CPU時間]/CPU數(shù)量。
如何才能獲取最佳線程數(shù)尘惧?
第一康栈,單用戶壓測,查看CPU的消耗的百分比喷橙,然后直接乘以該百分比啥么,再進行壓測。
第二贰逾,通過慢慢增加并發(fā)請求來進行性能壓測悬荣,通過觀察壓測結(jié)果判斷是否達到服務器的資源瓶頸,以獲得最佳線程數(shù)量似踱。
最佳內(nèi)存設置
處理并發(fā)請求要考慮內(nèi)存的設置,即每個請求需要消耗多少內(nèi)存稽煤、并發(fā)請求書乘以消耗的內(nèi)存就是總內(nèi)存的大小核芽,如果設置的內(nèi)存小于這個數(shù),就會導致頻繁的Full GC酵熙。
如何判斷是否達到內(nèi)存瓶頸轧简?壓測時觀察Old區(qū)內(nèi)存增長是否正常。
如何計算出每個請求平均占用的內(nèi)存大小呢匾二?理論上通過Eden/(QPS * minorGC的平均間隔時間(s))來計算哮独。
如何減少每次請求中占用的內(nèi)存大小呢?
盡量減少線程請求生命周期里的對象數(shù)量察藐。
對象創(chuàng)建到可回收的時間要盡可能短皮璧,例如不要在非常耗時的操作前面創(chuàng)建一個大對象,而盡可能在真正使用這個對象時再創(chuàng)建分飞,對象使用完成后也要盡量置空悴务。
如何提升性能
如果要提升服務器端的響應時間RT,采用減少I/O的時間能達到最佳效果譬猫,比如合并多個I/O請求讯檐。
如果要提升QPS,采用優(yōu)化CPU的時間能達到最佳效果染服。
3.Java特性的優(yōu)化
比如别洪,常用StringBuilder、優(yōu)化自定義hashCode()柳刮、equals()挖垛、toString()方法痒钝,優(yōu)先使用原始數(shù)據(jù)類型,不在循環(huán)中使用try…catch晕换,copy時使用System.arraycopy()命令午乓。
減少編碼
使用局部變量
減少方法調(diào)用
4.減少并發(fā)沖突
并發(fā)沖突往往會導致程序性能上不去,成為性能瓶頸闸准。
容易出現(xiàn)并發(fā)的地方一般都會用鎖益愈,判斷是否出現(xiàn)鎖沖突要查看CPU沒用滿的情況下QPS是否還能上去,可以通過jstack檢查線程是否都在block狀態(tài)夷家。
5.減少序列化
序列化也是Java性能的一大天敵蒸其,減少Java中的序列化操作也能大大提升性能。
序列化大部分是在RPC調(diào)用中發(fā)生的库快,因此避免或者減少RPC的調(diào)用就可以減少序列化摸袁,當然當前的序列化協(xié)議已經(jīng)做了很多優(yōu)化提升性能。
6.減少字符到字節(jié)的轉(zhuǎn)換
每個字符的編碼都需要查表义屏,而這種操作非常耗CPU資源靠汁,所以減少字符到字節(jié)的轉(zhuǎn)換或者相反、減少字符編碼會非常有效闽铐。
讀取靜態(tài)文件蝶怔,一般情況下,我們會把靜態(tài)文件讀取到內(nèi)存兄墅,以減少每次從磁盤讀文件的消耗踢星,但是還可以進一步做的就是把這個靜態(tài)文件直接轉(zhuǎn)化成字節(jié)緩存,也就是把String經(jīng)過編碼轉(zhuǎn)換成byte[]數(shù)組隙咸,當然我們輸出的時候要用stream輸出而不是用out.print()沐悦。
7.使用長連接
在內(nèi)部調(diào)用中,會有一些HTTP請求五督,大部分情況以短連接為主藏否。
8.總結(jié)
a、發(fā)現(xiàn)短板
主要考慮以下場景會受到一些限制:光速充包、網(wǎng)速秕岛、網(wǎng)絡結(jié)構(gòu)和應用本身的一些瓶頸等。
b误证、減少數(shù)據(jù)大小
有兩個地方特別影響性能继薛,一是服務端在處理數(shù)據(jù)時不可避免地存在字符到字節(jié)的相互轉(zhuǎn)化;而是HTTP請求時要做Gzip壓縮愈捅,網(wǎng)絡傳輸?shù)暮臅r遏考,這些都和數(shù)據(jù)大小密切相關。
從以下方面減少數(shù)據(jù)大欣督鳌:
HTML灌具、圖片青团、JSON、JSON結(jié)構(gòu)咖楣、Java對象督笆、請求數(shù)。
c诱贿、數(shù)據(jù)分級
就是要保證首屏為先娃肿、重要信息未先,次要信息采用異步加載的方式珠十,提升用戶獲取數(shù)據(jù)的體驗料扰。
d、減少中間環(huán)節(jié)焙蹭,減少字符到字節(jié)的轉(zhuǎn)換晒杈,將變的轉(zhuǎn)換為不變的;增加預處理就是去掉不需要的操作.
要做好優(yōu)化還需要做好應用基線孔厉,大概包括以下內(nèi)容:
性能基線拯钻,何時性能突然下降;
成本基線撰豺,去年雙11用了多少臺機器粪般;
鏈路基線,系統(tǒng)發(fā)生了哪些變化郑趁;
持續(xù)關注系統(tǒng)的性能刊驴,代碼級(提升代碼質(zhì)量)姿搜,業(yè)務(改掉不合理的調(diào)用)寡润,架構(gòu)和鏈路級(改進架構(gòu));
用更通用和批量的方式解決問題舅柜,整合系統(tǒng)之間的調(diào)研鏈路(合并部署)梭纹,提升整體機器使用率(彈性部署)。
推薦閱讀:
<<<《大型網(wǎng)站技術架構(gòu)演進與性能優(yōu)化》之分布式改造[一]
<<<《大型網(wǎng)站技術架構(gòu)演進與性能優(yōu)化》之無線時代下的構(gòu)架演進[二]
<<<《大型網(wǎng)站技術架構(gòu)演進與性能優(yōu)化》之大中臺小前臺[三]
<<<《大型網(wǎng)站技術架構(gòu)演進與性能優(yōu)化》之全球部署方案[四]
<<<《大型網(wǎng)站技術架構(gòu)演進與性能優(yōu)化》之合并部署[六]
<<<《大型網(wǎng)站技術架構(gòu)演進與性能優(yōu)化》之大秒系統(tǒng)的極致優(yōu)化思路[七]
<<<《大型網(wǎng)站技術架構(gòu)演進與性能優(yōu)化》之資源調(diào)度優(yōu)化[八]
<<<《大型網(wǎng)站技術架構(gòu)演進與性能優(yōu)化》之大型網(wǎng)站的穩(wěn)定性建設[九]