亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

高性能Java代碼的最佳實(shí)踐

stackfing / 3428人閱讀

摘要:高性能代碼的最佳實(shí)踐前言在這篇文章中,我們將討論幾個(gè)有助于提升應(yīng)用程序性能的方法。要獲得有關(guān)應(yīng)用程序需求的最好最可靠的方法是對(duì)應(yīng)用程序執(zhí)行實(shí)際的負(fù)載測(cè)試,并在運(yùn)行時(shí)跟蹤性能指標(biāo)。

高性能Java代碼的最佳實(shí)踐
前言

在這篇文章中,我們將討論幾個(gè)有助于提升Java應(yīng)用程序性能的方法。我們首先將介紹如何定義可度量的性能指標(biāo),然后看看有哪些工具可以用來(lái)度量和監(jiān)控應(yīng)用程序性能,以及確定性能瓶頸。

我們還將看到一些常見(jiàn)的Java代碼優(yōu)化方法以及最佳編碼實(shí)踐。最后,我們將看看用于提升Java應(yīng)用程序性能的JVM調(diào)優(yōu)技巧和架構(gòu)調(diào)整。

請(qǐng)注意,性能優(yōu)化是一個(gè)很寬泛的話題,而本文只是對(duì)JVM探索的一個(gè)起點(diǎn)。

性能指標(biāo)

在開(kāi)始優(yōu)化應(yīng)用程序的性能之前,我們需要理解諸如可擴(kuò)展性、性能、可用性等方面的非功能需求。

以下是典型Web應(yīng)用程序常用的一些性能指標(biāo):

1.應(yīng)用程序平均響應(yīng)時(shí)間

2.系統(tǒng)必須支持的平均并發(fā)用戶數(shù)

3.在負(fù)載高峰期間,預(yù)期的每秒請(qǐng)求數(shù)

這些指標(biāo)可以通過(guò)使用多種監(jiān)視工具監(jiān)測(cè)到,它們對(duì)分析性能瓶頸和性能調(diào)優(yōu)有著非常大的作用。

示例應(yīng)用程序

我們將使用一個(gè)簡(jiǎn)單的Spring Boot Web應(yīng)用程序作為示例,在這篇文章中有相關(guān)的介紹。這個(gè)應(yīng)用程序可用于管理員工列表,并對(duì)外公開(kāi)了添加和檢索員工的REST API。

我們將使用這個(gè)程序作為參考來(lái)運(yùn)行負(fù)載測(cè)試,并在接下來(lái)的章節(jié)中監(jiān)控各種應(yīng)用指標(biāo)。

找出性能瓶頸

負(fù)載測(cè)試工具和應(yīng)用程序性能管理(APM)解決方案常用于跟蹤和優(yōu)化Java應(yīng)用程序的性能。要找出性能瓶頸,主要就是對(duì)各種應(yīng)用場(chǎng)景進(jìn)行負(fù)載測(cè)試,并同時(shí)使用APM工具對(duì)CPU、IO、堆的使用情況進(jìn)行監(jiān)控等等。

Gatling是進(jìn)行負(fù)載測(cè)試最好的工具之一,它提供了對(duì)HTTP協(xié)議的支持,是HTTP服務(wù)器負(fù)載測(cè)試的絕佳選擇。

Stackify的Retrace是一個(gè)成熟的APM解決方案。它的功能很豐富,對(duì)確定應(yīng)用程序的性能基線很有幫助。 Retrace的關(guān)鍵組件之一是它的代碼分析功能,它能夠在不減慢應(yīng)用程序的情況下收集運(yùn)行時(shí)信息。

Retrace還提供了監(jiān)視基于JVM應(yīng)用程序的內(nèi)存、線程和類的小部件。除了應(yīng)用程序本身的指標(biāo)之外,它還支持監(jiān)視托管應(yīng)用程序的服務(wù)器的CPU和IO使用情況。

因此,像Retrace這樣功能全面的監(jiān)控工具是解鎖應(yīng)用程序性能潛力的第一步。而第二步則是在你的系統(tǒng)上重現(xiàn)真實(shí)使用場(chǎng)景和負(fù)載。

