天天看點

手把手教你編寫最簡單的性能腳本

在腳本實作中,我們最常用的協定就是 HTTP 和 TCP 了吧,是以在今天的内容裡,我簡單地說一下如何編寫 HTTP 和 TCP 腳本,以應測試主題。

先上圖

手把手教你編寫最簡單的性能腳本

我們知道 HTTP 是應用層的協定之一,現在很多場景都在用它,并且是用的 HTTP1.1 的版本,對應的是 RFC2616,當然還有補充協定 RFC7231、6265。

還有一點也需要注意,HTTP 是通過 Socket 來使用 TCP 的,Socket 做為套接層 API,它本身不是協定,隻規定了 API。

而我們通常在 JMeter 中寫 TCP 腳本,就是直接調用 Socket 層的 API。TCP 腳本和 HTTP 腳本最大的差別就是,TCP 腳本中發送和接收的内容完全取決于 Socket server 是怎麼處理的,并沒有通用的規則。是以腳本中也就隻有根據具體的項目來發揮了。

這個接口的通路邏輯:JMeter——SprintBoot 的應用——MySQL。

手把手教你編寫最簡單的性能腳本

 編寫 JMeter 腳本

1、建立線程組

手把手教你編寫最簡單的性能腳本

 Ramp-up Period(in seconds):遞增時間,以秒為機關。指的就是上面配置的線程數将在多長時間内會全部遞增完。如果我們配置了 100 線程,這裡配置為 10 秒,那麼就是 100/(10s*1000ms)=1 線程 /100ms;如果我們配置了 10 線程,這裡配置為 1 秒,則是 10/1000=1 線程 /100ms。這時我們要注意了哦,在 10 線程啟動的這個階段中,對伺服器的壓力是一樣的。示意圖如下:

手把手教你編寫最簡單的性能腳本

 Loop Count 這個值指的是一個線程中腳本疊代的次數。這裡你需要注意,這個值和後面的 Scheduler 有一個判斷關系,下面我們會提到。

Delay Thread creation until needed:這個含義從字面看不是特别清楚。這裡有一個預設的知識點,那就是 JMeter 所有的線程是一開始就建立完成的,隻是遞增的時候會按照上面的規則遞增。如果選擇了這個選項,則不會在一開始建立所有線程,隻有在需要時才會建立。這一點和 LoadRunner 中的初始化選項類似。隻是不知道你有沒有注意過,基本上,我們做性能測試的工程師,很少有選擇這個選項的。選與不選之間,差別到底是什麼呢?

如果不選擇,在啟動場景時,JMeter 會用更多的 CPU 來建立線程,它會影響前面的一些請求的響應時間,因為壓力機的 CPU 在做其他事情嘛。

如果選擇了的話,就會在使用時再建立,CPU 消耗會平均一些,但是這時會有另一個隐患,就是會稍微影響正在跑的線程。這個選項,選擇與否,取決于壓力機在執行過程中,它能産生多大的影響。如果你的線程數很多,一旦啟動,壓力機的 CPU 都被消耗在建立線程上了,那就可以考慮選擇它,否則,可以不選擇。

即便設定了 Scheduler 的 Duration 為 100 秒,線程仍然會以 10 秒為結束點。

有些人不太了解這一點,經常會設定疊代次數,同時又設定 Scheduler 中的 Duration。而對 TPS 來說,就會産生這樣的圖:

手把手教你編寫最簡單的性能腳本

場景沒執行完,結果 TPS 全掉下去了,于是開始查後端系統,其實和後端沒有任何關系。

 2、建立 HTTP Sampler

手把手教你編寫最簡單的性能腳本

這個圖檔可以表示成功嗎?

不是的,業務的成功,隻能靠業務來判斷。這裡隻是查詢成功了,沒傳回資料也是查詢成功了。

POST 接口

下面我将 Method 改為 POST,POST 接口與 GET 接口的差別有這麼幾處:要把 Path 改為 /pa/add;輸入 JSON 格式的 Body Data。

手把手教你編寫最簡單的性能腳本

 執行起來,檢視下結果。

手把手教你編寫最簡單的性能腳本

 報錯了,先看懂問題,再處理問題,别瞎蒙!

