關於JMeter原子性相關探究

1.背景

最近寶路遇到個項目,在使用JMeter過程中引發了一些思考,寶路嘗試用各種方式去驗證,進而有了今天“JMeter原子性”相關主題。

2.目的

探究JMeter的事務的原子性

3.實戰

說道原子性,有的同學還一頭霧水。。。。啥是原子性?相信大家應該都接觸過數據庫,數據庫的事務就具有原子性(其餘的幾個特性本次不討論),寶路覺得這個原子性的概念,更像是從化學這麼學科中“偷”過來的。在化學中,原子是在化學反應不可再分的微粒。影射到事務,那就是一個或者多個操作步驟組成了一個原子單元,在事務執行過程中,如果其中任意一個操作步驟失敗,那麼整個事務即失敗。

說下本次JMeter的測試計劃,本次設計4個接口,“登錄”、“活動信息”、“查卡列表”、“查詢餘額”,只有登錄成功之後纔會觸發其餘交易。

   腳本結構(全部交易默認成功):

  腳本中sampler都用相同代碼來模擬,可以通過random參數控制返回內容,sleep參數控制交易耗時。

public class JMeterTransaction extends AbstractJavaSamplerClient {
​
    @Override
    public Arguments getDefaultParameters() {
        Arguments arguments = new Arguments();
        arguments.addArgument("random","1");
        arguments.addArgument("sleep","50");
        return arguments;
    }
​
    @Override
    public SampleResult runTest(JavaSamplerContext arg0) {
        SampleResult result = new SampleResult();
        result.sampleStart();
        String random = arg0.getParameter("random");
        long sleep = Long.valueOf(arg0.getParameter("sleep"));
        try {
            TimeUnit.MILLISECONDS.sleep(sleep);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        result.setSuccessful(true);
        result.setResponseCodeOK();
        result.setResponseData(random,"UTF-8");
        result.sampleEnd();
        return result;
    }
}

10併發執行1min結果:

嗯?各接口樣本數爲什麼不一樣?有點意思?理論上每個接口樣本數應該一致啊。。。。。

寶路調整了下事務控制器配置,勾選了Genernate parent sampler

10併發執行1min結果:

感覺目前沒啥問題,寶路將執行過程中的結果保存了,打開本次jtl結果:

嗯?如出一轍。。。從目前看與事務原子性,登錄成功多少筆,其餘的交易就應該成功多少筆。目前能看JMeter的事務控制不符合原子性,難道是我使用的姿勢有問題?

    多次執行過,寶路發現個共性:同一個測試計劃的各接口的樣本總數是遞減的。所以寶路做了推測:在場景停止時(線程數從某個設定的值下降到0),比如某個線程在執行完“查詢卡列表”時,線程就被kill了,進而導致“查詢餘額”接口沒被執行。

寶路又做了驗證:

不勾選事務控制器Genernate parent sampler

勾選事務控制器Genernate parent sampler

清除結果後,使用聚合報告打開本次執行的jtl結果:

經過多次執行,發了個詭異現象:在不勾選Genernate parent sampler時,事務控制器統計的樣本數與最後一個接口統計的樣本數相同,在勾選Genernate parent sampler時,事務控制器統計的樣本數與首個接口統計的樣本數相同。

先不管這個是不是BUG,從事務角度看不滿足原子性。單純的事務控制器並不嚴格的具備原子性,這是目前看到的表像。

那麼怎麼解決呢?寶路之前寫過一篇關於JavaRequest探究的文章,感興趣的同學可以點擊看下。本文就不過多闡述了。直接看結果

清除聚合報告數據後,再打開本次執行的jtl結果文件

嗯,真香。目前覺得唯一的缺點就是沒有一個能監聽subResult的插件。相同的場景,都是基於java請求的編寫的底層腳本,唯一的區別就是組織方式不同。

其實你完全可以這樣看:把TestJavaLee中的main看成事務控制器,你細細品,再細細品。。。。

進而寶路得出:單純用事務控制器來組織多個sampler,嚴格來說不具有事務的原子性。

如果有不同想法或者看法,歡迎給寶路留言,最後附下TestJavaLee代碼:

public class TestJavaLee extends AbstractJavaSamplerClient {
    @Override
    public Arguments getDefaultParameters() {
        Arguments arguments = new Arguments();
        arguments.addArgument("subResult","RAW_NO");
        return arguments;
    }
​
    @Override
    public SampleResult runTest(JavaSamplerContext arg0) {
        SampleResult main = new SampleResult();
        main.setSampleLabel("Main事務");
        main.sampleStart();
​
        SampleResult sample_a = new SampleResult();
        sample_a.setSampleLabel("登錄");
        sample_a.sampleStart();
        try {
            TimeUnit.MILLISECONDS.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        sample_a.sampleEnd();
        sample_a.setSuccessful(true);
        main.addSubResult(sample_a,false);
​
        SampleResult sample_b = new SampleResult();
        sample_b.setSampleLabel("活動信息");
        sample_b.sampleStart();
        try {
            TimeUnit.MILLISECONDS.sleep(70);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        sample_b.sampleEnd();
        sample_b.setSuccessful(true);
        main.addSubResult(sample_b,false);
​
        SampleResult sample_c = new SampleResult();
        sample_c.setSampleLabel("查卡列表");
        sample_c.sampleStart();
        try {
            TimeUnit.MILLISECONDS.sleep(80);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        sample_c.sampleEnd();
        sample_c.setSuccessful(true);
​
        main.addSubResult(sample_c,false);
​
        SampleResult sample_d = new SampleResult();
        sample_d.setSampleLabel("查詢餘額");
        sample_d.sampleStart();
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        sample_d.sampleEnd();
        sample_d.setSuccessful(true);
​
        main.addSubResult(sample_d,false);
​
        main.setSuccessful(true);
        return main;
    }
​
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章