轉(zhuǎn)帖|行業(yè)資訊|編輯:龔雪|2016-05-06 17:46:34.000|閱讀 267 次
概述:你的Java應(yīng)用程序的性能是怎樣診斷和優(yōu)化的?不妨看看這兩位西醫(yī)的方子。如果你有更好療效的藥方,也歡迎在評(píng)論區(qū)告訴我們。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門(mén)軟控件火熱銷售中 >>
當(dāng)我在幫助一些開(kāi)發(fā)者或架構(gòu)師分析及優(yōu)化Java應(yīng)用程序的性能時(shí),關(guān)鍵往往不在于對(duì)個(gè)別方法進(jìn)行微調(diào),以節(jié)省一或兩微秒的執(zhí)行時(shí)間。雖然對(duì)某些軟件來(lái)說(shuō),微秒級(jí)的優(yōu)化確實(shí)非常重要,但我認(rèn)為這并非著眼點(diǎn)所在。我在2015年間對(duì)數(shù)百個(gè)應(yīng)用進(jìn)行了分析,發(fā)現(xiàn)多數(shù)性能與可伸縮性問(wèn)題都來(lái)源于糟糕的架構(gòu)決策、框架的錯(cuò)誤配置、錯(cuò)誤的數(shù)據(jù)庫(kù)訪問(wèn)模式、過(guò)量的日志記錄,以及由于內(nèi)存過(guò)度消耗而導(dǎo)致的垃圾回收所帶來(lái)的影響。
在我看來(lái),性能工程的根本在于通過(guò)大量的觀察,將關(guān)鍵的架構(gòu)指標(biāo)、可伸縮性指標(biāo)以及性能指標(biāo)關(guān)聯(lián)在一起。通過(guò)對(duì)每次構(gòu)建的結(jié)果以及不同負(fù)載情況下的表現(xiàn)進(jìn)行分析,以發(fā)現(xiàn)系統(tǒng)中的回歸缺陷或瓶頸所在。以下圖中的儀表板作為示例:
通過(guò)將系統(tǒng)負(fù)載、響應(yīng)時(shí)間與SQL語(yǔ)句的執(zhí)行次數(shù)等指標(biāo)相關(guān)聯(lián),可得出某些性能工程方面問(wèn)題的根本原因。
最上面一張圖叫做“層分解”圖表,它顯示了你的應(yīng)用中各個(gè)邏輯組件(例如Web Service、數(shù)據(jù)庫(kù)訪問(wèn)、業(yè)務(wù)邏輯、Web服務(wù)器等等)的總體執(zhí)行時(shí)間。紅色部分所表示的是某個(gè)后端Web Service所花費(fèi)的時(shí)間,很明顯這里產(chǎn)生了一個(gè)組件熱點(diǎn)。
我們同時(shí)可以發(fā)現(xiàn),該Web Service并沒(méi)有承受異常的負(fù)載,因?yàn)閺牡诙垐D來(lái)看,當(dāng)時(shí)應(yīng)用程序所處理的請(qǐng)求數(shù)量這條線比較平穩(wěn)。一般情況下,整體響應(yīng)時(shí)間多數(shù)都耗費(fèi)在數(shù)據(jù)層,但這并不代表數(shù)據(jù)庫(kù)本身的速度緩慢!我了解,低效的數(shù)據(jù)庫(kù)訪問(wèn)往往是造成性能不佳的主要原因,因此通常會(huì)結(jié)合分析SQL語(yǔ)句的執(zhí)行次數(shù)。在這個(gè)示例中,已經(jīng)能夠很清楚地看到它與大多數(shù)響應(yīng)時(shí)間的峰值是相關(guān)的。
我所觀察到最常見(jiàn)的問(wèn)題模式就是糟糕的數(shù)據(jù)庫(kù)訪問(wèn)模式,此外還有過(guò)于細(xì)粒度的服務(wù)調(diào)用、糟糕的共享數(shù)據(jù)訪問(wèn)共享、過(guò)度的日志記錄,以及由內(nèi)存泄露以及大量的對(duì)象創(chuàng)建所導(dǎo)致的垃圾回收影響或是應(yīng)用程序的崩潰。
在本文中,我將專注于探討數(shù)據(jù)庫(kù)方面的問(wèn)題,因?yàn)槲沂执_信你的所有應(yīng)用都是因這些訪問(wèn)模式中的某一種而產(chǎn)生問(wèn)題的!你可以在市場(chǎng)上已有的各種性能診斷、追蹤,或是APM工具之間隨意選擇。Perfino就是一款不錯(cuò)的產(chǎn)品,還有免費(fèi)的Dynatrace Personal License。Java本身也提供了各種出色的工具,例如Java Mission Control等等。許多提供數(shù)據(jù)訪問(wèn)功能的框架也經(jīng)常通過(guò)其日志輸出提供各種診斷選項(xiàng),例如Hibernate或Spring等等。
在使用這些跟蹤工具時(shí),通常不需要對(duì)代碼進(jìn)行任何修改,因?yàn)樗麄兌祭昧薐VMTI(JVM Tooling Interface)以捕獲代碼層面的信息,甚至能夠跨遠(yuǎn)程的各層次進(jìn)行調(diào)用追蹤,這一點(diǎn)對(duì)于分布式、面向(微)服務(wù)的應(yīng)用來(lái)說(shuō)非常實(shí)用。你所要做的就是修改你的JVM啟動(dòng)命令行選項(xiàng),以加載這些工具。
某些工具的開(kāi)發(fā)商還提供了與IDE的集成功能,你只需簡(jiǎn)單地表示“在運(yùn)行時(shí)開(kāi)啟XYZ性能診斷功能”。我在YouTube上做了一個(gè)簡(jiǎn)單的視頻指南,演示了如何對(duì)在Eclipse中啟動(dòng)的應(yīng)用進(jìn)行追蹤。(//www.youtube.com/watch?v=unrey8wfq-M&list=PLqt2rd0eew1bmDn54E2_M2uvbhm_WxY_6&index=14)
即使你已經(jīng)發(fā)現(xiàn)造成應(yīng)用整體響應(yīng)時(shí)間過(guò)長(zhǎng)的主要原因在于數(shù)據(jù)庫(kù),但也不要因此就輕率地指責(zé)數(shù)據(jù)庫(kù)與DBA!造成數(shù)據(jù)庫(kù)繁忙的原因可能有以下幾種:
在本文中,我將著重講解如何在應(yīng)用程序端將訪問(wèn)數(shù)據(jù)庫(kù)所消耗的時(shí)間減至最低。
在對(duì)應(yīng)用程序進(jìn)行問(wèn)題診斷時(shí),我通常總要檢查幾個(gè)數(shù)據(jù)庫(kù)訪問(wèn)模式。我會(huì)逐個(gè)分析應(yīng)用的請(qǐng)求,并將這些問(wèn)題分別放入以下這個(gè)“DB問(wèn)題模式”的分類表中:
我的第一個(gè)示例是一個(gè)web應(yīng)用程序,它能夠提供某幢大樓中的會(huì)議室信息。會(huì)議室的信息都保存在某個(gè)數(shù)據(jù)庫(kù)中,每次當(dāng)用戶生成會(huì)議室信息的報(bào)表時(shí),就會(huì)調(diào)用某個(gè)自定義的數(shù)據(jù)訪問(wèn)層以訪問(wèn)該數(shù)據(jù)庫(kù)。
在對(duì)個(gè)別請(qǐng)求進(jìn)行分析時(shí),我總是從所謂的事務(wù)流(Transaction Flow)著手檢查。事務(wù)流是一種可視化選項(xiàng),可展現(xiàn)出應(yīng)用程序處理請(qǐng)求的過(guò)程。對(duì)于會(huì)議室信息報(bào)表這個(gè)請(qǐng)求來(lái)說(shuō),可以看到,該請(qǐng)求首先進(jìn)入web服務(wù)器層(圖左)、隨后進(jìn)入應(yīng)用服務(wù)層(圖中),然后對(duì)數(shù)據(jù)層發(fā)起調(diào)用(圖右)。這些層之間的“鏈接”表現(xiàn)了這些層之間的交互次數(shù),例如這個(gè)單一的請(qǐng)求執(zhí)行了多少次SQL查詢。
從這個(gè)屏幕上我們可以立即發(fā)現(xiàn)造成問(wèn)題的頭兩種模式,即過(guò)多的SQL執(zhí)行模式以及數(shù)據(jù)庫(kù)繁忙模式。讓我們來(lái)分析一下:
很容易就可以看出這個(gè)請(qǐng)求產(chǎn)生了大量的SQL語(yǔ)句執(zhí)行,并且造成數(shù)據(jù)庫(kù)繁忙效應(yīng):它總共執(zhí)行了24889次SQL!花費(fèi)了40.27秒(占整個(gè)請(qǐng)求時(shí)間的66.51%)才完成整個(gè)執(zhí)行過(guò)程!
如果我們對(duì)個(gè)別的SQL語(yǔ)句進(jìn)行分析,將發(fā)現(xiàn)這個(gè)請(qǐng)求還有另外的問(wèn)題,即N+1 次查詢問(wèn)題以及低效的連接池訪問(wèn)(下文將進(jìn)行詳細(xì)討論):
這種糟糕的訪問(wèn)模式是無(wú)法通過(guò)對(duì)數(shù)據(jù)庫(kù)的索引進(jìn)行優(yōu)化而解決的。
我已經(jīng)無(wú)數(shù)次看到這種問(wèn)題發(fā)生了。應(yīng)用的邏輯需要對(duì)某個(gè)對(duì)象列表進(jìn)行迭代,但它并沒(méi)有選擇使用“貪婪加載”(Eager Loading)方式,則是使用了“延遲加載”(Lazy Loading)方式。這種選擇可能來(lái)自于O/R映射框架,例如Hibernate或Spring,也可能來(lái)自于自主開(kāi)發(fā)的框架,正如上文所述的示例一樣。該示例使用了某種自主開(kāi)發(fā)的實(shí)現(xiàn)方式,它會(huì)加載每個(gè)會(huì)議室對(duì)象,并通過(guò)獨(dú)立的SQL查詢語(yǔ)句獲取每個(gè)會(huì)議室的全部屬性。
每個(gè)SQL查詢都是在一個(gè)向連接池獲取的JDBC連接中執(zhí)行的,然后在每個(gè)查詢完成之后都會(huì)返回。這也解釋了為什么該請(qǐng)求會(huì)產(chǎn)生12444次set clientname操作,因?yàn)镾ybase JDBC驅(qū)動(dòng)每次向連接池請(qǐng)求連接時(shí)都會(huì)提交這一請(qǐng)求。這就是問(wèn)題所在!其他的JDBC驅(qū)動(dòng)未必會(huì)產(chǎn)生set clientname這個(gè)調(diào)用,你可以查看一下調(diào)用getConnection的次數(shù),這同樣可反映出這個(gè)問(wèn)題。
對(duì)于N+1次查詢問(wèn)題本身來(lái)說(shuō),使用連接查詢就可以輕易地避免這一問(wèn)題。在這個(gè)會(huì)議室與屬性的示例中,可以使用以下連接查詢:
select r.*, p.* from meeting_rooms as r inner join room_properties as p on p.room_id = r.room_id
結(jié)果就是整個(gè)執(zhí)行過(guò)程只產(chǎn)生了1次查詢執(zhí)行,不再是12000多次了!同時(shí)也免除了12000次連接的獲取操作以及對(duì)“set clientname”的調(diào)用。
據(jù)我所知,Hibernate或其他O/R映射器有許多使用者。我想要提醒你們一點(diǎn),O/R映射器所提供的延遲加載與貪婪加載選項(xiàng),以及其他各種緩存層各有其存在的理由。對(duì)于特定的用例,需要確保你正確地使用了這些特性與選項(xiàng)。
在下面這個(gè)示例中,延遲加載并不是一種好的選擇,因?yàn)榧虞d2千個(gè)對(duì)象以及他們的屬性會(huì)導(dǎo)致產(chǎn)生4千多次SQL查詢。考慮到我們總是需要獲取所有對(duì)象,那么更好的方式是貪婪加載這些對(duì)象,然后考慮對(duì)他們進(jìn)行緩存,前提是這些對(duì)象不會(huì)變更得十分頻繁:
在使用Hibernate或Spring等O/R映射器時(shí),需要選擇正確的加載與緩存選項(xiàng)。你需要理解他們的幕后工作原理。
大多數(shù)O/R映射器都會(huì)通過(guò)日志記錄提供優(yōu)秀的診斷選項(xiàng),同時(shí)也可以查看在線社區(qū)中的內(nèi)容,以了解各種最佳實(shí)踐。推薦你閱讀由Alois Reitbauer撰寫(xiě)的一系列博客文章,他曾經(jīng)在Hibernate推出的早些年頭對(duì)其進(jìn)行過(guò)非常深入的研究。在這系列文章中,他特別強(qiáng)調(diào)了如何有效地使用緩存與加載選項(xiàng)。
當(dāng)數(shù)據(jù)庫(kù)引擎完成對(duì)某條SQL語(yǔ)句的解析,并創(chuàng)建了數(shù)據(jù)訪問(wèn)的執(zhí)行計(jì)劃后,該結(jié)果會(huì)被保存在數(shù)據(jù)庫(kù)中的一個(gè)緩存區(qū)域中以便重用,而無(wú)需重新解析這一語(yǔ)句(語(yǔ)句解析是數(shù)據(jù)庫(kù)中最耗費(fèi)CPU時(shí)間的操作)。用于在緩存中找到某個(gè)查詢的鍵是語(yǔ)句的全文本。這也意味著,如果你調(diào)用了1000次相同的語(yǔ)句,卻為其傳了100個(gè)不同的參數(shù)值(例如where語(yǔ)句中的值),那么在緩存中就會(huì)產(chǎn)生1000個(gè)不同的條目,而使用了新參數(shù)的第1001次查詢也必須被再次解析。這種工作方式非常低效。
因此,我們提出了“預(yù)處理的語(yǔ)句”這一概念:某條語(yǔ)句經(jīng)過(guò)預(yù)處理、解析后被保存在緩存中,以占位符的方式表示變量。在這條語(yǔ)句的實(shí)際執(zhí)行過(guò)程中,這些占位符會(huì)被實(shí)際的值所替換,無(wú)需再次解析這條語(yǔ)句,可以直接從緩存中找出執(zhí)行計(jì)劃。
數(shù)據(jù)庫(kù)訪問(wèn)框架通常在這一點(diǎn)上做得很出色,會(huì)對(duì)查詢語(yǔ)句進(jìn)行預(yù)處理。但在自定義代碼中,我發(fā)現(xiàn)開(kāi)發(fā)者經(jīng)常會(huì)忽略這一點(diǎn)。在以下示例中,只有一小部分SQL執(zhí)行經(jīng)過(guò)了預(yù)處理過(guò)程:
通過(guò)對(duì)SQL執(zhí)行次數(shù)與已預(yù)處理的SQL執(zhí)行次數(shù)進(jìn)行對(duì)比,發(fā)現(xiàn)了未經(jīng)預(yù)處理的數(shù)據(jù)庫(kù)訪問(wèn)的問(wèn)題
如果你打算自行開(kāi)發(fā)數(shù)據(jù)庫(kù)訪問(wèn)代碼,請(qǐng)?jiān)俅未_認(rèn)你正確地調(diào)用了prepareStatement。舉例來(lái)說(shuō),如果你調(diào)用某個(gè)查詢不止1次,那么通常來(lái)說(shuō)最好能夠使用PreparedStatement。如果你選擇使用框架以訪問(wèn)數(shù)據(jù),也請(qǐng)?jiān)俅未_認(rèn)這些框架的行為,以及在優(yōu)化和執(zhí)行所生成的SQL時(shí)有哪些配置選項(xiàng)可以選擇。實(shí)現(xiàn)一點(diǎn)最簡(jiǎn)單的方式是對(duì)executeStatement與prepareStatement執(zhí)行的次數(shù)進(jìn)行監(jiān)控。如果你重復(fù)對(duì)每個(gè)SQL查詢進(jìn)行相同的監(jiān)控,那么將很容易地找到優(yōu)化熱點(diǎn)。
我經(jīng)常發(fā)現(xiàn)有些應(yīng)用會(huì)使用默認(rèn)的連接池大小,例如每個(gè)池10或20個(gè)連接。開(kāi)發(fā)者總是會(huì)忽略對(duì)連接池大小的優(yōu)化,因?yàn)樗麄儧](méi)有進(jìn)行必要的大規(guī)模負(fù)載測(cè)試,也不知道有多少個(gè)用戶會(huì)使用這些新特性,更不了解并行的DB訪問(wèn)會(huì)導(dǎo)致什么結(jié)果。也有可能是從預(yù)發(fā)布環(huán)境轉(zhuǎn)向生產(chǎn)環(huán)境的部署時(shí)“丟失”了連接池的配置信息,導(dǎo)致生產(chǎn)環(huán)境中的配置使用了應(yīng)用服務(wù)器中的默認(rèn)配置。
通過(guò)JMX指標(biāo)信息,能夠方便地對(duì)連接池的使用情況進(jìn)行監(jiān)控。每種應(yīng)用服務(wù)器(Tomcat、JBoss、Websphere等等)都會(huì)提供這些指標(biāo),不過(guò)有些服務(wù)器需要你明確地開(kāi)啟這種特性。下圖展示了某個(gè)群集中的WebLogic服務(wù)器的連接池使用情況。你可以看到,在其中三臺(tái)應(yīng)用服務(wù)器中,“活動(dòng)的DB連接數(shù)量”都已經(jīng)達(dá)到最大值。
確保你適當(dāng)?shù)卣{(diào)整了連接池的大小,不要使用與你期待的負(fù)載情況不符的默認(rèn)設(shè)置
出現(xiàn)這一問(wèn)題的根本原因不在于訪問(wèn)量的峰值。在本文開(kāi)頭部分所介紹的“系統(tǒng)負(fù)載 / 響應(yīng)時(shí)間 / 數(shù)據(jù)庫(kù)執(zhí)行次數(shù)”這個(gè)儀表板中顯示,應(yīng)用并沒(méi)有產(chǎn)生特別的訪問(wèn)量峰值情況。最終發(fā)現(xiàn),在每天下午2點(diǎn)多這個(gè)時(shí)間段設(shè)定了一個(gè)運(yùn)行報(bào)表的計(jì)劃,它需要執(zhí)行多個(gè)運(yùn)行時(shí)間相當(dāng)長(zhǎng)的UPDATE語(yǔ)句,每個(gè)語(yǔ)句都使用了不同的連接。這會(huì)在幾分鐘內(nèi)阻塞其他連接,導(dǎo)致了應(yīng)用程序在“正常的”訪問(wèn)量下出現(xiàn)性能問(wèn)題,因?yàn)橛脩舻恼?qǐng)求無(wú)法獲得數(shù)據(jù)庫(kù)的連接:
個(gè)別的SQL執(zhí)行阻塞了其他連接達(dá)幾分鐘,造成了連接池資源消耗殆盡的問(wèn)題
如果你已經(jīng)了解到某些請(qǐng)求會(huì)使連接掛起一段較長(zhǎng)的時(shí)間,你可以選擇以下幾種方案:
不過(guò),首先你要確保對(duì)這些查詢進(jìn)行優(yōu)化。通過(guò)分析SQL查詢執(zhí)行計(jì)劃,以找出哪些操作是最耗時(shí)的。如今,大多數(shù)APM工具都能夠讓你以某種方式獲取某個(gè)SQL語(yǔ)句的執(zhí)行計(jì)劃。如果沒(méi)有可用的工具,最簡(jiǎn)單的方式就是使用數(shù)據(jù)庫(kù)的命令行工具,或者咨詢某個(gè)DBA,讓他幫助你生成執(zhí)行計(jì)劃。
通過(guò)學(xué)習(xí)SQL查詢執(zhí)行計(jì)劃,對(duì)你的SQL語(yǔ)句進(jìn)行優(yōu)化
執(zhí)行計(jì)劃能夠顯示出DB引擎處理SQL語(yǔ)句的方式。造成SQL語(yǔ)句執(zhí)行緩慢的原因多種多樣,不僅僅限于缺少索引或是使用索引的方式不對(duì),很多情況下是因?yàn)樵O(shè)計(jì)、結(jié)構(gòu)或連接查詢所造成的。如果你并非SQL方面的專家,可以向DBA或SQL大牛求助。
負(fù)載測(cè)試以及在生產(chǎn)環(huán)境中進(jìn)行監(jiān)控的提示與技巧
除了對(duì)各個(gè)請(qǐng)求進(jìn)行分析,以指出這些問(wèn)題模式之外,我同樣也會(huì)關(guān)注當(dāng)某個(gè)應(yīng)用程序在負(fù)載情況下的長(zhǎng)期趨勢(shì)。除了我在本文開(kāi)頭為你展示的儀表板之外,我也會(huì)指出數(shù)據(jù)驅(qū)動(dòng)行為的變化,并對(duì)數(shù)據(jù)緩存是否正確運(yùn)行進(jìn)行驗(yàn)證。
下面這張圖表展示了SQL語(yǔ)句執(zhí)行的平均次數(shù)(綠色)以及SQL語(yǔ)句執(zhí)行的總次數(shù)(藍(lán)色)。我們?yōu)閼?yīng)用進(jìn)行了一次兩小時(shí)的性能測(cè)試,保持負(fù)載始終處于較高水平。我所期望的結(jié)果是平均次數(shù)逐漸減少,而總次數(shù)則趨向平穩(wěn)。因?yàn)榘凑瘴业募僭O(shè),從DB所獲取的數(shù)據(jù)大多數(shù)是靜態(tài)的,或是會(huì)被緩存在某個(gè)不同的層。
如果你的應(yīng)用表現(xiàn)不符合這一預(yù)期,那么可能是遇到了數(shù)據(jù)驅(qū)動(dòng)的性能問(wèn)題,或是產(chǎn)生了緩存問(wèn)題
假設(shè)如我之前所展示的一樣,你的應(yīng)用中產(chǎn)生了常見(jiàn)的N+1次查詢問(wèn)題。那么隨著終端用戶在DB中產(chǎn)生越來(lái)越多的數(shù)據(jù),應(yīng)用程序所產(chǎn)生的SQL平均次數(shù)也將不斷提高,因?yàn)檫@些查詢所返回的數(shù)據(jù)也會(huì)越來(lái)越多!因此,請(qǐng)務(wù)必注意這些數(shù)字!
示例4表現(xiàn)了某個(gè)后臺(tái)報(bào)表應(yīng)用在每天下午2點(diǎn)執(zhí)行所造成的問(wèn)題,與之類似,我同樣也會(huì)關(guān)注SQL訪問(wèn)隨著時(shí)間變化的模式。我所關(guān)注的不僅包括總執(zhí)行時(shí)間,同時(shí)也包括SELECT、INSERT、UPDATE與DELETE的執(zhí)行次數(shù)。這樣一來(lái),我就能夠指出是否在某個(gè)時(shí)間段內(nèi)會(huì)進(jìn)行一些特別的活動(dòng),例如通過(guò)后臺(tái)作業(yè)對(duì)大批數(shù)據(jù)進(jìn)行更新。
通過(guò)觀察總執(zhí)行時(shí)間,以及SELECT、INSERT、UPDATE與DELETE的執(zhí)行次數(shù),了解應(yīng)用的數(shù)據(jù)庫(kù)訪問(wèn)行為
進(jìn)行大量更新操作的批處理作業(yè)的執(zhí)行需要一段時(shí)間才能完成,尤其對(duì)于包含大量行的表來(lái)說(shuō)更為明顯。如果整張表因此被鎖住,那么其他需要對(duì)這張表、哪怕只是對(duì)其中某些行進(jìn)行更新的請(qǐng)求都必須等待鎖被釋放。你應(yīng)考慮在沒(méi)有其他用戶在線的時(shí)間段運(yùn)行這些作業(yè),或?qū)崿F(xiàn)某種不同的加鎖邏輯,實(shí)現(xiàn)對(duì)單個(gè)行的加鎖、更新以及釋放操作。
在本文中,我著重分析的數(shù)據(jù)庫(kù)性能問(wèn)題多數(shù)與數(shù)據(jù)庫(kù)服務(wù)器本身是否緩慢是無(wú)關(guān)的,而主要是由使用了糟糕的數(shù)據(jù)庫(kù)訪問(wèn)模式(N+1次查詢問(wèn)題、未經(jīng)預(yù)處理的語(yǔ)句等等)的應(yīng)用程序代碼、或是配置錯(cuò)誤(低效的連接池訪問(wèn)、數(shù)據(jù)驅(qū)動(dòng)問(wèn)題)所導(dǎo)致的問(wèn)題。
但是,如果我們完全忽略了數(shù)據(jù)庫(kù)本身,那也是不明智的。因此,我總是會(huì)對(duì)關(guān)鍵的數(shù)據(jù)庫(kù)性能指標(biāo)進(jìn)行檢查。大多數(shù)數(shù)據(jù)庫(kù)都會(huì)通過(guò)特殊的系統(tǒng)表提供豐富的性能信息,比如Oracle就會(huì)提供某些v$表以及視圖,以訪問(wèn)關(guān)鍵的數(shù)據(jù)庫(kù)性能指標(biāo)(會(huì)話、等待時(shí)間、解析時(shí)間、執(zhí)行時(shí)間等等),或是表鎖以及運(yùn)行時(shí)間較慢的SQL等信息,這些信息來(lái)自于使用這個(gè)共享的數(shù)據(jù)庫(kù)實(shí)例的各個(gè)應(yīng)用程序。
我在進(jìn)行數(shù)據(jù)庫(kù)健康檢查時(shí)通常會(huì)觀察兩個(gè)儀表板,你可以在此看到來(lái)自于這些性能表中的指標(biāo)數(shù)據(jù):
觀察數(shù)據(jù)庫(kù)是處于健康狀態(tài),還是由于共享該數(shù)據(jù)庫(kù)實(shí)例的應(yīng)用產(chǎn)生過(guò)多的負(fù)載而產(chǎn)生了影響。
通過(guò)表鎖等信息,判斷是否有某個(gè)正在執(zhí)行中的SQL語(yǔ)句對(duì)服務(wù)器乃至你的應(yīng)用造成了負(fù)面影響
在持續(xù)集成流程中對(duì)數(shù)據(jù)庫(kù)指標(biāo)進(jìn)行自動(dòng)檢測(cè)
在我為你介紹分析關(guān)鍵數(shù)據(jù)庫(kù)指標(biāo)以及用例的一些新點(diǎn)子之前,我希望首先能夠彌補(bǔ)一個(gè)缺失的主題,而這一點(diǎn)是我們都應(yīng)當(dāng)考慮到的,那就是自動(dòng)化!
我建議你不要手動(dòng)地執(zhí)行這些檢查步驟,而是通過(guò)持續(xù)集成工具檢查這些指標(biāo),將這一步驟與單元測(cè)試、集成測(cè)試、REST API或其他類型的功能性測(cè)試等步驟結(jié)合在一起。如果你已經(jīng)設(shè)計(jì)出一套測(cè)試用例集,用于檢查各種REST API或新特性的功能,那么為什么不在每次構(gòu)建的測(cè)試執(zhí)行期間去捕獲這些指標(biāo)呢?這種方式可以帶來(lái)以下益處:
下面這幅屏幕截圖展示了每次構(gòu)建與每次測(cè)試時(shí)對(duì)這些指標(biāo)的追蹤,并在其表現(xiàn)異常時(shí)發(fā)出警告。你可以將這些指標(biāo)集成在你的構(gòu)建管道中,并且當(dāng)某個(gè)代碼變更造成影響時(shí)通過(guò)通知信息了解情況,隨后立即修復(fù)這一問(wèn)題,避免當(dāng)代碼發(fā)布到生產(chǎn)環(huán)境時(shí)產(chǎn)生系統(tǒng)崩潰的情況。
在你的持續(xù)集成流程中加入這些指標(biāo),并對(duì)指標(biāo)的變化進(jìn)行觀察,以自動(dòng)地找出各種糟糕的數(shù)據(jù)庫(kù)訪問(wèn)模式!
在本文中,我們專注的是數(shù)據(jù)庫(kù)方面的熱點(diǎn)問(wèn)題。但在我的工作過(guò)程中,我也在其他領(lǐng)域發(fā)現(xiàn)許多類型的性能問(wèn)題。在2015年,我參與了一個(gè)將一體性應(yīng)用遷移為(微)服務(wù)的項(xiàng)目,在其中發(fā)現(xiàn)了一個(gè)巨大的峰值問(wèn)題。該問(wèn)題類似于我們已分析過(guò)的某些模式,例如N+1次查詢問(wèn)題,原因在于某個(gè)用例會(huì)數(shù)百次調(diào)用某個(gè)后端服務(wù)。
大多數(shù)情況下,這種問(wèn)題都是由糟糕的接口設(shè)計(jì)而造成的,并且沒(méi)有考慮到某個(gè)原本在本地調(diào)用的方法在Docker容器或云計(jì)算環(huán)境中被執(zhí)行時(shí)會(huì)發(fā)生什么。網(wǎng)絡(luò)問(wèn)題會(huì)突然間出現(xiàn),包括通過(guò)網(wǎng)絡(luò)傳輸?shù)男畔⒁约靶碌倪B接池(意味著你需要考慮線程與套接字),這些問(wèn)題是你必須處理的。
原文翻譯自:
文章轉(zhuǎn)載自:
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@fc6vip.cn