上面這個問題其實提示得很清楚:“不支援的媒體類型”。這裡就兩個資訊,一個是 Content type,一個是 charset。它們是 JMeter 中 HTTP Header 裡預設自帶的。我們要發送的是 JSON 資料,而 JMeter 預設是把它當成 text 發出去的,這就出現了問題。是以我們要加一個 Header,将 Content type 指定為 JSON。

加一個 HTTP Header,如下所示:

手把手教你編寫最簡單的性能腳本

 在這裡,我需要跟你強調的是,手工編寫 HTTP 腳本時,要注意以下幾點:

要知道請求的類型,我們選擇的類型和後端接口的實作類型要是一緻的。

業務的成功要有明确的業務判斷(在下面的 TCP 中,我們再加斷言來判斷)。

判斷問題時,請求的邏輯路徑要清晰。

編寫完 HTTP 腳本時,我們再來看一下如何編寫 TCP 腳本。

手工編寫 TCP 腳本

首先建立 TCP Sampler。右鍵點選 Thread Group - Add - Sampler - TCP Sampler 即可建立。

手把手教你編寫最簡單的性能腳本

 輸入配置和要發送的資訊。

手把手教你編寫最簡單的性能腳本

IP 位址和端口是必須要輸入的。對于建立一個 TCP 協定的 JMeter 腳本來說,簡單地說,過程就是這樣的:建立連接配接 - 發資料 - 關閉連接配接。

但是,通常我們在建立 TCP 協定的腳本時,都是根據業務接口規範來說的,複雜點其實不在腳本本身上,而是在接口的規則上。

添加斷言

我回放了一下腳本,發現如下情況:

手把手教你編寫最簡單的性能腳本

 都執行對了呀,為什麼下面的沒有傳回資訊呢?這種情況下隻有第一個請求有傳回資訊,但是下面也沒有報錯。這裡就需要注意了。

測試工具的成功,并不等于業務的成功。

是以我們必須要做的就是響應斷言,也就是傳回值的判斷。在 JMeter 中,斷言有以下這些:

手把手教你編寫最簡單的性能腳本

 什麼是斷言呢?

手把手教你編寫最簡單的性能腳本

 斷言指的就是伺服器端有一個業務成功的辨別,會傳遞給用戶端,用戶端判斷是否正常接收到了這個辨別的過程。

手把手教你編寫最簡單的性能腳本

 在這裡我添加了一個斷言,用以判斷伺服器是否傳回了 OK。 你要注意這個“OK”是從哪來的哦,它是從服務端的這一行代碼中來的。 String response = message + " is OK";

請注意,這個斷言的資訊,一是可以判斷出業務的正确性。我在工作中發現有些人用頁面中一些并不必要的文字來判斷,這樣就不對了,我們應該用有業務含義的判斷辨別。

如果我們再次回放腳本,你會發現除了第一個請求,後面 9 個請求都錯了。

是以,在做腳本時,請你一定要注意,斷言是必須要加的。

長短連接配接的問題

我們檢視一下 JMeter 的控制台錯誤資訊:

ERROR o.a.j.p.t.s.TCPSampler: 
java.net.SocketException: Broken pipe (Write failed)
  at java.net.SocketOutputStream.socketWrite0(Native Method) ~[?:1.8.0_111]
  at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109) ~[?:1.8.0_111]
  at java.net.SocketOutputStream.write(SocketOutputStream.java:141) ~[?:1.8.0_111]
  at org.apache.jmeter.protocol.tcp.sampler.TCPClientImpl.write(TCPClientImpl.java:78) ~[ApacheJMeter_tcp.jar:5.1.1 r1855137]
  at org.apache.jmeter.protocol.tcp.sampler.TCPSampler.sample(TCPSampler.java:401) [ApacheJMeter_tcp.jar:5.1.1 r1855137]
  at org.apache.jmeter.threads.JMeterThread.doSampling(JMeterThread.java:622) [ApacheJMeter_core.jar:5.1.1 r1855137]
  at org.apache.jmeter.threads.JMeterThread.executeSamplePackage(JMeterThread.java:546) [ApacheJMeter_core.jar:5.1.1 r1855137]
  at org.apache.jmeter.threads.JMeterThread.processSampler(JMeterThread.java:486) [ApacheJMeter_core.jar:5.1.1 r1855137]
  at org.apache.jmeter.threads.JMeterThread.run(JMeterThread.java:253) [ApacheJMeter_core.jar:5.1.1 r1855137]
  at java.lang.Thread.run(Thread.java:745) [?:1.8.0_111]      

