效能優化有感
效能優化是個枯燥,卻又有趣的過程
效能優化我大致分為幾個方面
- 程式碼優化
- 執行緒優化、非同步
- JVM優化
- 資料庫優化
- 快取優化
- 架構優化
下面來展開談談感悟,也可以參考美團技術團隊常見效能優化
程式碼優化
程式碼是跟我們接觸最多的東西,程式碼優化主要有
- 程式碼結構優化,可以方便日後擴充套件和程式碼標準化
- 是否可以進行抽象避免冗餘程式碼
- 是否可以利用設計模式
- 程式碼是否遵循阿里巴巴Java開發手冊
這裡可以採用阿里巴巴Java開發規範外掛
- 程式碼是否有多重迴圈,無效的查詢等
- 多重迴圈可以根據資料量採用HashMap進行查詢,屬於利用空間換取時間
- 無效的查詢等可以進行刪除
這裡推薦Findbugs
執行緒優化
執行緒優化是一個複雜的過程,多執行緒如何運用,如何避免死鎖、飢餓、活鎖等問題
-
執行緒使用的地方
- 在查詢中可以運用到多執行緒,把序列化操作變化為並行化操作
- I/O阻塞的操作,最經典的莫過於BIO
- 計算量大的操作,使用多執行緒可以更好的運用CPU的運算能力
-
執行緒池
需要了解執行緒池的狀態,執行緒池的引數,以及內部原理,並選擇合適的執行緒池
這裡推薦一篇文章Java執行緒池實現原理及其在美團業務中的實踐 再次感謝美團技術團隊- 執行緒池分為
- newCachedThreadPool
- newFixedThreadPool
- newSingleThreadExecutor
- newScheduleThreadPool
- forkjoinPool
注意:這裡不建議使用Executors來建立執行緒池,方式OOM等問題,參考阿里巴巴開發規範,建議使用new ThreadPoolExecutor()
- 執行緒池分為
-
非同步
非同步建議採用MQ,使用範圍例如insert、update操作,可以丟到MQ,這裡要注意MQ訊息丟失問題,同時MQ也可以實現延遲佇列,例如30分鐘關閉訂單,採用Job的方式並不是一個好的解決方案,可以採用MQ延時佇列實現,這裡推薦rocketmq(阿里巴巴牛逼) -
併發容器的選擇
concurrenthashmap和synchronizedmap效能差距很大,建議選擇合適的併發容器
JVM優化
JVM優化這裡本人也不是特別的熟練,只是講一些自己所知道的
- 無日誌不優化
在沒有日誌的情況下,該怎麼優化,如何優化,哪些方面需要優化,這裡都是未知的,所以需要日誌才能進行優化 - 工具
優化要有趁手的工具,好在JDK本身就為我們提供了不少,在JDK的bin目錄下有一堆自帶的工具,這裡介紹幾個我熟悉且用過的- jps:檢視當前機器上的java程式
- jcmd:跟jps差不多但是能看到啟動命令
- jstat:檢視JVM資訊,例如GC資訊
- jinfo:檢視JVM引數
- jmap:JVM在記憶體中的情況,可以匯出Dump
- jstack:棧資訊,可以用來檢視死鎖等
- jconsole:一個視覺化工具
- jvisualvm:也是一個視覺化工具比jconsole功能強一些,但是都有侷限性,在伺服器上無法使用
- eclipse memory analyer:分析dump檔案
- 引數優化
使用上面的工具對伺服器進行監控,可以根據資訊適當的調整堆大小,GC收集器等。建議開啟-XX:+HeapDumpOnOutOfMemoryError
資料庫優化
資料庫是優化中重要的一環,具體優化方法如下
- SQL優化:是否可以去掉不必要的查詢,使用explain對sql進行分析,避免回表等
- 分庫分表:一臺資料庫可能存在效能瓶頸,可以採用分庫分表的方式,拆分主要採用冷熱資料分離、日期分割、HASH取模等。
- 讀寫分離:對資料的修改可以操作主庫,對資料的查詢可以操作從庫,進行讀寫分離
分庫分表以及讀寫分離後可能會出現分散式事務、讀寫分離操作的複雜性等問題這裡需要引入中介軟體例如:MyCat sharding jdbc
快取優化
快取是個優化的好辦法但是也有弊端
- 快取分類
- JVM快取:concurrenthashmap、guava快取
- Redis等NoSQL資料庫
- 快取拆分
可以在程式碼中對介面進行拆分,可以快取的和不可以快取的寫成多個方法,對可以快取的進行快取 - 快取帶來的弊端
快取並不是越多越好,快取給系統帶來了複雜性,例如:何時新增快取、何時刪除快取、快取雪崩、快取擊穿、快取穿透、快取預熱、Redis叢集如何實現、Redis哨兵、Redis腦裂等問題
架構優化
架構優化其實就程式設計師來說能做的並不是很多
- 限流:GateWay進行限流,限流方法有滑動視窗、漏桶、令牌桶演算法,這裡建議採用合適的方法進行限流防止應用崩潰
- 熔斷:可以採用hystrix防止服務雪崩
- CDN優化:對靜態資源採用CDN可以提交響應速率
- DNS優化:這個暫時不熟可以交給運維處理
- 服務擴容:可以採用K8S和Docker的技術對服務進行動態擴容,這裡也是運維實現
測試
優化了這麼多,體現當然是壓力測試,這裡因為不熟悉效能指標,單機TPS部分介面可以達到800+ RT在300ms以內,希望大家提供一個單機效能標準,以上採用的是LoadRuner測試的結果
洋洋灑灑寫了這麼多,主要的還是平時的積累以及思考,也希望您對內容進行補充。