說(shuō)起來(lái)容易,做起來(lái)難,而且了解應(yīng)用程序當(dāng)前的性能也非常重要。這就是我們接下來(lái)要關(guān)注的問(wèn)題。

Gatling負(fù)載測(cè)試

Gatling的模擬測(cè)試腳本是用Scala編寫的,但該工具還附帶了一個(gè)非常有用的圖形界面,可用于記錄具體的場(chǎng)景,并生成Scala腳本。

在運(yùn)行模擬腳本之后,Gatling會(huì)生成一份非常有用的、可用于分析的HTML報(bào)告。

定義場(chǎng)景

在啟動(dòng)記錄器之前,我們需要定義一個(gè)場(chǎng)景,表示用戶在瀏覽Web應(yīng)用時(shí)發(fā)生的事情。

在我們的這個(gè)例子中,具體的場(chǎng)景將是“啟動(dòng)200個(gè)用戶,每個(gè)用戶發(fā)出一萬(wàn)個(gè)請(qǐng)求?!?/p>

配置記錄器

根據(jù)“Gatling的第一步”所述,用下面的代碼創(chuàng)建一個(gè)名為EmployeeSimulation的scala文件:

class EmployeeSimulation extends Simulation {
 val scn = scenario("FetchEmployees").repeat(10000) {
 exec(
 http("GetEmployees-API")
 .get("http://localhost:8080/employees")
 .check(status.is(200))
 )
 }
 setUp(scn.users(200).ramp(100))
 } 

運(yùn)行負(fù)載測(cè)試

要執(zhí)行負(fù)載測(cè)試,請(qǐng)運(yùn)行以下命令:

$GATLING_HOME/bin/gatling.sh-sbasic.EmployeeSimulation

對(duì)應(yīng)用程序的API進(jìn)行負(fù)載測(cè)試有助于發(fā)現(xiàn)及其細(xì)微的并且難以發(fā)現(xiàn)的錯(cuò)誤,如數(shù)據(jù)庫(kù)連接耗盡、高負(fù)載情況下的請(qǐng)求超時(shí)、因?yàn)閮?nèi)存泄漏而導(dǎo)致堆的高使用率等等。

監(jiān)控應(yīng)用程序

要使用Retrace進(jìn)行Java應(yīng)用程序的開(kāi)發(fā),首先需要在Stackify上申請(qǐng)免費(fèi)試用賬號(hào)。然后,將我們自己的Spring Boot應(yīng)用程序配置為L(zhǎng)inux服務(wù)。我們還需要在托管應(yīng)用程序的服務(wù)器上安裝Retrace代理,按照這篇文章所述的操作即可。

Retrace代理和要監(jiān)控的Java應(yīng)用程序啟動(dòng)后,我們就可以到Retrace儀表板上單擊AddApp按鈕添加應(yīng)用了。添加應(yīng)用完成之后,Retrace將開(kāi)始監(jiān)控應(yīng)用程序了。

找到最慢的那個(gè)點(diǎn)

Retrace會(huì)自動(dòng)監(jiān)控應(yīng)用程序,并跟蹤數(shù)十種常見(jiàn)框架及其依賴關(guān)系的使用情況,包括SQL、MongoDB、Redis、Elasticsearch等等。Retrace能幫助我們快速確定應(yīng)用程序?yàn)槭裁磿?huì)出現(xiàn)如下性能問(wèn)題:

某個(gè)SQL語(yǔ)句是否會(huì)拖慢系統(tǒng)的速度?

Redis突然變慢了嗎?

特定的HTTP Web服務(wù)宕了,還是變慢了?

例如,下面的圖形展示了在一段給定的時(shí)間內(nèi)速度最慢的組件。

代碼級(jí)別的優(yōu)化

負(fù)載測(cè)試和應(yīng)用程序監(jiān)控對(duì)于確定應(yīng)用程序的一些關(guān)鍵性能瓶頸非常有用。但同時(shí),我們需要遵循良好的編碼習(xí)慣,以避免在對(duì)應(yīng)用程序進(jìn)行監(jiān)控的時(shí)候出現(xiàn)過(guò)多的性能問(wèn)題。

