讀stressTester源碼說并發(fā)壓測(cè)

第一步 收集

上碼:

public StressResult test(int concurrencyLevel, int totalRequests, StressTask stressTask, int warmUpTime) {
        if (stressTask == null) {
            stressTask = this.emptyTestService;
        }
//預(yù)執(zhí)行,確保代碼無誤
        this.warmUp(warmUpTime, stressTask);
        int everyThreadCount = totalRequests / concurrencyLevel;
// 建立兩個(gè)開關(guān)怀各,一個(gè)管理開始時(shí)所有的數(shù)據(jù)預(yù)備到位席赂,一個(gè)管理結(jié)束時(shí)所有的數(shù)據(jù)執(zhí)行完畢
//開始的開關(guān)
        CyclicBarrier threadStartBarrier = new CyclicBarrier(concurrencyLevel);
//結(jié)束的開關(guān)
        CountDownLatch threadEndLatch = new CountDownLatch(concurrencyLevel);
//失敗的次數(shù)統(tǒng)計(jì)
        AtomicInteger failedCounter = new AtomicInteger();
        StressContext stressContext = new StressContext();
        stressContext.setTestService(stressTask);
        stressContext.setEveryThreadCount(everyThreadCount);
        stressContext.setThreadStartBarrier(threadStartBarrier);
        stressContext.setThreadEndLatch(threadEndLatch);
        stressContext.setFailedCounter(failedCounter);
//設(shè)定線程池
        ExecutorService executorService = Executors.newFixedThreadPool(concurrencyLevel);
        List<StressThreadWorker> workers = new ArrayList(concurrencyLevel);

        int realTotalRequests;
        StressThreadWorker worker;
//添加到隊(duì)列和執(zhí)行隊(duì)列中的數(shù)據(jù)分開來寫
//將數(shù)據(jù)添加到執(zhí)行隊(duì)列中去
        for(realTotalRequests = 0; realTotalRequests < concurrencyLevel; ++realTotalRequests) {
            worker = new StressThreadWorker(stressContext, everyThreadCount);
            workers.add(worker);
        }
//將執(zhí)行隊(duì)列中的數(shù)據(jù)執(zhí)行
        for(realTotalRequests = 0; realTotalRequests < concurrencyLevel; ++realTotalRequests) {
            worker = (StressThreadWorker)workers.get(realTotalRequests);
            executorService.submit(worker);
        }
//在此處等待線程池執(zhí)行完畢
        try {
            threadEndLatch.await();
        } catch (InterruptedException var20) {
            log.error("InterruptedException", var20);
        }
//關(guān)閉線程池
        executorService.shutdownNow();
//真是請(qǐng)求的數(shù)量需要重新計(jì)算缰盏,避免上面有除不盡的情況,如并發(fā)99痰娱,總請(qǐng)求書1000
        realTotalRequests = everyThreadCount * concurrencyLevel;
        int failedRequests = failedCounter.get();
        StressResult stressResult = new StressResult();
        StressTester.SortResult sortResult = this.getSortedTimes(workers);
        List<Long> allTimes = sortResult.allTimes;
        stressResult.setAllTimes(allTimes);
        List<Long> trheadTimes = sortResult.trheadTimes;
        long totalTime = (Long)trheadTimes.get(trheadTimes.size() - 1);
        stressResult.setTestsTakenTime(totalTime);
        stressResult.setFailedRequests(failedRequests);
        stressResult.setTotalRequests(realTotalRequests);
        stressResult.setConcurrencyLevel(concurrencyLevel);
        stressResult.setWorkers(workers);
        return stressResult;
    }

下面貼一下StressThreadWorker的源碼:


package com.taobao.stresstester.core;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

class StressThreadWorker implements Runnable {
    private StressTask service;
    private CyclicBarrier threadStartBarrier;
    private CountDownLatch threadEndLatch;
    private AtomicInteger failedCounter = null;
    private int count;
    protected static Logger log = LoggerFactory.getLogger(SimpleResultFormater.class);
    private List<Long> everyTimes;

    public StressThreadWorker(StressContext stressContext, int count) {
        this.threadStartBarrier = stressContext.getThreadStartBarrier();
        this.threadEndLatch = stressContext.getThreadEndLatch();
        this.failedCounter = stressContext.getFailedCounter();
        this.count = count;
        this.everyTimes = new ArrayList(count);
        this.service = stressContext.getTestService();
    }

    public List<Long> getEveryTimes() {
        return this.everyTimes;
    }

    public void run() {
        try {
//等數(shù)據(jù)就位
            this.threadStartBarrier.await();
            this.doRun();
        } catch (Exception var2) {
            log.error("Test exception", var2);
            var2.printStackTrace();
        }

    }

