1. 程式人生 > >效能測試初探---介面效能測試

效能測試初探---介面效能測試

(一).效能指標

PV: PageView, 頁面瀏覽量或點選量,使用者每次重新整理即被計算一次;使用者的一次重新整理,給伺服器造成了一次請求。

UV: UniqueVisitor, 訪問你網站的一臺計算機客戶端為一個訪客,0:00 - 24:00 內相同的客戶端僅記一次。

TPS: Transaction Per Second 每秒系統處理的交易或事物的數量,衡量系統處理能力的重要指標。

RT: 響應時間,從客戶端傳送一個請求開始,到客戶端接收到從伺服器返回的響應結果結束所經歷的時間,包括請求傳送時間,網路傳輸時間和伺服器處理時間三部分。

VU: Virtual User, 模擬真實業務邏輯步驟的虛擬使用者,虛擬使用者模擬的操作步驟被記錄在虛擬使用者指令碼中,通常使用併發實現。

TPS波動: 系統性能依賴於特定的硬體、軟體程式碼、應用服務、網路資源等,所以在效能場景執行期間,TPS可能會表現為穩定,或者波動,抑或遵循一定的上升或下降趨勢。用TPS波動係數來記錄這個指標值。

CPU: CPU資源是指效能測試場景執行的這個時間段內,應用服務系統的CPU資源佔用率。CPU資源是判斷系統處理能力以及應用執行是否穩定的重要引數。

Load: 系統正在幹活的多少的度量,佇列長度。系統平均負載,被定義為在特定時間間隔(1m,5m,15m)內執行佇列中的平均程序數。

I/O: I/O可分為磁碟IO和網絡卡IO。

JVM: 即Java虛擬機器,它擁有自己的處理器、堆疊、暫存器等,還有自己相應的指令系統。Java應用執行在JVM上面。

GC: GC是一種自動記憶體管理程式,它主要的職責是分配記憶體、保證被引用的物件始終在記憶體中、把不被應用的物件從記憶體中釋放。FGC會引起JVM掛起。

網速: 網路中的資料傳輸速率,一般以Byte/s為單位。通過ping延時來反映網速.

流量: 效能測試中,一般指單位時間內流經網絡卡的總流量。分為inbound和outbound,一般以KB為單位。

VU(併發壓測使用者數) = TPS(每秒執行事務數) × RT(響應時間)