在下一章節(jié)中,我們將來(lái)看一些最佳實(shí)踐。

使用StringBuilder來(lái)連接字符串

字符串連接是一個(gè)非常常見(jiàn)的操作,也是一個(gè)低效率的操作。簡(jiǎn)單地說(shuō),使用+=來(lái)追加字符串的問(wèn)題在于每次操作都會(huì)分配新的String。

下面這個(gè)例子是一個(gè)簡(jiǎn)化了的但卻很典型的循環(huán)。前面使用了原始的連接方式,后面使用了構(gòu)建器:

public String stringAppendLoop() {
 String s = "";
 for (int i = 0; i < 10000; i++) {
 if (s.length() > 0)
 s += ", ";
 s += "bar";
 }
 return s;
 } 
public String stringAppendBuilderLoop() {
 StringBuilder sb = new StringBuilder();
 for (int i = 0; i < 10000; i++) {
 if (sb.length() > 0)
 sb.append(", ");
 sb.append("bar");
 }
 return sb.toString();
 } 

上面代碼中使用的StringBuilder對(duì)性能的提升非常有效。請(qǐng)注意,現(xiàn)代的JVM會(huì)在編譯或者運(yùn)行時(shí)對(duì)字符串操作進(jìn)行優(yōu)化。

避免遞歸

導(dǎo)致出現(xiàn)StackOverFlowError錯(cuò)誤的遞歸代碼邏輯是Java應(yīng)用程序中另一種常見(jiàn)的問(wèn)題。如果無(wú)法去掉遞歸邏輯,那么尾遞歸作為替代方案將會(huì)更好。

我們來(lái)看一個(gè)頭遞歸的例子:

public int factorial(int n) {
 if (n == 0) {
 return 1;
 } else {
 return n * factorial(n - 1);
 }
 } 

現(xiàn)在我們把它重寫為尾遞歸:

private int factorial(int n, int accum) {
 if (n == 0) {
 return accum;
 } else {
 return factorial(n - 1, accum * n);
 }
 }
 public int factorial(int n) {
 return factorial(n, 1);
 } 

其他JVM語(yǔ)言(如Scala)已經(jīng)在編譯器級(jí)支持尾遞歸代碼的優(yōu)化,當(dāng)然,對(duì)于這種優(yōu)化目前也存在著一些爭(zhēng)議。

謹(jǐn)慎使用正則表達(dá)式

正則表達(dá)式在很多場(chǎng)景中都非常有用,但它們往往具有非常高的性能成本。了解各種使用正則表達(dá)式的JDK字符串方法很重要,例如String.replaceAll()、String.split()。

如果你不得不在計(jì)算密集的代碼段中使用正則表達(dá)式,那么需要緩存Pattern的引用而避免重復(fù)編譯:

static final Pattern HEAVY_REGEX = Pattern.compile("(((X)Y)Z)*");

使用一些流行的庫(kù),比如Apache Commons Lang也是一個(gè)很好的選擇,特別是在字符串的操作方面。

避免創(chuàng)建和銷毀過(guò)多的線程

線程的創(chuàng)建和處置是JVM出現(xiàn)性能問(wèn)題的常見(jiàn)原因,因?yàn)榫€程對(duì)象的創(chuàng)建和銷毀相對(duì)較重。

如果應(yīng)用程序使用了大量的線程,那么使用線程池會(huì)更加有用,因?yàn)榫€程池允許這些昂貴的對(duì)象被重用。

為此,Java的ExecutorService是線程池的基礎(chǔ),它提供了一個(gè)高級(jí)API來(lái)定義線程池的語(yǔ)義并與之進(jìn)行交互。

Java 7中的Fork/Join框架也值得提一下,因?yàn)樗峁┝艘恍┕ぞ邅?lái)嘗試使用所有可用的處理器核心以幫助加速并行處理。為了提高并行執(zhí)行效率,框架使用了一個(gè)名為ForkJoinPool的線程池來(lái)管理工作線程。

JVM調(diào)優(yōu)

堆大小的調(diào)優(yōu)

