java系統如何做業務性能優化
前言
基本上每個系統都有一個在整個生命週期都需要討論的話題“性能”。在業務初期,“野蠻生長”是第一要務,只要能滿足用戶性能,堆機器、堆人力、堆數據庫等,能直接解決的都無需上升到專門的優化專題。
經常聽到的一句話就是,機器性能的提升,很少有人去關注系統調優了。當然,在服務器性能飆升導致工程師越來越少關注底層優化邏輯。
業務性能優化
那麼爲什麼還要那麼關注業務性能優化? 一方面,時刻保持性能優化,在技術方案設計期間、在編碼期間、在上線運行期間、在業務維護期間,都應該追求極致的體驗,可以降低系統消耗節省成本,可以節省用戶時間提升用戶效率。
另外一方面,性能優化應該是工程師自身的一種基本素質。系統保持相對優化狀態,對於穩定性、效能都是有着重要影響。
性能優化方法論
這裏簡單介紹一下我對性能優化的看法。
工具化
要保證能快速定位系統的瓶頸,就應該有一套合適的工具幫助快速定位到性能薄弱點。那有一套調用鏈的整體觀測方法,就能輕易實現這個目的了。
google公司的Dapper就是一套分佈式下的跟蹤系統,具體論文:http://bigbully.github.io/Dapper-translation/。
分佈式跟蹤鏈路
基本上大型互聯網公司都會基於Dapper實現一套自身的分佈式鏈路系統,通過這個系統的調用鏈,就很容易分析出系統在每個接口和模塊上的耗時,進而可以更清晰的定位接口,進一步分析代碼查看其RT耗時及制定出相應的優化方案。
如上圖所示,阿里雲提供的鷹眼能力,可以看到在每個應用上的調用耗時。
spring調用攔截
上面說的,是可以做到系統間的調用分析,對於單個應用來說,可能使用應用內部的一些攔截器來實現整體調用情況分析,可能會更爲高效、具備針對性。
以上是我用的springaop的攔截器,可以打印出每個bean的消耗。進而可以分析具體某個bean的方法耗時已經耗時在哪個邏輯裏。
最佳實踐
通常來說,每個優化都是要CASE BY CASE的,但是從經驗上來說,有幾個優化方法是屢試不爽的,也基本上可以覆蓋80%的場景。
批處理
很多業務場景,都需要有列表頁,比如商品列表、用戶列表、訂單列表等,如果使用單接口的話,往往就需要循環取數,RT則容易就變成了O(N),用批處理則可以將取數優化成O(1)。經驗上來看,一次內存計算1毫秒已經頂天了,但是一次RPC至少10毫秒左右。
從實際調用來看,一次北京到上海的RT耗時大約在60毫秒左右。因此解決RPC調用是全部優化需要首先考慮的一個問題。
緩存處理
只要滿足數據非強一致性,則可以使用緩存來降級,減少大量的DB和內存計算。比如商品詳情,基本上是不會有什麼變化,因此商品數據無需頻繁去DB中取,我們只要將商品對象緩存起來,直接取緩存數據即可。緩存還有更多的用法,比如用作臨時存儲等。當然緩存還有數據一致性的問題、多級緩存的問題,這裏就不再贅述,後續將對緩存重點再講解一波。緩存的RT一般1毫秒左右,接口RT則一般至少10毫秒以上,因此用緩存空間來換取時間還是穩賺的。
異步處理
異步處理相對前面一些措施來說會比較複雜一些,首先需要對業務理解透徹,哪些是可以拆分成異步化處理的,哪些是必須同步處理的,其次是要對異步有深刻理解,異步化本身相對同步來說,會增加一個複雜度。以下是同步轉異步的僞代碼。
當然,異步是有代價的,可以說是一種用空間換時間的辦法,同時,異步的編程複雜度也會高很多。這裏大家可以看看rxjava,後續會繼續介紹rxjava在生產上的最佳實踐。
非必要情況下,還是慎用異步的編程模式,但是架構上可以採用異步的模式,比如支付成功後發送用戶消息、調用物流接口,則可以用系統消息來解耦。
總結
性能優化是一個業務持續集成類似的模式,也是需要持續做性能,性能優化是伴隨業務生命週期的。優化的方式和角度都很多,這裏只是總結出我在做中大型系統的自己的思考。