    protected void doRun() throws Exception {
//此處的count數(shù)是每個(gè)線程需要執(zhí)行的數(shù)鸽粉,即請(qǐng)求總數(shù)/并發(fā)線程總數(shù)
        for(int i = 0; i < this.count; ++i) {
            long start = System.nanoTime();

            try {
                this.service.doTask();
            } catch (Throwable var12) {
//失敗次數(shù)統(tǒng)計(jì),所有線程共享 失敗次數(shù)
                this.failedCounter.incrementAndGet();
            } finally {
//在finally中進(jìn)行接收數(shù)據(jù)
//每個(gè)work是一個(gè)新對(duì)象藻三,所以統(tǒng)計(jì)的數(shù)據(jù)不會(huì)互相影響,最后的數(shù)據(jù)放在每個(gè)work中
                long var6 = System.nanoTime();
                long limit = var6 - start;
                this.everyTimes.add(limit);
            }
        }

        this.threadEndLatch.countDown();
    }
}

結(jié)果整理排序的類:

protected StressTester.SortResult getSortedTimes(List<StressThreadWorker> workers) {
        List<Long> allTimes = new ArrayList();
        List<Long> trheadTimes = new ArrayList();
        Iterator var5 = workers.iterator();

        while(var5.hasNext()) {
            StressThreadWorker worker = (StressThreadWorker)var5.next();
            List<Long> everyWorkerTimes = worker.getEveryTimes();
            long workerTotalTime = StatisticsUtils.getTotal(everyWorkerTimes);
            trheadTimes.add(workerTotalTime);
            Iterator var10 = everyWorkerTimes.iterator();

//將所有的每次執(zhí)行的時(shí)間匯總
            while(var10.hasNext()) {
                Long time = (Long)var10.next();
                allTimes.add(time);
            }
        }
//此處按照大小排序跪者,在后面取百分比多少的運(yùn)行時(shí)間時(shí)棵帽,直接按照索引取數(shù)值
        Collections.sort(allTimes);
        Collections.sort(trheadTimes);
        StressTester.SortResult result = new StressTester.SortResult();
        result.allTimes = allTimes;
        result.trheadTimes = trheadTimes;
        return result;
    }

    class SortResult {
        List<Long> allTimes;
        List<Long> trheadTimes;

        SortResult() {
        }
    }

第二步 格式化輸出

public void format(StressResult stressResult, Writer writer) {
//測(cè)試總耗時(shí)
        long testsTakenTime = stressResult.getTestsTakenTime();
//測(cè)試總請(qǐng)求數(shù)
        int totalRequests = stressResult.getTotalRequests();
//測(cè)試并發(fā)線程數(shù)
        int concurrencyLevel = stressResult.getConcurrencyLevel();
//納秒轉(zhuǎn)毫秒
        float takes = StatisticsUtils.toMs(testsTakenTime);
//此處存放的是所有請(qǐng)求的時(shí)間集合
        List<Long> allTimes = stressResult.getAllTimes();
//聚合所有時(shí)間,求和
        long totaleTimes = StatisticsUtils.getTotal(allTimes);
//TPS(每秒傳輸?shù)恼?qǐng)求)=總線程數(shù)*總請(qǐng)求數(shù)/總耗時(shí)     最后再轉(zhuǎn)換為秒級(jí)別
        float tps = 1.0E9F * (float)concurrencyLevel * ((float)totalRequests / (float)totaleTimes);
//計(jì)算平均時(shí)間(此處是納秒)
        float averageTime = StatisticsUtils.getAverage(totaleTimes, totalRequests);
//每個(gè)線程的平均時(shí)間
        float onTheadAverageTime = averageTime / (float)concurrencyLevel;
//計(jì)算指定百分比對(duì)應(yīng)索引渣玲,直接獲取索引對(duì)應(yīng)的數(shù)字逗概,即百分比多少的數(shù)據(jù)是在多少納秒之前執(zhí)行的
        int count_50 = totalRequests / 2;
        int count_66 = totalRequests * 66 / 100;
        int count_75 = totalRequests * 75 / 100;
        int count_80 = totalRequests * 80 / 100;
        int count_90 = totalRequests * 90 / 100;
        int count_95 = totalRequests * 95 / 100;
        int count_98 = totalRequests * 98 / 100;
        int count_99 = totalRequests * 99 / 100;
        long longestRequest = (Long)allTimes.get(allTimes.size() - 1);
        long shortestRequest = (Long)allTimes.get(0);
        StringBuilder view = new StringBuilder();
        view.append(" Concurrency Level:\t").append(concurrencyLevel).append("--并發(fā)數(shù)");
        view.append("\r\n Time taken for tests:\t").append(takes).append(" ms").append("--測(cè)試耗時(shí)");
        view.append("\r\n Complete Requests:\t").append(totalRequests).append("--完成測(cè)試次數(shù)");
        view.append("\r\n Failed Requests:\t").append(stressResult.getFailedRequests()).append("--失敗次數(shù)");
        view.append("\r\n Requests per second:\t").append(tps).append("--QPS");
        view.append("\r\n Time per request:\t").append(StatisticsUtils.toMs(averageTime)).append(" ms").append("--平均耗時(shí)");
        view.append("\r\n Time per request:\t").append(StatisticsUtils.toMs(onTheadAverageTime)).append(" ms (across all concurrent requests)").append("--平均耗時(shí),忽略并發(fā)影響");
        view.append("\r\n Shortest request:\t").append(StatisticsUtils.toMs(shortestRequest)).append(" ms").append("--最短耗時(shí)");
        view.append("\r\n Percentage of the requests served within a certain time (ms)");
        view.append("\r\n  50%\t").append(StatisticsUtils.toMs((Long)allTimes.get(count_50))).append("--50% 的耗時(shí)在0.005703毫秒以下");
        view.append("\r\n  66%\t").append(StatisticsUtils.toMs((Long)allTimes.get(count_66)));
        view.append("\r\n  75%\t").append(StatisticsUtils.toMs((Long)allTimes.get(count_75)));
        view.append("\r\n  80%\t").append(StatisticsUtils.toMs((Long)allTimes.get(count_80)));
        view.append("\r\n  90%\t").append(StatisticsUtils.toMs((Long)allTimes.get(count_90)));
        view.append("\r\n  95%\t").append(StatisticsUtils.toMs((Long)allTimes.get(count_95)));
        view.append("\r\n  98%\t").append(StatisticsUtils.toMs((Long)allTimes.get(count_98)));
        view.append("\r\n  99%\t").append(StatisticsUtils.toMs((Long)allTimes.get(count_99)));
        view.append("\r\n 100%\t").append(StatisticsUtils.toMs(longestRequest)).append(" (longest request)").append("--最長(zhǎng)的耗時(shí)");

        try {
            writer.write(view.toString());
        } catch (IOException var29) {
            log.error("IOException:", var29);
        }

    }