為生產(chǎn)系統(tǒng)確定合適的JVM堆大小并不是一件簡(jiǎn)單的事情。要做的第一步是回答以下問(wèn)題以預(yù)測(cè)內(nèi)存需求:

計(jì)劃要把多少個(gè)不同的應(yīng)用程序部署到單個(gè)JVM進(jìn)程中,例如EAR文件、WAR文件、jar文件的數(shù)量是多少?

在運(yùn)行時(shí)可能會(huì)加載多少個(gè)Java類,包括第三方API的類?

估計(jì)內(nèi)存緩存所需的空間,例如,由應(yīng)用程序(和第三方API)加載的內(nèi)部緩存數(shù)據(jù)結(jié)構(gòu),比如從數(shù)據(jù)庫(kù)緩存的數(shù)據(jù)、從文件中讀取的數(shù)據(jù)等等。

估計(jì)應(yīng)用程序?qū)?chuàng)建的線程數(shù)。

如果沒(méi)有經(jīng)過(guò)真實(shí)場(chǎng)景的測(cè)試,這些數(shù)字很難估計(jì)。

要獲得有關(guān)應(yīng)用程序需求的最好最可靠的方法是對(duì)應(yīng)用程序執(zhí)行實(shí)際的負(fù)載測(cè)試,并在運(yùn)行時(shí)跟蹤性能指標(biāo)。我們之前討論的基于Gatling的測(cè)試就是一個(gè)很好的方法。

選擇合適的垃圾收集器

Stop-the-world(STW)垃圾收集的周期是影響大多數(shù)面向客戶端應(yīng)用程序響應(yīng)和整體Java性能的大問(wèn)題。但是,目前的垃圾收集器大多解決了這個(gè)問(wèn)題,并且通過(guò)適當(dāng)?shù)膬?yōu)化和大小的調(diào)整,能夠消除對(duì)收集周期的感知。

分析器、堆轉(zhuǎn)儲(chǔ)和詳細(xì)的GC日志記錄工具對(duì)此有一定的幫助作用。再一次注意,這些都需要在真實(shí)場(chǎng)景的負(fù)載模式下進(jìn)行監(jiān)控。

有關(guān)不同垃圾收集器的更多信息,請(qǐng)查看這個(gè)指南。

JDBC性能

關(guān)系型數(shù)據(jù)庫(kù)是Java應(yīng)用程序中另一個(gè)常見(jiàn)的性能問(wèn)題。為了獲得完整請(qǐng)求的響應(yīng)時(shí)間,我們很自然地必須查看應(yīng)用程序的每一層,并思考如何讓代碼與底層SQL DB進(jìn)行交互。

連接池

讓我們從眾所周知的事實(shí)開(kāi)始,即數(shù)據(jù)庫(kù)連接是昂貴的。 連接池機(jī)制是解決這個(gè)問(wèn)題非常重要的第一步。

這里建議使用HikariCP JDBC,這是一個(gè)非常輕量級(jí)(大約130Kb)并且速度極快的JDBC連接池框架。

JDBC批處理

持久化處理應(yīng)盡可能地執(zhí)行批量操作。 JDBC批處理允許我們?cè)趩未螖?shù)據(jù)庫(kù)交互中發(fā)送多個(gè)SQL語(yǔ)句。

這樣,無(wú)論是在驅(qū)動(dòng)端還是在數(shù)據(jù)庫(kù)端,性能都可能得到顯著地提升。 PreparedStatement是一個(gè)非常棒的的批處理命令,一些數(shù)據(jù)庫(kù)系統(tǒng)(例如Oracle)只支持預(yù)處理語(yǔ)句的批處理。

另一方面,Hibernate則更加靈活,它允許我們只需修改一個(gè)配置即可快速切換為批處理操作。

語(yǔ)句緩存

語(yǔ)句緩存是另一種提高持久層性能的方法,這是一種鮮為人知但又容易掌握的性能優(yōu)化方法。

只要底層的JDBC驅(qū)動(dòng)程序支持,你就可以在客戶端(驅(qū)動(dòng)程序)或數(shù)據(jù)庫(kù)端(語(yǔ)法樹(shù)甚至執(zhí)行計(jì)劃)中緩存PreparedStatement。