在尋找合適的併發使用者數上,建議使用PTS(淘寶效能自動化:https://pts.aliyun.com/lite/index.htm?spm=0.0.0.0.8t95Nt)的“梯度模式”,逐漸增加併發使用者數,這個時候壓力也會越來越大,當TPS的增長率小於響應時間的增長率時,這就是效能的拐點,也就是最合理的併發使用者數;當TPS不再增長或者下降時,這個時候的壓力就是最大的壓力,所使用的併發使用者數就是最大的併發使用者數。如果此時的TPS不滿足你的要求,那麼就需要尋找瓶頸來優化。
這裡寫圖片描述

a點:效能期望值

b點:高於期望,系統安全

c點:高於期望,拐點

d點:超過負載,系統崩潰

(二).LoadRunner統計介面效能資料

LoadRunner分成3步:
1. Create/Edit Scripts;
2. Run Load Tests;
3. Analyze Test Results;

第一步:編寫指令碼(GET請求)

新建 New Scrips, 選擇Web(HTTP/HTML)協議,因為不是對頁面測試,無需記錄操作,在“Start Recording”彈窗中,選擇Cancel。
手動編寫指令碼:

Action()
{
    web_set_max_html_param_len("10240");

    // 關鍵詞Text的value值為在請求返回的結果中搜尋的字串
    // 關鍵詞SaveCount的value值為在結果中找到Text文字內容的個數
    web_reg_find("Text={\"statuses\":",
             "SaveCount=Count",
              LAST);


    // 自定義事務unread_friends_timeline_reload,起始點
    lr_start_transaction("unread_friends_timeline_reload");
    // basic認證,在頭資訊新增Authorization值,變數authorization引數化
    web_add_header("Authorization","{authorization}"); 
    // http請求
    web_custom_request("web_custom_request",
        "URL=http://ip:port/2/statuses/unread_friends_timeline.json?source=******",
        "Method=GET",
        "RecContentType=application/json",
        "Mode=HTTP",
        "EncType=application/x-www-form-urlencoded",
        LAST);

    // 判斷結果是否包含預期文字,如果包含,則事務unread_friends_timeline_reload狀態為LR_PASS
   if (atoi(lr_eval_string("{Count}")) == 1){

        lr_end_transaction("unread_friends_timeline_reload", LR_PASS);

        }

    else{

         lr_error_message("error=%s","errorContent");

         lr_end_transaction("unread_friends_timeline_reload", LR_FAIL);

         }

return 0;

}

按“F5”鍵執行指令碼,Replay Log輸出如下:

Virtual User Script started at : 2015-10-07 16:58:47
Starting action vuser_init.
Web Turbo Replay of LoadRunner 11.0.0 for WIN2003; build 9409 (Jan 11 2012 11:34:16)    [MsgId: MMSG-27143]
Run Mode: HTML      [MsgId: MMSG-26000]
Run-Time Settings file: "E:\unreadfeed\unreadfeedreload\\default.cfg"   [MsgId: MMSG-27141]
Ending action vuser_init.
Running Vuser...
Starting iteration 1.
Starting action Action.
Action.c(3): web_set_max_html_param_len was successful      [MsgId: MMSG-26392]
Action.c(6): Registering web_reg_find was successful    [MsgId: MMSG-26390]
Action.c(12): Notify: Transaction "unread_friends_timeline_reload" started.
Action.c(15): Warning -26593: The header being added may cause unpredictable results when applied to all ensuing URLs. It is added anyway   [MsgId: MWAR-26593]
Action.c(15): web_add_header("Authorization") highest severity level was "warning"      [MsgId: MMSG-26391]
Action.c(16): Registered web_reg_find successful for "Text={"statuses":" (count=1)      [MsgId: MMSG-26364]
Action.c(16): web_custom_request("web_custom_request") was successful, 91858 body bytes, 198 header bytes   [MsgId: MMSG-26386]
Action.c(26): Notify: Transaction "unread_friends_timeline_reload" ended with "Pass" status (Duration: 0.8905 Wasted Time: 0.6256).
Ending action Action.
Ending iteration 1.
Ending Vuser...
Starting action vuser_end.
Ending action vuser_end.
Vuser Terminated.

Action.c(26): Notify: Transaction “unread_friends_timeline_reload” ended with “Pass” status (Duration: 0.8905 Wasted Time: 0.6256). 表示指令碼除錯通過。

模擬POST請求:

web_custom_request中引數設定:”Method=POST”,“Body=屬性名稱=屬性值&屬性名稱=屬性值&……”,web_custom_request中Body中的屬性值如果包含一些特殊字元,必須通過URL編碼,否則Web伺服器會返回500錯誤。

例子:

web_custom_request("web_custom_request",
        "URL=http://ip/2/statuses/update.json",
        "Method=POST",
        "RecContentType=application/json",
        "Mode=HTTP",
        "EncType=application/x-www-form-urlencoded",
        "Body=status=123&source=********",
        LAST);

第二步: Run Load Tests

自定義指令碼之後,執行第二步,Run Load Tests, 彈出New Scenario小視窗,左下選擇測試指令碼,進入場景設計。

場景設定主要包括4部分,選擇Global Schedule->Edit Action設定場景:

1.Initialize: VU初始化設定

2.Start Vusers: 定義多少個VU, 使用者增長選擇
(1)Simultaneously 同時;(2)每隔一定時間,增長使用者

3.Duration: 執行時間設定

4.Stop Vusers: 終止VU的策略

場景設定結束後,點選左下Run, 點選Start Scenario,開始場景效能測試。

點選stop, 終止效能測試; 自動跳到第三步。

第三步: Analyze Test Results

結果展示,會有3份報告

(1)Analysis Summary: Statistics Summary, Transaction Summary,HTTP Responses Summary

(2)Averagee Response Time: Minimum, Average, Maximum, std.Deviation(標準方差), 單位:s

(3)Transactions per Second:Graph Minmum, Average, Graph Maximum, Graph Median, Graph Std. Deviatior

LoadRunner並沒有提供響應時間的分佈情況,只有最小,最大,平均,標準方差,90 Percent,如果需要統計50%,60%,70%,80%,90% RT的分佈情況,需通過LR獲取原始資料,通過Excel公式PERCENTILE計算:

在Averagee Response Time報告下,選擇Windows選單->Raw Data, 右側出現Raw Data, 展開該選項,通過Transaction Name(值為指令碼中自定義的事務名)獲取介面響應時間原始資料Transaction Response Time,貼上到excel中,假設原始資料都在一列(A2-A57),比如要獲得50% RT, 則使用公式=PERCENTILE(A2:A57;0.5)得到結果,依次類推…

(三).業界效能測試工具

PTS:

開源工具:

Gatling is an open-source load testing framework based on Scala, Akka and Netty
High performance
Ready-to-present HTML reports
Scenario recorder and developer-friendly DSL

測試指令碼為scala, 短板:沒有TPS資料,優點:結果圖形化展示很清晰。
部分截圖:
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述

nGrinder is a platform for stress tests that enables you to execute script creation, test execution, monitoring, and result report generator simultaneously. The open-source nGrinder offers easy ways to conduct stress tests by eliminating inconveniences and providing integrated environments.
nGrinder是NAVER(韓國最大網際網路公司NHN旗下搜尋引擎網站)開源的效能測試工具,提供war包,直接部個web服務,就能使用。
這裡寫圖片描述
預設管理員賬號:admin/admin
賬號登入後,需要下載agent和monitor(注意下載的agent會有對應的賬號資訊,一個賬號對應唯一的agent,其他賬號登入不能使用其他人的agent,只能使用自己下載的agent):
這裡寫圖片描述
安裝在測試機上,monitor監控機器效能,agent執行效能測試;測試指令碼為Groovy/Jython,測試指令碼類似JUnit case,自定義了runner: GrinderRunner

package org.ngrinder;

import static net.grinder.script.Grinder.grinder
import static org.junit.Assert.*
import static org.hamcrest.Matchers.*
import net.grinder.plugin.http.HTTPRequest
import net.grinder.plugin.http.HTTPPluginControl;
import net.grinder.script.GTest
import net.grinder.script.Grinder
import net.grinder.scriptengine.groovy.junit.GrinderRunner
import net.grinder.scriptengine.groovy.junit.annotation.BeforeProcess
import net.grinder.scriptengine.groovy.junit.annotation.BeforeThread
// import static net.grinder.util.GrinderUtils.* // You can use this if you're using nGrinder after 3.2.3
import org.junit.Before
import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith

import HTTPClient.HTTPResponse
import HTTPClient.NVPair

/**
 * A simple example using the HTTP plugin that shows the retrieval of a
 * single page via HTTP. 
 * 
 * This script is automatically generated by ngrinder.
 * 
 * @author user
 */
@RunWith(GrinderRunner)
class TestRunner {
    public static GTest test
    public static HTTPRequest request

    @BeforeProcess
    public static void beforeProcess() {
        HTTPPluginControl.getConnectionDefaults().timeout = 6000
        test = new GTest(1, "www.baidu.com")
        request = new HTTPRequest()
        test.record(request);
        grinder.logger.info("before process.");
    }

    @BeforeThread 
    public void beforeThread() {
        grinder.statistics.delayReports=true;
        grinder.logger.info("before thread.");
    }

    @Test
    public void test(){
        HTTPResponse result = request.GET("http://www.baidu.com")

        if (result.statusCode == 301 || result.statusCode == 302) {
            grinder.logger.warn("Warning. The response may not be correct. The response code was {}.", result.statusCode); 
        } else {
            assertThat(result.statusCode, is(200));
        }
    }
}

圖形化設定引數:
這裡寫圖片描述

結果顯示:
這裡寫圖片描述