您好,登錄后才能下訂單哦!
本篇內容介紹了“怎么用Java制定性能調優策略”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
性能測試是提前能發現性能瓶頸,保障系統性能穩定的必要措施。
微基準性能測試可以精確定位到某個模塊或者某個方法的性能問題,特別適合做一個功能模塊或者一個方法在不同實現方式下的性能對比。例如,對比一個方法使用同步實現和非同步實現的性能。
宏基準性能測試是一個綜合測試,需要考慮到測試環境、測試場景和測試目標。
首先看測試環境,我們需要模擬線上的真實環境。
然后看測試場景。我們需要確定在測試某個接口時,是否有其他業務接口同時也在平行運行,造成干擾。如果有,請重視,因為你一旦忽視了這種干擾,測試結果就會出現偏差。
最后看測試目標。我們的性能測試是要有目標的,這里可以通過吞吐量以及響應時間來衡量系統是否達標。不達標,就進行優化;達標就繼續加大測試的并發數,探底接口的 TPS(最大每秒事務處理量),這樣做,可以深入了解到接口的性能。除了測試接口的吞吐量和響應時間以外,我們還需要循環測試可能導致性能問題的接口,觀察各個服務器的 CPU 、內存以及 I/O 使用率的變化。
以上就是兩種測試方法的詳解。其中值得注意的是,性能測試存在干擾因子,會使測試結果不準確。所以,我們在做性能測試時,還要注意一些問題。
當我們做性能測試時,我們的系統會運行得越來越快,后面的訪問速度要比我們第一次訪問的速度快上幾倍。這是怎么回事呢?
在 Java 編程語言和環境中,.Java 文件編譯成為 .class 文件后,機器還是無法直接運行 .class 文件中的字節碼,需要通過解釋器將字節碼轉換成本地機器碼才能運行。為了節約內存和執行效率,代碼最初被執行時,解釋器會率先執行這段代碼。
隨著代碼被執行的次數增多,當虛擬機發現某個方法或代碼塊運行得特別頻繁時,就會把這些代碼認定為熱點代碼。為了提高熱點代碼的執行效率,在運行時,虛擬機將會通過即時編譯器,把這些代碼編譯成與本地平臺相關的機器碼,并進行各層次的優化,然后儲存在內存中,之后每次運行代碼時,直接從內存匯總獲取即可。
所以在剛開始運行的階段,虛擬機會花費很長的時間來全面優化代碼,后面就能以最高性能執行了。
這就是熱身過程,如果在進行性能測試時,熱身時間過長,就會導致第一次訪問速度過慢,你就可以考慮先優化,再進行測試
我們在做性能測試時發現,每次測試處理的數據集都是一樣的,但測試結果卻有差異。這是因為測試時,伴隨著很多不穩定因為,比如機器其他進程的影響、網絡波動以及每個階段 JVM 垃圾回收的不同等等。
我們可以通過多次測試,將測試結果求平均,或者統計一個曲線圖,只要保證我們的平均值是在合理范圍之內,而且波動不是很大,這種情況下,性能測試就是通過的。
如果我們的服務器有多個 Java 應用服務,部署在不同的 Tomcat 下,這就意味著我們的服務器會有多個 JVM。任意一個 JVM 都擁有整個系統的資源使用權。如果一臺機器上只部署單獨的一個 JVM ,在做性能測試時,測試結果很好,或者你調優的效果很好,但在一臺機器多個 JVM 的情況下就不一定了。所以我們應該盡量避免線上環境中一臺機器部署多個 JVM 的情況。
我們在完成性能測試之后,需要輸出一份性能測試報告,幫我們分析系統性能測試的情況。其中測試結果需要包含測試接口的平均、最大和最小吞吐量,響應時間,服務器的 CPU、內存、I/O、網絡 IO 使用率,JVM 的 GC 頻率等。
通過觀察這些調優標準,可以發現性能瓶頸,我們再通過自下而上的方式分析查找問題。首先從操作系統層面,查看系統的 CPU、內存、I/O、網絡的使用率是否存在異常,再通過命令查找異常日志,最后通過分析日志,找到導致瓶頸的原因;還可以從 Java 應用的 JVM 層面,查看 JVM 的垃圾回收頻率以及內存分配情況是否存在異常,分析日志,找到導致瓶頸的原因。
如果系統和 JVM 層面都沒有出現異常情況,我們可以查看應用服務業務層是否存在性能瓶頸,例如 Java 編程的問題、讀寫數據瓶頸等等。
分析查找問題是一個復雜而又細致的過程,某個性能問題可能是一個原因導致的,也可能是幾個原因共同導致的結果。我們分析查找問題可以采用自下而上的方式,而我們解決系統性能問題,則可以采用自上而下的方式逐級優化。下面我來介紹下從應用層到操作系統層的幾種調優策略。
應用層的問題代碼往往會因為耗盡系統資源而暴露出來。例如,我們某段代碼導致內存溢出,往往是將 JVM 中的內存用完了,這個時候系統的內存資源消耗殆盡了,同時也會引發JVM 頻繁地發生垃圾回收,導致 CPU 100% 以上居高不下,這個時候又消耗了系統的CPU 資源。
還有一些是非問題代碼導致的性能問題,這種往往是比較難發現的,需要依靠我們的經驗來優化。例如,我們經常使用的 LinkedList 集合,如果使用 for 循環遍歷該容器,將大大降低讀的效率,但這種效率的降低很難導致系統性能參數異常。
這時有經驗的同學,就會改用 Iterator (迭代器)迭代循環該集合,這是因為 LinkedList是鏈表實現的,如果使用 for 循環獲取元素,在每次循環獲取元素時,都會去遍歷一次List,這樣會降低讀的效率。
面向對象有很多設計模式,可以幫助我們優化業務層以及中間件層的代碼設計。優化后,不僅可以精簡代碼,還能提高整體性能。例如,單例模式在頻繁調用創建對象的場景中,可以共享一個創建對象,這樣可以減少頻繁地創建和銷毀對象所帶來的性能消耗。
好的算法可以幫助我們大大地提升系統性能。例如,在不同的場景中,使用合適的查找算法可以降低時間復雜度。
有時候系統對查詢時的速度并沒有很高的要求,反而對存儲空間要求苛刻,這個時候我們可以考慮用時間來換取空間。
例如,我在 03 講就會詳解的用 String 對象的 intern 方法,可以將重復率比較高的數據集存儲在常量池,重復使用一個相同的對象,這樣可以大大節省內存存儲空間。但由于常量池使用的是 HashMap 數據結構類型,如果我們存儲數據過多,查詢的性能就會下降。所以在這種對存儲容量要求比較苛刻,而對查詢速度不作要求的場景,我們就可以考慮用時間換空
這種方法是使用存儲空間來提升訪問速度。現在很多系統都是使用的 MySQL 數據庫,較為常見的分表分庫是典型的使用空間換時間的案例。
因為 MySQL 單表在存儲千萬數據以上時,讀寫性能會明顯下降,這個時候我們需要將表數據通過某個字段 Hash 值或者其他方式分拆,系統查詢數據時,會根據條件的 Hash 值判斷找到對應的表,因為表數據量減小了,查詢性能也就提升了。
以上都是業務層代碼的優化,除此之外,JVM、Web 容器以及操作系統的優化也是非常關鍵的。
根據自己的業務場景,合理地設置 JVM 的內存空間以及垃圾回收算法可以提升系統性能。例如,如果我們業務中會創建大量的大對象,我們可以通過設置,將這些大對象直接放進老年代。這樣可以減少年輕代頻繁發生小的垃圾回收(Minor GC),減少 CPU 占用時間,提升系統性能。
Web 容器線程池的設置以及 Linux 操作系統的內核參數設置不合理也有可能導致系統性能瓶頸,根據自己的業務場景優化這兩部分,可以提升系統性能。
第一,限流,對系統的入口設置最大訪問限制。這里可以參考性能測試中探底接口的 TPS。同時采取熔斷措施,友好地返回沒有成功的請求。
第二,實現智能化橫向擴容。智能化橫向擴容可以保證當訪問量超過某一個閾值時,系統可以根據需求自動橫向新增服務。
第三,提前擴容。這種方法通常應用于高并發系統,例如,瞬時搶購業務系統。這是因為橫向擴容無法滿足大量發生在瞬間的請求,即使成功了,搶購也結束了。
目前很多公司使用 Docker 容器來部署應用服務。這是因為 Docker 容器是使用 Kubernetes 作為容器管理系統,而 Kubernetes 可以實現智能化橫向擴容和提前擴容Docker 服務。
“怎么用Java制定性能調優策略”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。