規(guī)模的縮放

數(shù)據(jù)庫(kù)復(fù)制和分片是提高吞吐量非常好的方法,我們應(yīng)該充分利用這些經(jīng)過(guò)實(shí)踐檢驗(yàn)的架構(gòu)模式,以擴(kuò)展企業(yè)應(yīng)用的持久層。

架構(gòu)改進(jìn)

緩存

現(xiàn)在內(nèi)存的價(jià)格很低,而且越來(lái)越低,從磁盤或通過(guò)網(wǎng)絡(luò)來(lái)檢索數(shù)據(jù)的性能代價(jià)仍然很高。緩存自然而然的變成了在應(yīng)用程序性能方面不能忽視的關(guān)鍵。

當(dāng)然,在應(yīng)用的拓?fù)浣Y(jié)構(gòu)中引入一個(gè)獨(dú)立的緩存系統(tǒng)確實(shí)會(huì)增加架構(gòu)的復(fù)雜度,所以,應(yīng)當(dāng)充分利用當(dāng)前使用的庫(kù)和框架現(xiàn)有的緩存功能。

例如,大多數(shù)的持久化框架都支持緩存。 Spring MVC等Web框架還可以使用Spring中內(nèi)置的緩存支持,以及基于ETags的強(qiáng)大的HTTP級(jí)緩存。

橫向擴(kuò)展

無(wú)論我們?cè)趩蝹€(gè)實(shí)例中準(zhǔn)備了多少硬件,都會(huì)有不夠用的時(shí)候。簡(jiǎn)而言之,擴(kuò)展有著天生的局限性,當(dāng)系統(tǒng)遇到這些問(wèn)題時(shí),橫向擴(kuò)展是處理更多負(fù)載的唯一途徑。這一步肯定會(huì)相當(dāng)?shù)膹?fù)雜,但卻是擴(kuò)展應(yīng)用的唯一辦法。

對(duì)大多數(shù)的現(xiàn)代框架和庫(kù)來(lái)說(shuō),這方面還是支持得很好的,而且會(huì)變得越來(lái)越好。 Spring生態(tài)系統(tǒng)有一個(gè)完整的項(xiàng)目集,專門用于解決這個(gè)特定的應(yīng)用程序架構(gòu)領(lǐng)域,其他大多數(shù)的框架也都有類似的支持。

除了能夠提升Java的性能,通過(guò)集群進(jìn)行橫向擴(kuò)展也有其他的好處,添加新的節(jié)點(diǎn)能產(chǎn)生冗余,并更好的處理故障,從而提高整個(gè)系統(tǒng)的可用性。

結(jié)論

在這篇文章中,我們圍繞著提升Java應(yīng)用的性能探討了許多概念。我們首先介紹了負(fù)載測(cè)試、基于APM工具的應(yīng)用程序和服務(wù)器監(jiān)控,隨后介紹了編寫高性能Java代碼的一些最佳實(shí)踐。最后,我們研究了JVM特定的調(diào)優(yōu)技巧、數(shù)據(jù)庫(kù)端的優(yōu)化和架構(gòu)方面的調(diào)整。

感謝您耐心看完的文章

順便給大家推薦一個(gè)Java技術(shù)交流群:710373545里面會(huì)分享一些資深架構(gòu)師錄制的視頻資料:有Spring,MyBatis,Netty源碼分析,高并發(fā)、高性能、分布式、微服務(wù)架構(gòu)的原理,JVM性能優(yōu)化、分布式架構(gòu)等這些成為架構(gòu)師必備的知識(shí)體系。還能領(lǐng)取免費(fèi)的學(xué)習(xí)資源,目前受益良多!

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/74695.html

