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


在腳本實現中,我們最常用的協議就是 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、寫腳本是以最簡為最佳,用不着故意復雜。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM