線程同步類CyclicBarrier在性能測試集合點應用

在之前的性能測試方案設計中,如果是涉及到多用戶的,我一般都是通過先登錄用戶,然後再將Base對象傳入多線程任務類,以此進行性能測試。

但是這種處理方式有個問題,就是在執行多線程任務類之前,可能會造成等待時間過多,因爲需要串行登錄用戶,如果線程過多的話,等待的時間會稍等長一點。

爲此我找到了一個解決辦法,就是使用線程同步類CyclicBarrier將用戶登錄過程在多線程中實現,然後所有用戶登錄完成之後再進行性能測試方法的執行,簡單講就是設置一個多線程集合點,所有線程都到達集合點之後,再一起執行具體的測試方法。

之前的文章又介紹過多線程同步類CountDownLatchCyclicBarrierPhaser,以及在我之前的性能測試過程中的應用,文章列表如下:

需求

分兩步:第一步記錄一條數據(有唯一性驗證);第二步更改該條記錄的狀態。

描述比較模糊,簡單理解就是insert之後update,業務功能簡單。

用例設計思路

雖然業務簡單,但是實現比較麻煩,所以我採取了鏈路性能測試,確定唯一性標記,然後進行update,避免了,單獨測試造數據太麻煩的問題。

僞代碼如下:

@Override
        protected void doing() {
            String orderNum = "FunTester" + getMark() + StringUtil.getString(10)
            threadmark += orderNum
            order.insert(orderNum)
            order.update(orderNum)
        }

這裏將orderNum當做標記對象了,用於鏈路追蹤和日誌查詢。

多線程類實現

我繼續採取ThreadLimitTimesCount<Integer>類作爲模型類的內部靜態類實現,定長線程和固定次數。


private static class FunTester extends ThreadLimitTimesCount<Integer{

        Order order

        CyclicBarrier cyclicBarrier

        FunTester(int u, int times, CyclicBarrier cyclicBarrier) 
{
            super(u, times, null)
            this.cyclicBarrier = cyclicBarrier
        }

        @Override
        void before() {
            super.before()
            this.order = new Order(getBase(t))
            cyclicBarrier.await()
        }

        @Override
        protected void doing() {
            String orderNum = "f" + getMark() + StringUtil.getString(5)
            threadmark += orderNum
            order.create(101"FunTester測試課程"131204542191010, orderNum)
            order.refund(orderNum)
        }

    }

這裏用到了cyclicBarrier.await()方法,使得所有線程達到該集合點之後,才進行下一步的代碼執行。

測試腳本

static void main(String[] args) {

        Common.notPrintResponse()
        ClientManage.init(1050, EMPTY, 0)
        def argsUtil = new ArgsUtil(args)
        def thread = argsUtil.getIntOrdefault(010)
        def times = argsUtil.getIntOrdefault(110)
        def threads = []
        CyclicBarrier cyclicBarrier = new CyclicBarrier(thread, new Runnable() {

            @Override
            void run() {
                logger.info("所有賬號登錄完成!,即將開始測試!")
            }
        })
        thread.times {
            threads << new FunTester(it, times, cyclicBarrier)
        }

        new Concurrent(threads, "一個不可描述的用例場景").start()


        FunLibrary.testOver()

    }

Common.notPrintResponse()方法爲了屏蔽測試過程中,打印響應結果,因爲日誌太多了,處理起來比較麻煩。最近在研究鏈路測試中對各個接口的數據處理,所以想到了這個方法。

控制檯輸出

INFO-> 當前用戶:fv,IP:10.60.193.37,工作目錄:/Users/fv/Documents/workspace/qa/,系統編碼格式:UTF-8,系統Mac OS X版本:10.16
INFO-> 本校共有:627名老師,852名學生,11個班級!
INFO-> 請求uri:不可描述的地址/login,耗時:458 ms, requestId:Fun20210310111251QvEl
INFO-> 請求uri:不可描述的地址/login,耗時:458 ms, requestId:Fun20210310111251xQKM
INFO-> 用戶:82951571527,登錄成功!
INFO-> 用戶:82951571522,登錄成功!
INFO-> 請求uri:不可描述的地址/login,耗時:458 ms, requestId:Fun20210310111251TLml
INFO-> 用戶:82951571529,登錄成功!
INFO-> 請求uri:不可描述的地址/login,耗時:471 ms, requestId:Fun20210310111251CgTd
INFO-> 用戶:82951571531,登錄成功!
INFO-> 請求uri:不可描述的地址/login,耗時:483 ms, requestId:Fun20210310111251YQyQ
INFO-> 請求uri:不可描述的地址/login,耗時:459 ms, requestId:Fun20210310111251IGUs
INFO-> 請求uri:不可描述的地址/login,耗時:458 ms, requestId:Fun20210310111251NZQt
INFO-> 請求uri:不可描述的地址/login,耗時:484 ms, requestId:Fun20210310111251KVRP
INFO-> 用戶:82951571525,登錄成功!
INFO-> 用戶:82951571513,登錄成功!
INFO-> 用戶:82951571514,登錄成功!
INFO-> 用戶:82951571516,登錄成功!
INFO-> 請求uri:不可描述的地址/login,耗時:604 ms, requestId:Fun20210310111251AXdV
INFO-> 用戶:82951571518,登錄成功!
INFO-> 請求uri:不可描述的地址/login,耗時:610 ms, requestId:Fun20210310111251KUMm
INFO-> 用戶:82951571524,登錄成功!
INFO-> 所有賬號登錄完成!,即將開始測試!

*********中間省略N次請求日誌*************

INFO->
 線程:一個不可描述的用例場景2,執行次數:10,錯誤次數: 0,總耗時:2.317 s
INFO-> 一個不可描述的用例場景進度:▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍  100%
INFO-> 總計10個線程,共用時:3.132 s,執行總數:100,錯誤數:0,失敗數:0
INFO-> 數據保存成功!文件名:/Users/fv/Documents/workspace/qa/long/data/易視騰3.3購買退款101112_10
INFO-> 
~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~ JSON ~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~
>  {
>  ① . "rt":210,
>  ① . "total":100,
>  ① . "qps":47.619,
>  ① . "failRate":0.0,
>  ① . "threads":10,
>  ① . "startTime":"2021-03-10 11:12:51",
>  ① . "endTime":"2021-03-10 11:12:54",
>  ① . "errorRate":0.0,
>  ① . "executeTotal":100,
>  ① . "mark":"一個不可描述的用例場景101112",
>  ① . "table":"eJwBHQDi/+aVsOaNrumHj+WkquWwkSzml6Dms5Xnu5jlm74hMCkTtQ=="
>  }
~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~ JSON ~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~
INFO-> 數據量太少,無法繪圖!

最後因爲測試請求,數據量太少了,所以屏蔽了畫圖功能,欲知圖像如何,請參考:性能測試中圖形化輸出測試數據


FunTester騰訊雲社區欽定年度作者,非著名測試開發er,歡迎關注。

點擊閱讀原文,查看公衆號歷史文章


本文分享自微信公衆號 - FunTester(NuclearTester)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章