相關(guān)文章

  • Java異常處理 10 個(gè)最佳實(shí)踐

    摘要:為可恢復(fù)的錯(cuò)誤使用檢查型異常,為編程錯(cuò)誤使用非檢查型錯(cuò)誤。檢查型異常保證你對(duì)錯(cuò)誤條件提供異常處理代碼,這是一種從語(yǔ)言到強(qiáng)制你編寫健壯的代碼的一種方式,但同時(shí)會(huì)引入大量雜亂的代碼并導(dǎo)致其不可讀。在編程中選擇檢查型異常還是運(yùn)行時(shí)異常。 異常處理是Java 開(kāi)發(fā)中的一個(gè)重要部分。它是關(guān)乎每個(gè)應(yīng)用的一個(gè)非功能性需求,是為了處理任何錯(cuò)誤狀況,比如資源不可訪問(wèn),非法輸入,空輸入等等。Java提供了...

    Forelax 評(píng)論0 收藏0
  • 學(xué)習(xí)Java必讀10本書籍

    摘要:學(xué)習(xí)編程的本最佳書籍這些書涵蓋了各個(gè)領(lǐng)域,包括核心基礎(chǔ)知識(shí),集合框架,多線程和并發(fā),內(nèi)部和性能調(diào)優(yōu),設(shè)計(jì)模式等。擅長(zhǎng)解釋錯(cuò)誤及錯(cuò)誤的原因以及如何解決簡(jiǎn)而言之,這是學(xué)習(xí)中并發(fā)和多線程的最佳書籍之一。 showImg(https://segmentfault.com/img/remote/1460000018913016); 來(lái)源 | 愿碼(ChainDesk.CN)內(nèi)容編輯 愿碼Slo...

    masturbator 評(píng)論0 收藏0
  • 2016年Java書單

    摘要:相對(duì)于電子書,我更喜歡紙質(zhì)版的書籍。過(guò)去的年一共閱讀過(guò)本技術(shù)書,下面對(duì)這些書做一個(gè)小結(jié)。源碼深度解析這本書是年購(gòu)買的,年是第四次閱讀。必知必會(huì)數(shù)據(jù)庫(kù)的復(fù)習(xí)書籍,內(nèi)容淺顯易懂。 相對(duì)于電子書,我更喜歡紙質(zhì)版的書籍。我喜歡在拿到新書時(shí)記錄購(gòu)買時(shí)間、地點(diǎn)、開(kāi)始閱讀的時(shí)間、第一次看完的時(shí)間,算是一種學(xué)習(xí)的記錄。過(guò)去的2016年一共閱讀過(guò)15本技術(shù)書,下面對(duì)這些書做一個(gè)小結(jié)。 《深入理解Java...

    Scholer 評(píng)論0 收藏0
  • 貓頭鷹深夜翻譯:JAVA中異常處理最佳實(shí)踐

    摘要:無(wú)需檢查的異常也是的子類。從低層拋出的需檢查異常強(qiáng)制要求調(diào)用方捕獲或是拋出該異常。當(dāng)前執(zhí)行的線程將會(huì)停止并報(bào)告該異常。單元測(cè)試允許我在使用中查看異常,并且作為一個(gè)可以被執(zhí)行的文檔來(lái)使用。不要捕獲最高層異常繼承的異常同樣是的子類。 前言 異常處理的問(wèn)題之一是知道何時(shí)以及如何去使用它。我會(huì)討論一些異常處理的最佳實(shí)踐,也會(huì)總結(jié)最近在異常處理上的一些爭(zhēng)論。 作為程序員,我們想要寫高質(zhì)量的能夠解...

    W_BinaryTree 評(píng)論0 收藏0
  • Java 字符串拼接效率分析及最佳實(shí)踐

    摘要:兩個(gè)字符串拼接直接調(diào)用性能最好。關(guān)于的其他最佳實(shí)踐用時(shí)總是把能確定不為空的變量寫在左邊,如使用判斷空串,避免空指針異常。在需要把其他對(duì)象轉(zhuǎn)換為字符串對(duì)象時(shí),使用而不是直接調(diào)用方法,因?yàn)榍罢咭呀?jīng)對(duì)空值進(jìn)行檢測(cè)了,不會(huì)拋出空指針異常。 本文來(lái)源于問(wèn)題 Java字符串連接最佳實(shí)踐? java連接字符串有多種方式,比如+操作符,StringBuilder.append方法,這些方法各有什么優(yōu)...

    BakerJ 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<