性能優化有感
性能優化是個枯燥,卻又有趣的過程
性能優化我大致分為幾個方面
- 代碼優化
- 線程優化、異步
- 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測試的結果
洋洋灑灑寫了這么多,主要的還是平時的積累以及思考,也希望您對內容進行補充。