摘要:對于大多數(shù)典型的企業(yè)應(yīng)用而言,其性能表現(xiàn)幾乎完全依賴于持久層的性能。速成法使用批處理對于批處理程序,驅(qū)動程序提供了旨在減少網(wǎng)絡(luò)來回傳輸?shù)膬?yōu)化方法。速成法檢查錯誤的提交間隔如果你使用批處理程序,提交間隔會對性能造成十倍甚至百倍的影響。
對于大多數(shù)典型的 Spring/Hibernate 企業(yè)應(yīng)用而言,其性能表現(xiàn)幾乎完全依賴于持久層的性能。此篇文章中將介紹如何確認(rèn)應(yīng)用是否受數(shù)據(jù)庫約束,同時(shí)介紹七種常用的提高應(yīng)用性能的速成法。本文系 OneAPM 工程師編譯整理。
如何確認(rèn)應(yīng)用是否受限于數(shù)據(jù)庫確認(rèn)應(yīng)用是否受限于數(shù)據(jù)庫的第一步,是在開發(fā)環(huán)境中進(jìn)行測試,并使用 VisualVM 進(jìn)行監(jiān)控。VisualVM 是一款包含在 JDK 中的 Java 分析器,在命令行輸入 jvisualvm 即可調(diào)用。
啟用 Visual VM 之后,嘗試以下步驟:
雙擊你正在運(yùn)行的應(yīng)用
選擇 Sampler
點(diǎn)擊 Settings 復(fù)選框
選擇Profile only packages,然后輸入下列包:
your.application.packages.*
org.hibernate.*
org.springframework.*
your.database.driver.package, 比如 oracle.*
點(diǎn)擊 Sample CPU
如果應(yīng)用性能受限于數(shù)據(jù)庫,其 CPU 分析結(jié)果看起來會像下圖:
我們看到,客戶端 Java 進(jìn)程花在等待數(shù)據(jù)庫從網(wǎng)絡(luò)中返回結(jié)果的時(shí)間占56%。
看到數(shù)據(jù)庫查詢是導(dǎo)致應(yīng)用運(yùn)行緩慢的原因,其實(shí)是好兆頭。Hibernate 反射調(diào)用占比32.7%是正常情況,無法進(jìn)一步優(yōu)化。
性能調(diào)優(yōu)第一步:定義基準(zhǔn)運(yùn)行性能調(diào)優(yōu)的第一步是為程序定義基準(zhǔn)運(yùn)行,我們要定義一組能有效執(zhí)行的輸入數(shù)據(jù),讓程序基準(zhǔn)運(yùn)行與生產(chǎn)環(huán)境下的運(yùn)行差不多。
主要的區(qū)別在于基準(zhǔn)運(yùn)行的耗時(shí)要小很多。作為參考,5到10分鐘的執(zhí)行時(shí)間比較不錯。
什么是好的基準(zhǔn)?好的基準(zhǔn)應(yīng)該具備以下特征:
功能正確
輸入數(shù)據(jù)的種類與生產(chǎn)環(huán)境下相似
在短時(shí)間內(nèi)執(zhí)行完畢
基準(zhǔn)運(yùn)行的優(yōu)化方案可以外推至完整運(yùn)行
定義好的基準(zhǔn)是成功解決問題的一半。
什么是不好的基準(zhǔn)例如,通過批量運(yùn)行處理通訊系統(tǒng)的電話數(shù)據(jù)記錄,選取10000條記錄就是錯誤的做法。
原因是:前10000條記錄可能多為語音電話,而未知的性能問題可能發(fā)生在短信流量的處理過程中。一開始如果基準(zhǔn)不夠好,就會導(dǎo)致錯誤的結(jié)論。
收集 SQL 日志與查詢時(shí)間SQL 查詢的執(zhí)行語句與其執(zhí)行時(shí)間可以通過 log4jdbc等方式收集。詳細(xì)了解如何使用 log4jdbc 收集 SQL 查詢信息,點(diǎn)擊文章 使用 log4jdbc 優(yōu)化 Spring/Hibernate 應(yīng)用 SQL 日志。
查詢的執(zhí)行時(shí)間是從 Java 客戶端收集的,該時(shí)間包含查詢數(shù)據(jù)庫的來回網(wǎng)絡(luò)調(diào)用。SQL 查詢的日志如下:
16 avr. 2014 11:13:48 | SQL_QUERY /* insert your.package.YourEntity */ insert into YOUR_TABLE (...) values (...) {executed in 13 msec}
預(yù)處理語句也是很重要的信息來源,它們常常會透露出常用的查詢類型。了解更多的日志訊息,可以查看文章:Hibernate 為什么/在何處使用該 SQL 查詢?
通過 SQL 日志可以了解哪些指標(biāo)?SQL 日志可以回答下列問題:
哪些是執(zhí)行過的最慢查詢?
哪些是最常用的查詢?
生成主鍵的耗時(shí)是多少?
是否有數(shù)據(jù)適合緩存?
如何解析 SQL 日志對于大量的日志文件,最可行的解析方式就是使用命令行工具,該方法的好處是非常靈活,只要寫一小段腳本或命令,我們可以抽取出幾乎大多數(shù)指標(biāo)。只要你喜歡,任何命令行工具都適用。
如何你習(xí)慣了 Unix 命令行,bash 或是一個(gè)好選擇。Bash 也可以在 Windows 工作站使用,Cygwin 或 Git 都包含了 bash 命令行。
常用的速成法下面介紹的速成法能找出 Spring/Hibernate 應(yīng)用中常見的性能問題,以及對應(yīng)的解決方案。
速成法1——減少生成主鍵的代價(jià)在插入操作頻繁的進(jìn)程中,主鍵的生成策略很重要。生成 id 的一種常見方法是使用數(shù)據(jù)庫序列,通常一張表一個(gè) id,從而避免在不同表間進(jìn)行插入時(shí)的沖突。
問題在于,如果要插入50條記錄,我們希望為了獲取這50個(gè) id,可以避免50趟查詢數(shù)據(jù)庫的來回網(wǎng)絡(luò)調(diào)用,讓 Java 進(jìn)程不一直等待。
Hibernate 通常如何解決此問題?Hibernate 提供了優(yōu)化的 ID 生成器以避免此問題。也即,對于序列,會默認(rèn)使用 HiLo id 生成器。以下是 HiLo 序列生成器的工作方式:
調(diào)用一次序列,獲得 1000 (高值)
用以下方式計(jì)算50個(gè) id
1000 * 50 + 0 = 50000
1000 * 50 + 1 = 50001
...
1000 * 50 + 49 = 50049, 達(dá)到低值 (50)
為新的高值1001調(diào)用序列,依次類推
因此一次序列調(diào)用,可生成50個(gè)鍵,從而減少數(shù)次來回網(wǎng)絡(luò)調(diào)用導(dǎo)致的負(fù)擔(dān)。
這些優(yōu)化的鍵生成器默認(rèn)在 Hibernate 4中開啟。如要禁用,可將 hibernate.id.new_generator_mappings 設(shè)置為 false。
為什么生成主鍵仍是一個(gè)問題?問題在于,如果你聲明鍵生成策略為 AUTO,且未啟用優(yōu)化的鍵生成器,那么應(yīng)用最后會面臨大量的序列調(diào)用。
為了確保啟用優(yōu)化的鍵生成器,請將鍵生成策略改為 SEQUENCE 而非 AUTO。
@Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "your_key_generator") private Long id;
改變設(shè)定之后,在插入操作頻繁的應(yīng)用中能看到10%到20%的性能提升,而且?guī)缀鯖]有改動代碼。
速成法2——使用 JDBC 批處理 inserts/updates對于批處理程序,JDBC 驅(qū)動程序提供了旨在減少網(wǎng)絡(luò)來回傳輸?shù)膬?yōu)化方法:”JDBC batch inserts/updates“。使用該方法后,插入或更新會先在驅(qū)動層排隊(duì),然后再傳送到數(shù)據(jù)庫。
當(dāng)達(dá)到閾值后,所有排隊(duì)的語句都會一次性傳給數(shù)據(jù)庫。這可以避免驅(qū)動程序逐一傳送語句,導(dǎo)致網(wǎng)絡(luò)來回傳送的負(fù)擔(dān)。
經(jīng)過以下配置,就能激活批處理 inserts/updates:
100 true true
僅設(shè)置 JDBC 批處理大小并不夠。因?yàn)?JDBC 驅(qū)動程序只會在收到對同一張表 insert/updates 時(shí)批處理這些語句。
如果收到對一張新表的插入語句,JDBC 驅(qū)動程序會先清除對前一張表的批處理語句,然后開始分批處理針對新表的 SQL 語句。
Spring Batch 內(nèi)置了相似的功能。該優(yōu)化能在插入操作頻繁的應(yīng)用中帶來30%到40%的性能提升,而不用改動任何代碼行。
速成法3——定期清理 Hibernate 會話在向數(shù)據(jù)庫添加或修改數(shù)據(jù)時(shí),Hibernate 會在會話中保留一版已經(jīng)存在的實(shí)體,以防在會話關(guān)閉之前這些實(shí)體再度被修改。
但是,多數(shù)情況下,一旦對應(yīng)的插入操作已經(jīng)在數(shù)據(jù)庫中完成,我們就可以安心地丟棄那些實(shí)體。這會釋放 Java 客戶端進(jìn)程中的內(nèi)存,避免過久的 Hibernate 會話導(dǎo)致的性能問題。
這種長久的會話應(yīng)該盡量避免。但如果出于某種原因不得不使用它們,以下是控制內(nèi)存消耗的方法:
entityManager.flush(); entityManager.clear();
flush 會觸使新實(shí)體中的插入語句傳送至數(shù)據(jù)庫。clear 則會釋放會話中的新實(shí)體。
速成法4——減少 Hibernate dirty-checking(臟數(shù)據(jù)檢查) 的代價(jià)Hibernate 內(nèi)部使用了一種機(jī)制用于追蹤被修改的實(shí)體,名為 dirty-checking。該機(jī)制并不基于實(shí)體類中的 equals 和 hashcode 方法。
Hibernate 盡可能將 dirty-checking 的性能成本保持在最低值,只在需要時(shí)使用 dirty-check。但是該機(jī)制也有成本,在列數(shù)很多的表中該成本尤其可觀。
在進(jìn)行任何優(yōu)化之前,最重要的是使用 VisualVM 測量 dirty-checking 的成本。
如何避免 dirty-checking ?dirty-checking 可以通過以下方式禁用:
@Transactional(readOnly=true) public void someBusinessMethod() { .... }
禁用 dirty-checking 的另一種方式是使用 Hibernate 無狀態(tài)會話,預(yù)知詳情請查看文檔。
速成法5——搜索”壞“查詢計(jì)劃
檢查最慢查詢列表,看看有沒有好的查詢計(jì)劃。最常見的”壞“查詢計(jì)劃包括:
全表搜索:通常缺少一個(gè)索引或表統(tǒng)計(jì)過期時(shí)進(jìn)行全表搜索。
全笛卡爾連接:意思是計(jì)算多張表的全笛卡爾乘積。檢查一下缺少的連接條件,或拆分為幾個(gè)步驟以簡化查詢。
速成法6——檢查錯誤的提交間隔如果你使用批處理程序,提交間隔會對性能造成十倍甚至百倍的影響。
請確保提交間隔是符合預(yù)期的(對于 Spring 批任務(wù),通常是100到1000之間)。經(jīng)常,該參數(shù)的配置不正確。
速成法7—— 使用二級查詢緩存如果一些數(shù)據(jù)可以緩存,則可以查看本文了解如何設(shè)置 Hibernate 緩存:Hibernate 二級/查詢緩存的陷阱。
結(jié)論解決應(yīng)用性能問題的關(guān)鍵,在于通過收集一些指標(biāo)發(fā)現(xiàn)當(dāng)前的瓶頸。
沒有一些測量指標(biāo),往往無法在短時(shí)間內(nèi)找到真正的問題根源。
此外,很多典型的數(shù)據(jù)庫驅(qū)動應(yīng)用的性能陷阱,如果一開始就使用了 Spring Batch,就能夠避免。
原文地址:http://blog.jhades.org/performance-tuning-of-spring-hibernate-applications/
OneAPM for Java 能夠深入到所有 Java 應(yīng)用內(nèi)部完成應(yīng)用性能管理和監(jiān)控,包括代碼級別性能問題的可見性、性能瓶頸的快速識別與追溯、真實(shí)用戶體驗(yàn)監(jiān)控、服務(wù)器監(jiān)控和端到端的應(yīng)用性能管理。想閱讀更多技術(shù)文章,請?jiān)L問 OneAPM 官方博客
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/64716.html
摘要:要是使用到日歷的話,我們想到使用這個(gè)日歷類上面僅僅是我個(gè)人總結(jié)的要點(diǎn),如果有錯誤的地方還請大家給我指正。 納稅服務(wù)系統(tǒng)總結(jié) 納稅服務(wù)系統(tǒng)是我第一個(gè)做得比較大的項(xiàng)目(不同于javaWeb小項(xiàng)目),該項(xiàng)目系統(tǒng)來源于傳智Java32期,十天的視頻課程(想要視頻的同學(xué)關(guān)注我的公眾號就可以直接獲取了) 我跟著練習(xí)一步一步完成需求,才發(fā)覺原來Java是這樣用來做網(wǎng)站的,Java有那么多的類庫,頁面...
摘要:入門篇學(xué)習(xí)總結(jié)時(shí)間年月日星期三說明本文部分內(nèi)容均來自慕課網(wǎng)。主要的功能是日志記錄,性能統(tǒng)計(jì),安全控制,事務(wù)處理,異常處理等等。 《Spring入門篇》學(xué)習(xí)總結(jié) 時(shí)間:2017年1月18日星期三說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學(xué)示例源碼:https://github.com/zccodere/s...個(gè)人學(xué)習(xí)源碼:https://git...
摘要:在框假中充當(dāng)了管理容器的角色。中也有對事務(wù)的管理,中事務(wù)管理是通過創(chuàng)建和維護(hù)來完成。這也就是所謂控制反轉(zhuǎn)的概念所在依賴控制權(quán)由應(yīng)用代碼中轉(zhuǎn)到了外部容器,控制權(quán)的轉(zhuǎn)移,是所謂反轉(zhuǎn)。 在SSH框假中spring充當(dāng)了管理容器的角色。我們都知道Hibernate用來做持久層,因?yàn)樗鼘DBC做了一個(gè)良好的封裝,程序員在與數(shù)據(jù)庫進(jìn)行交互時(shí)可以不用書寫大量的SQL語句。Struts是用來做應(yīng)用層...
摘要:最近在做某在線教育平臺網(wǎng)站的開發(fā),按師兄的建議要用來搞。現(xiàn)在把開發(fā)過程中的一些相關(guān)經(jīng)驗(yàn)貼出來。事先聲明,請確保和都已經(jīng)安裝好。對于不使用的開發(fā)者,可以直接建一個(gè)簡單的項(xiàng)目。使用的話,請按照圖進(jìn)行操作。 訪問GitHub下載最新源碼:https://github.com/gaussic/Sp... 文章已針對IDEA 2016做了一定的更新,部分更新較為重要,請重新閱讀文章并下載最新源碼...
近期在維護(hù)公司項(xiàng)目的時(shí)候遇到一個(gè)問題,因?yàn)閷?shí)體類中的 set 方法涉及到了業(yè)務(wù)邏輯,因此在給對象賦值的過程中不能夠使用 set 方法,為了實(shí)現(xiàn)功能,所以采用了反射的機(jī)制給對象屬性賦值,借此機(jī)會也了解了反射的一些具體用法和使用場景,分以下兩點(diǎn)對反射進(jìn)行分析: 反射的優(yōu)勢和劣勢 反射的應(yīng)用場景 反射的優(yōu)勢和劣勢 ??個(gè)人理解,反射機(jī)制實(shí)際上就是上帝模式,如果說方法的調(diào)用是 Java 正確的打開方式...
閱讀 818·2021-10-25 09:48
閱讀 610·2021-08-23 09:45
閱讀 2496·2019-08-30 15:53
閱讀 1758·2019-08-30 12:45
閱讀 585·2019-08-29 17:21
閱讀 3406·2019-08-27 10:56
閱讀 2546·2019-08-26 13:48
閱讀 690·2019-08-26 12:24