Broken pipe。這個提示表明用戶端上沒有這個連接配接了,而 JMeter 還以為有這個連結,于是接着用這個連結來發,顯然是找不到這個通道,于是就報錯了。

為什麼會報這個錯呢?因為我們代碼是短連結的,服務端處理完之後,就把這個連結給斷掉了。

這是為什麼呢?因為在 JMeter 中,預設是複用 TCP 連接配接的,但是在我們這個示例中,服務端并沒有儲存這個連接配接。是以,我們應該在腳本中,把下圖中的 Re-use connection 給去掉。

手把手教你編寫最簡單的性能腳本

 這時再回放腳本,你就會發現 10 次疊代全都對了。如下圖所示:

手把手教你編寫最簡單的性能腳本

 但是,這裡還有一個知識點,希望你注意。短連接配接的時候,必然會産生更多的 TCP 連接配接的建立和銷毀,對性能來說,這會讓系統變得緩慢。

是以你可以看到上面 10 條疊代全都對了的同時,響應時間也增加了。

長短連接配接的選擇取決于業務的需要,如果必須用短連結,那可能就需要更多的 CPU 來支撐;要是長連接配接,就需要更多的記憶體來支撐(用以儲存 TCP 連接配接)。

TCP 連接配接逾時

下面這個錯誤,屬于典型的主機連不上。

java.net.ConnectException: Operation timed out (Connection timed out)
  at java.net.PlainSocketImpl.socketConnect(Native Method) ~[?:1.8.0_111]
  at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) ~[?:1.8.0_111]
  at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) ~[?:1.8.0_111]
  at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) ~[?:1.8.0_111]
  at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) ~[?:1.8.0_111]
  at java.net.Socket.connect(Socket.java:589) ~[?:1.8.0_111]
  at org.apache.jmeter.protocol.tcp.sampler.TCPSampler.getSocket(TCPSampler.java:168) [ApacheJMeter_tcp.jar:5.1.1 r1855137]
  at org.apache.jmeter.protocol.tcp.sampler.TCPSampler.sample(TCPSampler.java:384) [ApacheJMeter_tcp.jar:5.1.1 r1855137]
  at org.apache.jmeter.threads.JMeterThread.doSampling(JMeterThread.java:622) [ApacheJMeter_core.jar:5.1.1 r1855137]
  at org.apache.jmeter.threads.JMeterThread.executeSamplePackage(JMeterThread.java:546) [ApacheJMeter_core.jar:5.1.1 r1855137]
  at org.apache.jmeter.threads.JMeterThread.processSampler(JMeterThread.java:486) [ApacheJMeter_core.jar:5.1.1 r1855137]
  at org.apache.jmeter.threads.JMeterThread.run(JMeterThread.java:253) [ApacheJMeter_core.jar:5.1.1 r1855137]
  at java.lang.Thread.run(Thread.java:745) [?:1.8.0_111]      

要想解決這個問題,就要先确定服務端是可以正常連通的。

如果不能正常連通,那麼通常都是 IP 不正确、端口不正确、防火牆阻止之類的問題。解決了網絡連通性的問題,就可以解決 connection timed out 的問題。

總結

其實這篇文章隻想告訴你一件事情,手工編寫腳本,從基礎上說,是非常簡單的,隻是有三點需要特别強調:

1、涉及到業務規則和邏輯判斷之後,編寫腳本就複雜了起來。但是了解業務規則是做腳本的前提條件,也是性能測試工程師的第一步。

2、編寫腳本的時候,要知道後端的邏輯。這裡的意思不是說,你一開始寫腳本的時候,就要去讀後端的代碼,而是說你在遇到問題的時候,要分析整個鍊路上每個環節使用到了什麼技術,以便快速地分析判斷。

3、寫腳本是以最簡為最佳,用不着故意複雜。