并發模擬工具詳解
簡介:
- 一、Psotman
- 二、Apache Bench(AB)
- 三、JMeter
- 四、代碼
一、Psotman:Http請求模擬工具
嚴格來說postMan并不是并發請求,而是串行執行的,現在用postMan更多的是用來測試Http連接的一個工具,但是也是一個很實用的工具,也有一些比較強大的功能和優點
1.1 下載地址
- 1) Postman for MAC:https://app.getpostman.com/app/download/osx64?utm_source=site&utm_medium=apps&utm_campaign=macapp&_ga=2.21151352.2119858274.1527039878-1088353859.1527039878
- 2) Postman for windows X64:https://app.getpostman.com/app/download/win64?_ga=2.201562513.1250696341.1530543681-1582181135.1530543681
- 3) Postman for windows X86:https://app.getpostman.com/app/download/win32?_ga=2.21151352.2119858274.1527039878-1088353859.1527039878
- 4) Postman for linux X64:https://app.getpostman.com/app/download/linux64?_ga=2.96050783.2119858274.1527039878-1088353859.1527039878
- 5) Postman for Linux X86:https://app.getpostman.com/app/download/linux32?_ga=2.96050783.2119858274.1527039878-1088353859.1527039878
- 6) 官網地址:https://www.getpostman.com/
1.2 操作說明(以win64為例)
1、打開Postman,輸入我們需要測試的網址,點擊左邊的"+",保存請求

2、點擊"+"后,彈出下面提示,保存鏈接地址生成測試文件夾名稱

3、保存成功后,選擇"collections"后選擇文件夾名為"gbfTest"的,點擊小三角——點擊Run

4、這里我們可以設置請求次數和間隔時間,一般間隔時間會設置為0,設置好之后,我們點擊Run gbfTest運行
5、查看結果,從圖中我們可以看到百度的響應速度還是很快的

6、點擊 Run Summary 可以看到運行結果概述

7、測試全部通過

8、測試結果可以通過點擊Export Results按鈕進行導出,方便分析每次的請求時間

二、Apace Bench(AB):Apache附帶的工具,測試網站性能
2.1 簡介
Apache Bench 是 Apache 服務器自帶的一個web壓力測試工具,簡稱ab。ab又是一個命令行工具,對發起負載的本機要求很低,根據ab命令可以創建很多的并發訪問線程,模擬多個訪問者同時對某一URL地址進行訪問,因此可以用來測試目標服務器的負載壓力。總的來說ab工具小巧簡單,它不僅可以對apache服務器進行網站訪問壓力測試,也可以對或其它類型的服務器進行壓力測試。比如nginx、tomcat、IIS等,上手學習較快,可以提供需要的基本性能指標,但是沒有圖形化結果,不能監控
2.2 原理
ab命令會創建多個并發訪問線程,模擬多個訪問者同時對某一URL地址進行訪問。它的測試目標是基于URL的,因此,它既可以用來測試apache的負載壓力,也可以測試nginx、lighthttp、tomcat、IIS等其它Web服務器的壓力
2.3 Apache Bench安裝
Apache服務器,下載地址:https://www.apachelounge.com/download/
選擇:httpd-2.4.41-win64-VS16 下載目錄結構:

2.4 Apache Bench 使用
運行環境:Windows7 Apache Bench版本:httpd-2.4.41-win64-VS16
1、進入cmd目錄下,進入我們解壓好的Apache Bench目錄下

3 使用命令
- ab -c 10 -n 10 http://www.baidu.com/ 或者 ab.exe -n 1000 -c 500 http://www.baidu.com
ab -c 10 -n 10 http://www.baidu.com/ 或者 ab.exe -n 1000 -c 500 http://www.baidu.com
對百度首頁進行一個請求總數為1000,本次請求并發數為500的測試