TPS和QPS的區(qū)別

TPS(transcations per second)每秒傳輸?shù)恼?qǐng)求總數(shù)忘衍。系統(tǒng)級(jí)別指標(biāo)仗谆。
QPS(queries per second)每秒查詢數(shù)指巡。單臺(tái)服務(wù)器級(jí)別指標(biāo)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末隶垮,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子秘噪,更是在濱河造成了極大的恐慌狸吞,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件指煎,死亡現(xiàn)場(chǎng)離奇詭異蹋偏,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)至壤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門威始,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人像街,你說我怎么就攤上這事黎棠。” “怎么了镰绎?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵脓斩,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我畴栖,道長(zhǎng)随静,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任吗讶,我火速辦了婚禮燎猛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘照皆。我一直安慰自己重绷,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布纵寝。 她就那樣靜靜地躺著论寨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪爽茴。 梳的紋絲不亂的頭發(fā)上葬凳,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音室奏,去河邊找鬼火焰。 笑死,一個(gè)胖子當(dāng)著我的面吹牛胧沫,可吹牛的內(nèi)容都是我干的昌简。 我是一名探鬼主播占业,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼纯赎!你這毒婦竟也來了谦疾?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤犬金,失蹤者是張志新(化名)和其女友劉穎念恍,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體晚顷,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡峰伙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了该默。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瞳氓。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖栓袖,靈堂內(nèi)的尸體忽然破棺而出匣摘,到底是詐尸還是另有隱情,我是刑警寧澤叽赊,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布恋沃,位于F島的核電站,受9級(jí)特大地震影響必指,放射性物質(zhì)發(fā)生泄漏囊咏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一塔橡、第九天 我趴在偏房一處隱蔽的房頂上張望梅割。 院中可真熱鬧,春花似錦葛家、人聲如沸户辞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽底燎。三九已至,卻和暖如春弹砚,著一層夾襖步出監(jiān)牢的瞬間双仍,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工桌吃, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留朱沃,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像逗物,于是被迫代替她去往敵國(guó)和親搬卒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容

  • 要想前員工自發(fā)建立非正式組織翎卓,首先這個(gè)企業(yè)要有足夠的吸引力和凝聚力契邀。能夠讓員工離職后都依依不舍的牽掛著對(duì)方,有可能...
    曲同寧閱讀 62評(píng)論 0 0
  • 今天去師范體育學(xué)院體驗(yàn)游泳了莲祸,來回三圈半蹂安。總體上感覺還是可以的锐帜,但從這里可以感覺到什么事情掌握好的方法和技巧,再加...
    你吖的的的閱讀 188評(píng)論 0 0