【转】使用JMeter对数据库做压力测试
作為一名開發(fā)人員,大多情況下都會(huì)認(rèn)真的做好功能測(cè)試,但是卻常常忽略了軟件開發(fā)之后的壓力測(cè)試,尤其是在面向大量用戶同時(shí)使用的Web應(yīng)用系統(tǒng)的開發(fā)過程,壓力測(cè)試往往是不夠充分的。近期我在一個(gè)求職招聘型的網(wǎng)站項(xiàng)目中就對(duì)壓力測(cè)試的重要性體會(huì)頗深。
在項(xiàng)目中,我負(fù)責(zé)開發(fā)職位信息的搜索部分,但是由于缺乏壓力測(cè)試,倉(cāng)促將搜素部分的功能提交到生產(chǎn)環(huán)境,結(jié)果當(dāng)并發(fā)量稍稍到達(dá)一定程度時(shí),數(shù)據(jù)庫(kù)系統(tǒng)便已經(jīng)不堪重負(fù)。無奈之下向網(wǎng)上資源查詢解決方法,其中一個(gè)就是對(duì)現(xiàn)有的應(yīng)用做足夠到位的壓力測(cè)試。
壓力測(cè)試有著很豐富的內(nèi)容,而這里,我只針對(duì)應(yīng)用中所遇到的問題以及解決方法做一個(gè)簡(jiǎn)單的描述,希望對(duì)以后遇到同樣問題的朋友能夠起到些許幫助作用。
我自己做的例子使用的環(huán)境是:
測(cè)試工具:JMeter 2.3.1
數(shù)據(jù)庫(kù):Oracle?10G
其他環(huán)境:JDK 1.6.0_05(也可以使用JDK1.4及以上版本)
1.創(chuàng)建好的JMeter測(cè)試計(jì)劃樹形結(jié)構(gòu)圖如下:
2.在剛打開JMeter的時(shí)候,默認(rèn)會(huì)存在兩個(gè)節(jié)點(diǎn),一個(gè)是“Test?Plan”,點(diǎn)擊這個(gè)節(jié)點(diǎn),在右邊的屬性頁(yè)面中,命名為“我們的數(shù)據(jù)庫(kù)測(cè)試計(jì)劃”
在屬性頁(yè)的最下面,我們看到設(shè)置jar包所在路徑的選項(xiàng),默認(rèn)存在一個(gè)選項(xiàng)"E:\software\develop\testunit\jMeter \jakarta-jmeter-2.3.1\lib",這個(gè)是我的機(jī)器中JMeter的lib目錄,在這個(gè)例子中,Oracle的jdbc驅(qū)動(dòng)也已經(jīng)拷貝到該目錄下。
3.新增一個(gè)“Thread Group”,重命名為“使用變化的SQL來做數(shù)據(jù)庫(kù)壓力測(cè)試”。其中,“Number of Threads”表示的是JMeter會(huì)同時(shí)創(chuàng)建多少個(gè)線程來進(jìn)行壓力測(cè)試,對(duì)于一個(gè)網(wǎng)站而言,也就是模擬一次存在多少個(gè)用戶來訪問該網(wǎng)站;而“Ramp-Up Period(in seconds)”表示JMeter每個(gè)多少秒發(fā)動(dòng)并發(fā);“Loop Count”則是指配置好的并發(fā)情形發(fā)生多少次。
4.在“Thead Group”下創(chuàng)建一個(gè)“User Defined Variables”,即用戶自定義變量,重命名為“我們定義的動(dòng)態(tài)語句部分”,這里我們使用它來生成動(dòng)態(tài)SQL語句,讓用戶每次訪問數(shù)據(jù)庫(kù)的SQL語句都不一樣,這樣減少Oracle數(shù)據(jù)庫(kù)對(duì)相同SQL語句的緩存對(duì)測(cè)試結(jié)果所帶來的影響。
變量定義的完整內(nèi)容如下:
| Name | Value |
| str | ${__split(D610 or 筆記本|D610 or D620|D620|服務(wù)器,keyword,|)} |
| many_sql | p_name like '%D610%' or p_name like '%AIX%'| p_name like '%筆記本%' or p_name like '%D610%'|p_name like '%D610%'| p_name like '%AIX%' |
| smt | ${__split(${many_sql},smt,|)} |
注:${__split(...)} 是JMeter中自帶的拆分字符串為數(shù)組的函數(shù),可以通過JMeter工具欄"Options"->"Function Helper Dialog"來打開函數(shù)代碼輔助工具生成我們所需的函數(shù)調(diào)用。
另外有個(gè)需要注意的問題是:在${__split(...)} 中,如果拆分字符串中的內(nèi)容包含有符號(hào)",",一定得用符號(hào)"\"進(jìn)行轉(zhuǎn)義,否則可能被JMeter誤認(rèn)為是參數(shù)分隔符,會(huì)導(dǎo)致無法正確生成字符串?dāng)?shù)組。
5.接下來是配置JDBC連接設(shè)置
6.創(chuàng)建一個(gè)具體的JDBC請(qǐng)求
"Query Type"中選擇的是預(yù)編譯語句;
SQL語句當(dāng)中,動(dòng)態(tài)內(nèi)容的代碼行是"and contains(p.p_name,?) > 0",這里的"?"就是預(yù)編譯語句中的動(dòng)態(tài)參數(shù),在屬性頁(yè)下面的"Parameter Values"和"Parameter types"來指定,由于預(yù)編譯語句在Java教程已有很多講解,這里不再贅述。
注:這里有一個(gè)JMeter的函數(shù)"__V..."沒有提到,將在后面說明另外一個(gè)JDBC調(diào)用測(cè)試的時(shí)候進(jìn)行補(bǔ)充。
?
7.創(chuàng)建三個(gè)監(jiān)聽器,可以從三個(gè)不同的層面來觀察響應(yīng)結(jié)果
執(zhí)行一下測(cè)試計(jì)劃,我們來看看三個(gè)監(jiān)聽器所返回的結(jié)果是怎樣的。
以上是表格方式查看響應(yīng)結(jié)果的情況,可以看到通過表格可以查看某個(gè)范圍內(nèi)的響應(yīng)時(shí)間和響應(yīng)狀態(tài)是否正常;
以上三幅截圖則是來自樹形監(jiān)聽器,樹形監(jiān)聽器在幾種監(jiān)聽器中應(yīng)該是最細(xì)致的,可以查看響應(yīng)狀態(tài)、時(shí)間、以及執(zhí)行的SQL語句,乃至返回的結(jié)果均能進(jìn)行驗(yàn)證。
?
至于上面的圖形監(jiān)聽器,可以宏觀的觀察SQL語句在壓力測(cè)試下響應(yīng)的平滑度,并且有一定的統(tǒng)計(jì)信息,能夠觀察平均響應(yīng)時(shí)間等。
現(xiàn)在我們來看另外一種方式編寫我們的JDBC調(diào)用。就是使用JMeter提供的函數(shù)動(dòng)態(tài)生成我們所需要不斷變化的SQL語句部分。之所以需要這么做是為了方便我們觀察執(zhí)行的SQL語句內(nèi)容。
在前面使用預(yù)編譯的方式,傳遞動(dòng)態(tài)參數(shù)的SQL語句執(zhí)行的結(jié)果,大家已經(jīng)看到過,在樹形監(jiān)聽器中,我們觀察到到執(zhí)行過的SQL語句是:
?
| SELECT * FROM (SELECT tmp.*, ROWNUM rn FROM ( select p.p_id, p.p_name, c.cmp_name from test_product p, test_company c where p.cmp_id = c.cmp_id and contains(p.p_name, ?) > 0 --and (p.p_name like '%D%' or p.p_name like '%AIX%') ORDER BY p.p_id desc ) tmp WHERE 1 = 1 AND ROWNUM <= 100) WHERE 1 = 1 AND rn >= 1 |
?
這樣導(dǎo)致我們無法看出參數(shù)"?"當(dāng)中表示的具體值是什么,這對(duì)我們?cè)谀承┣闆r下確定SQL語句的性能是相當(dāng)不利的。所以我們這里需要使用JMeter的動(dòng)態(tài)函數(shù)特性。
我們創(chuàng)建第二個(gè)"JDBC Request"節(jié)點(diǎn),而后禁用"產(chǎn)品名 全文關(guān)鍵字 JDBC Request",將新創(chuàng)建的"JDBC Request"重命名為"產(chǎn)品名 like JDBC Request",將其中的SQL語句改寫為:
?
?
| SELECT * FROM (SELECT tmp.*, ROWNUM rn FROM ( select p.p_id, p.p_name, c.cmp_name from test_product p, test_company c where p.cmp_id = c.cmp_id AND ( ${__V(smt_${__Random(1,4,rnd)})} ) ORDER BY p.p_id desc ) tmp WHERE 1 = 1 AND ROWNUM <= 100) WHERE 1 = 1 AND rn >= 1 |
?
這里核心的部分就是代碼行"AND ${__V(smt_${__Random(1,4,rnd)})} "。"${__Random(1,4,rnd)}"用來生成隨機(jī)數(shù),取值范圍在1到4之間,而"__V(...)"函數(shù)幫助我們轉(zhuǎn)義"smt_${__Random(1,4,rnd)}"生成的內(nèi)容,很類似于JavaScript中的"eval"函數(shù)。
例如"${__Random(1,4,rnd)}"生成隨機(jī)數(shù)為1,則"smt_${__Random(1,4,rnd)}"對(duì)應(yīng)的內(nèi)容為"smt_1","__V"將獲取數(shù)組變量"smt"中的第一個(gè)元素,于是生成的SQL語句如下:
這里我們可以清楚的看到所執(zhí)行的SQL語句。
后記
本例中我們使用了JMeter附帶的函數(shù)"__split"和"__V","__Random"等等,文章對(duì)于這些函數(shù)的描述可能不夠完整,亦可能不夠準(zhǔn)確,更多詳盡的解釋,大家可以參考JMeter官方文檔。
轉(zhuǎn)載于:https://www.cnblogs.com/blongfree/p/4981345.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的【转】使用JMeter对数据库做压力测试的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: js中四种创建对象的方式
- 下一篇: MySQL 5.6 my.cnf 参数说