參數分析:
- C:\Users\Lenovo\Downloads\httpd-2.4.41-win64-VS16\Apache24\bin>ab.exe -n 1000 -c
- 500 http://www.baidu.com/path
- This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
- Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
- Licensed to The Apache Software Foundation, http://www.apache.org/
- Benchmarking www.baidu.com (be patient)
- Completed 100 requests
- Completed 200 requests
- Completed 300 requests
- Completed 400 requests
- Completed 500 requests
- Completed 600 requests
- Completed 700 requests
- Completed 800 requests
- Completed 900 requests
- Completed 1000 requests
- Finished 1000 requests
- Server Software: Apache #測試服務器的名字
- Server Hostname: www.baidu.com #請求的URL主機名
- Server Port: 80 #請求端口
- Document Path: /path #請求路徑
- Document Length: 222 bytes #頁面大小
- Concurrency Level: 500 #并發量,設置的參數之一
- Time taken for tests: 45.805 seconds #整個測試所用的時間/秒
- Complete requests: 1000 #完成的請求數
- Failed requests: 0 #失敗的請求數
- Non-2xx responses: 1000 #接收到的HTTP響應數據的頭信息中含有2XX以外的狀態碼,則會在測試結果中顯示另一個名為“Non-2xx responses”的統計項,用于統計這部分請求數(1000)
- Total transferred: 484000 bytes #表示所有請求的響應數據長度總和
- HTML transferred: 222000 bytes #表示所有請求的響應數據中正文數據的總和
- Requests per second: 21.83 [#/sec] (mean) #吞吐率,吞吐率是與并發數相關的,使請求總數相同,但如果并發數不一樣,吞吐率還是很可能有很大差異的
- Time per request: 22902.310 [ms] (mean) #用戶平均請求等待時間。也就是一次并發總的時間
- Time per request: 45.805 [ms] (mean, across all concurrent requests) #服務器平均請求等待時間。也就是一次請求(在本例中也就是500中的平均每一次)所需時間
- Transfer rate: 10.32 [Kbytes/sec] received #這些請求在單位時間內從服務器獲取的數據長度
- Connection Times (ms)
- min mean[+/-sd] median max
- Connect: 9 46 460.5 11 9060
- Processing: 25 20066 13796.4 14798 36549
- Waiting: 14 16163 15029.9 8460 36484
- Total: 37 20111 13785.1 22804 36562
- Percentage of the requests served within a certain time (ms)
- 50% 22804 #50%用戶請求在22804ms內返回
- 66% 33043 #66%用戶請求在33043ms內返回
- 75% 34181
- 80% 34791
- 90% 35877
- 95% 36416
- 98% 36502 #98%用戶請求在36502ms內返回
- 99% 36512
- 100% 36562 (longest request)
命令參數參考:
- -n requests Number of requests to perform //本次測試發起的總請求數
- -c concurrency Number of multiple requests to make //一次產生的請求數(或并發數)
- -t timelimit Seconds to max. wait for responses //測試所進行的最大秒數,默認沒有時間限制。
- -r Don't exit on socket receive errors. // 拋出異常繼續執行測試任務
- -p postfile File containing data to POST //包含了需要POST的數據的文件,文件格式如“p1=1&p2=2”.使用方法是 -p 111.txt
- -T content-type Content-type header for POSTing
- //POST數據所使用的Content-type頭信息,如 -T “application/x-www-form-urlencoded” 。 (配合-p)
- -v verbosity How much troubleshooting info to print
- //設置顯示信息的詳細程度 – 4或更大值會顯示頭信息, 3或更大值可以顯示響應代碼(404, 200等), 2或更大值可以顯示警告和其他信息。 -V 顯示版本號并退出。
- -C attribute Add cookie, eg. -C “c1=1234,c2=2,c3=3” (repeatable)
- //-C cookie-name=value 對請求附加一個Cookie:行。 其典型形式是name=value的一個參數對。此參數可以重復,用逗號分割。
- 提示:可以借助session實現原理傳遞 JSESSIONID參數, 實現保持會話的功能,如-C ” c1=1234,c2=2,c3=3, JSESSIONID=FF056CD16DA9D71CB131C1D56F0319F8″ 。
- -w Print out results in HTML tables //以HTML表的格式輸出結果。默認時,它是白色背景的兩列寬度的一張表。
2.5 使用注意
1、MAC中自帶了Apache。
2、在使用ab命令時,并發了過高會出現錯誤:Too many open files,由于系統打開文件數量限制了具有輕量化特點的bench還是很適合中小企業使用,尤其在于模擬訪問頁面的多機測試
三、JMeter:Apache組織開發的壓力測試工具(使用比較多的工具)
3.1 簡介
Apache JMeter是一款純java編寫負載功能測試和性能測試開源工具軟件。相比Loadrunner而言,JMeter小巧輕便且免費,逐漸成為了主流的性能測試工具,是每個測試人員都必須要掌握的工具之一
JDK版本:1.8 運行環境:Windows 7 64 JMeter版本:3.3
注意:安裝JMeter需要 Java8和8以上的JDK版本
3.2 JDK安裝(如果已經安裝JDK 1.8 忽略這一步)
1、jdk官網下載地址:http://www.oracle.com/technetwork/java/javase/downloads/index.html
2、選擇 Java SE 8u231,點擊JDK下載

安裝下載的JDK
配置系統環境變量 具體可以自行查找資料,這里就不做過多描述
3.2 JMeter安裝
1、官網下載地址:JMeter地址:http://jmeter.apache.org/download_jmeter.cgi
2、下載最新JMeter 5.1.1 版本:Apache JMeter 5.1.1 (Requires Java 8+)

3、下載完成后解壓zip包,雙擊bin目錄下jmeter.bat文件

3.3 JMeter 使用
1、雙擊bin目錄下jmeter.bat文件后,打開Apache JMeter工具

2、案例測試(Test Plan - > Add - > Thread(User) - > Thread Group)

3、設置名稱和線程數

線程參數解讀:Number of Threads (users):虛擬用戶數(也就是線程數),一個虛擬用戶占用一個進程或線程Ramp-Up Period(in seconds):準備時長,設置的虛擬用戶數需要多長時間全部啟動。
Loop Count:循環次數每個線程發送請求的次數
如果線程數為20,循環次數為100,那么每個線程發送100次請求。總請求數為20*100=2000 。
如果勾選了“Forever”,那么所有線程會一直發送請求,一到選擇停止運行腳本。
Delay Thread creation until needed:直到需要時延遲線程的創建
Scheduler:調度器,設置線程組啟動的開始時間和結束時間(配置調度器時,需要勾選循環次數為永遠)
Duration(Seconds):持續時間(秒),測試持續時間,會覆蓋結束時間
Startup delay(Seconds):啟動延遲(秒),測試延遲啟動時間,會覆蓋啟動時間
4、添加Http請求
右鍵點擊,Htto請求 > Add > Sampler > Http Request

接下來我們對接口 https://www.baidu.com/s?ie=UTF-8&wd=edg進行性能測試,如下圖所示:

請求參數詳解:
- Web Server(Http服務): 1、Protocol[http]:協議,向目標服務器發送HTTP請求協議,可以是HTTP或HTTPS,默認為HTTP 2、服務器名稱或IP:HTTP請求發送的目標服務器名稱(域名)或IP 3、Port Number:端口號
- Http Reuqeset(Http請求體): 1、Method:請求方法類型,有GET、POST、HEAD、PUT、OPTIONS、TRACE、DELETE等 2、path:目標URL路徑,除去服務器地址、端口和請求參數后所得到的數據 3、Content encoding:編碼方式,設置為 UTF-8
- 請求參數: 設置請求參數,都在下面的列表中進行設置,
- 列表參數解讀:Name:請求參數名 Value:請求值 URL Encode:是否Url編碼 Conten-Type:內容類型,有需要自行調整(一般選擇默認即可) include Equals:是否包含等于
注意:參數傳入中文時需要勾選“URL Encode”
這里的按鈕都是針對列表中的數據進行操作的
- Detail
- :查看參數詳情
- Add
- :添加一行列表請求參數
- Delte
- :刪除一行數據
- Up
- :設置列表參數上移
- Down
- :設置列表參數下移
- add from
- Clipdoard
- :從我們復制的內容中進行添加
5、添加察看結果樹
1、右鍵點擊 Http請求 > Add > Listener > View Results Tree

2、這里我們設置響應數據格式:HTMLSourceFormatted,點擊運行我們就可以看到請求結果

3、本次搜索返回結果頁面標題為 edg_百度搜索

6、添加用戶自定義變量
1、添加用戶自定義變量用以Http請求參數化:Http請求 > Add > Config Element > User Defined Variables

2、新增請求參數,存放搜索關鍵字

3、在 Http測試請求 中使用該參數,格式為:${wd} ,如下圖所示

7、添加響應斷言
右鍵點擊 Http測試請求(注意是Http測試請求) > Add > Assertions > Response Assertion
校驗返回的文本中是否包含搜索詞,添加參數${wd}到要測試的模式中
- Contains
- :包括
- Matches
- :匹配
- Equals
- :相等
- SubString
- :原諒博主才疏學淺,這個就不做解釋了
- Not
- :否
- or
- :或者
7、添加響應斷言結果
右鍵點擊 Http測試請求 > Add > Listener > Assertion Results

點擊運行,查詢運行結果

8、添加聚合報告
右鍵點擊 Http請求 > Add > Listener > Aggregate Report

到這里我們就完成了一個完整的Http接口的性能測試編寫,接下來我們會對它的性能進行測試
3.4 JMeter 性能測試
1、配置Http請求(線程組)信息
點擊Http請求(線程組),配置相關的性能測試相關參數線程數:50 循環次數:永遠持續時間:60秒

2、執行測試信息
選擇聚合報告,查詢結構,點擊 箭頭 按鈕啟動測試,如果要清楚具體內容,點擊小掃把,清除調試結果

3、測試結果分析解讀
1、打開聚合報告

參數詳解:
- Label:每個 JMeter 的 element都有一個 Name 屬性,這里顯示的是 Name 屬性的值
- #Samples:請求數——表示這次測試中一共發出了多少個請求 如果模擬10個用戶,每個用戶迭代10次,那么這里顯示100
- Average:平均響應時間——默認情況下是單個 Request 的平均響應時間 當使用了 Transaction Controller 時,以Transaction 為單位顯示平均響應時間
- Median:中位數,也就是 50% 用戶的響應時間
- 90% Line:90% 用戶的響應時間
- 99% Line:99% 用戶的響應時間
- Min:最小響應時間
- Max:最大響應時間
- Error%:錯誤率——錯誤請求數/請求總數
- Throughput:吞吐量——默認情況下表示每秒完成的請求數(Request per Second) 當使用了TransactionController時,也可以表示類似LoadRunner的TransactionperSecond數
- KB/Sec:每秒從服務器端接收到的數據量
在實際中我們需要關注的點只有—— #Samples 請求數,Average 平均響應時間,Min 最小響應時間,Max 最大響應時間,Error% 錯誤率和Throughput 吞吐量
四、代碼模擬
1、Semaphore
Semaphore是計數信號量。Semaphore管理一系列許可證。每個acquire方法阻塞,直到有一個許可證可以獲得然后拿走一個許可證;每個release方法增加一個許可證,這可能會釋放一個阻塞的acquire方法。然而,其實并沒有實際的許可證這個對象,Semaphore只是維持了一個可獲得許可證的數量。
1.1 代碼演示:獲取一個許可證
- import lombok.extern.slf4j.Slf4j;
- import java.util.concurrent.CountDownLatch;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.Semaphore;
- @Slf4j
- public class SemaphoreExample1 {
- private final static int threadCount = 20;
- public static void main(String[] args) throws Exception {
- ExecutorService exec = Executors.newCachedThreadPool();
- final Semaphore semaphore = new Semaphore(3);
- for (int i = 0; i < threadCount; i++) {
- final int threadNum = i;
- exec.execute(() -> {
- try {
- semaphore.acquire(); // 獲取一個許可
- test(threadNum);
- semaphore.release(); // 釋放一個許可
- } catch (Exception e) {
- log.error("exception", e);
- }
- });
- }
- exec.shutdown();
- }
- private static void test(int threadNum) throws Exception {
- log.info("{}", threadNum);
- Thread.sleep(1000);
- }
- }
執行結果:如下圖所示,我們看到雖然結果是無序的,但是請求的線程數量是正確的,這里展示的是獲取一個許可,同時也釋放一個許可,我們可不可以獲取多個許可,釋放多個許可呢,答案是可以的

1.2 代碼演示:獲取多個許可證
- package com.mmall.concurrency.example.aqs;
- import lombok.extern.slf4j.Slf4j;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.Semaphore;
- @Slf4j
- public class SemaphoreExample {
- private final static int threadCount = 20;
- public static void main(String[] args) throws Exception {
- ExecutorService exec = Executors.newCachedThreadPool();
- final Semaphore semaphore = new Semaphore(3);
- for (int i = 0; i < threadCount; i++) {
- final int threadNum = i;
- exec.execute(() -> {
- try {
- semaphore.acquire(3); // 獲取多個許可
- test(threadNum);
- semaphore.release(3); // 釋放多個許可
- } catch (Exception e) {
- log.error("exception", e);
- }
- });
- }
- exec.shutdown();
- }
- private static void test(int threadNum) throws Exception {
- log.info("{}", threadNum);
- Thread.sleep(1000);
- }
- }
執行結果:這里我們看到我們設置了獲取多個許可同時也釋放多個許可,放回的線程數是正確的,同時執行結果也是有序的

2、CountDownLatch
CountDownLatch是一個同步工具類,用來協調多個線程之間的同步,或者說起到線程之間的通信(而不是用作互斥的作用)。CountDownLatch能夠使一個線程在等待另外一些線程完成各自工作之后,再繼續執行。使用一個計數器進行實現。計數器初始值為線程的數量。當每一個線程完成自己任務后,計數器的值就會減一。當計數器的值為0時,表示所有的線程都已經完成了任務,然后在CountDownLatch上等待的線程就可以恢復執行任務
2.1 代碼演示:
- import lombok.extern.slf4j.Slf4j;
- import java.util.concurrent.CountDownLatch;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- @Slf4j
- public class CountDownLatchExample1 {
- private final static int threadCount = 200;
- public static void main(String[] args) throws Exception {
- int num = 0;
- ExecutorService exec = Executors.newCachedThreadPool();
- final CountDownLatch countDownLatch = new CountDownLatch(threadCount);
- for (int i = 0; i < threadCount; i++) {
- final int threadNum = i;
- num++;
- exec.execute(() -> {
- try {
- test(threadNum);
- } catch (Exception e) {
- log.error("exception", e);
- } finally {
- countDownLatch.countDown();
- }
- });
- }
- countDownLatch.await();
- log.info("finish——"+num);
- exec.shutdown();
- }
- private static void test(int threadNum) throws Exception {
- Thread.sleep(100);
- log.info("{}", threadNum);
- Thread.sleep(100);
- }
- }
通過返回結果我們可以看到,設置的線程數量返回結果數量和我們設置的線程數量200一致
五、總結
postMan:非專業的并發測試,嚴格來說postMan并不是并發請求,而是串行執行的,postMan更多的是用來測試Http連接的一個工具,是一個很實用的工具
Apache Bench:Apache Bench是 Apache 服務器自帶的一個web壓力測試工具,簡稱ab,ab工具小巧簡單,上手學習較快,可以提供需要的基本性能指標,但是沒有圖形化結果,不能監控
JMeter:Apache JMeter 是Apache 組織開發的基于java的壓力測試工具。用于對軟件做壓力測試的工具,它可以用于測試靜態和動態資源例如靜態文件、Java 小服務程序、CGI 腳本、Java 對象、 數據庫, FTP 服務器等等
總的來說,并發測試中,JMeter和Apache Bench是比較好的選擇,由于Apache Bench是基于命令行的,ab處理速度更快,而Jmeter更準確,由于Jmeter本身支持斷言、可變參數和CSV數據集的輸入,能設定更加靈活多變的的測試場景,至于postMan這款工具,用來最多的是用來模擬Http請求的一個,并不是一個專業的并發請求工具。