用java编写一个简单的基准测试工具

发布于 2024-12-21 07:53:20 字数 305 浏览 2 评论 0原文

我想用 java 编写一个简单的基准测试工具,它将启动 x 个线程并总共点击 y 次 url。

它的实际任务部分将向 URL 发出 Web 请求,并发布 XML 文件。

所以我想做的是,分出 50 个线程并继续访问该 url,直到发出 10K 请求。

有人可以解释如何做到这一点,我相信使用执行器服务是正确的方法。

需要考虑的一些事情:

  1. 一旦线程完成,我猜它会立即运行另一个任务,对吗?
  2. 我需要线程返回,因为我必须跟踪成功/失败,应该将其存储在哪里(它必须是线程安全的)。

I want to write a simple benchmarking tool in java, that will spin up x threads and hit a url y times in total.

The actual task part of it will make a web request to a url, and post a XML file.

So what I want to do is, spin off 50 threads and keep hitting the url until I have made 10K requests.

Can someone explain how to do this, I believe using the Executor Service is the way to go.

Some things to consider:

  1. Once a thread is finished, I'm guessing it will immediately run another task correct?
  2. I need the thread to return as I have to keep track of success/failures, where should this be stored (it has to be thread-safe).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

凡尘雨 2024-12-28 07:53:20

是的,ExecutorService 是此任务的完美选择:

ExecutorService exec = Executors.newFixedThreadPool(50);

开始测量时间并简单地向其提交 10K 任务:

for(int i = 0; i < 10000; ++i) {
  exec(new SubmitToUrlTask());
}

考虑使用相同的实例(无状态或线程安全)SubmitToUrlTask​​而不是在每次迭代中创建新的。

最后你必须等待执行者完成:

exec.shutdown();
if(!exec.awaitTermination(1, TimeUnit.MINUTE)) {
  throw new IllegalStateException("Waiting for too long, captain!");
}

现在停止测量时间。 awaitTermination() 会阻塞,直到所有任务完成,但不会超过给定时间(示例中为 1 毫米分钟)。

一旦线程完成,我猜它会立即运行另一个任务,对吗?

是的,ExecutorService 是一堆线程和一个任务队列。如果线程没有任何事情可做,它将从队列中获取第一个任务。

我需要线程返回,因为我必须跟踪成功/失败,应该将其存储在哪里(它必须是线程安全的)。

您可以使用 CallableFuture 来跟踪结果。此外,如果您仅使用 SubmitToUrlTask​​ 的单个实例,它可以有两个 AtomicInteger 类型的变量,用于跟踪成功和失败。如果您不需要跟踪单个结果,这会简单得多。

话虽这么说,您是否考虑过使用具有所有这些功能以及更多开箱即用功能的 JMeter ?还有 ab 控制台实用程序。

Yes, ExecutorService is a perfect choice for this task:

ExecutorService exec = Executors.newFixedThreadPool(50);

Start measuring time and simply submit 10K tasks to it:

for(int i = 0; i < 10000; ++i) {
  exec(new SubmitToUrlTask());
}

Consider using the same instance of (stateless or thread-safe) SubmitToUrlTask rather than creating new one in each iteration.

At the end you must wait for the executor to finish:

exec.shutdown();
if(!exec.awaitTermination(1, TimeUnit.MINUTE)) {
  throw new IllegalStateException("Waiting for too long, captain!");
}

Stop measuring the time now. awaitTermination() blocks until all tasks have finished, but not longer than given time (1 mminute in the example).

Once a thread is finished, I'm guessing it will immediately run another task correct?

Yes, ExecutorService is a bunch of threads and a queue of tasks. If a thread does not have anything to do, it takes first task from the queue.

I need the thread to return as I have to keep track of success/failures, where should this be stored (it has to be thread-safe).

You can use Callable<Boolean> and Future<Boolean> to track results. Also if you are using only a single instance of SubmitToUrlTask, it can have two variables of AtomicInteger type, tracking both successes and failures. This is much simpler if you don't need to track individual results.

That being said, have you considered using JMeter that has all these functionalities + much more out of the box? There is also ab console utility.

请帮我爱他 2024-12-28 07:53:20

以下是带注释的源代码,概述了您可以使用的策略:

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class LoadGen {
    /**
     * Hits the given url for nRequests times on nUsers threads.
     *
     * @return LoadGen.Result object with status of the test
     */
    public static Result generateLoad(final String url,
        int nUsers, int nRequests) throws InterruptedException {
        // A thread pool with one thread per simulated user
        ExecutorService threadPool = Executors.newFixedThreadPool(nUsers);

        // A latch awaited on by the user threads before the test is started
        final CountDownLatch startSignal = new CountDownLatch(1);

        // A latch awaited on by the main thread for all user threads 
        // to complete the test
        final CountDownLatch doneSignal = new CountDownLatch(nUsers);

        // The Result object for this test run
        final Result result = new Result(nRequests);

        // Submit one Runnable per simulated user
        for (int i = 0; i < nUsers; i++) {
            threadPool.submit(new Runnable() {
                public void run() {
                    try {
                        // the Runnable awaits for the test to start
                        startSignal.await();

                        runSimulatedUser(url, result);

                        // indicate that this thread has completed
                        doneSignal.countDown();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }

        // Start all simulated user threads
        startSignal.countDown();

        // Wait for all simulated user threads to complete the test
        doneSignal.await();

        // Dispose all threads
        threadPool.shutdownNow();
        return result;
    }

    private static void runSimulatedUser(String url, Result result) {
        // run repeatedly ..
        while (true) {
            try {
                // hitting the URL, marking success and failure
                // until nRequests requests are made in total
                makeRequest(url);
                if (! result.success()) {
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
                if (! result.failure()) {
                    break;
                }
            }
        }
    }

    private static void makeRequest(String url) {
        // TODO: post the XML document to the URL etc
        System.out.println("Making request");
    }

    public static class Result {
        private final AtomicInteger nSuccess = new AtomicInteger();
        private final AtomicInteger nFailure = new AtomicInteger();
        private final AtomicInteger nTotal;

        public Result(int nTotal) {
            this.nTotal = new AtomicInteger(nTotal);
        }

        boolean success() {
            nSuccess.incrementAndGet();
            return nTotal.decrementAndGet() > 1;
        }

        boolean failure() {
            nFailure.incrementAndGet();
            return nTotal.decrementAndGet() > 1;
        }

        int getSuccessCount() {
            return nSuccess.get();
        }

        int getFailureCount() {
            return nFailure.get();
        }
    }

    public static void main(String[] args) throws Exception {
        // generate 10 requests on 2 threads
        LoadGen.generateLoad("http://myurl.com", 2, 10);
    }
}

Here is the annotated source code which outlines a strategy you can use:

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class LoadGen {
    /**
     * Hits the given url for nRequests times on nUsers threads.
     *
     * @return LoadGen.Result object with status of the test
     */
    public static Result generateLoad(final String url,
        int nUsers, int nRequests) throws InterruptedException {
        // A thread pool with one thread per simulated user
        ExecutorService threadPool = Executors.newFixedThreadPool(nUsers);

        // A latch awaited on by the user threads before the test is started
        final CountDownLatch startSignal = new CountDownLatch(1);

        // A latch awaited on by the main thread for all user threads 
        // to complete the test
        final CountDownLatch doneSignal = new CountDownLatch(nUsers);

        // The Result object for this test run
        final Result result = new Result(nRequests);

        // Submit one Runnable per simulated user
        for (int i = 0; i < nUsers; i++) {
            threadPool.submit(new Runnable() {
                public void run() {
                    try {
                        // the Runnable awaits for the test to start
                        startSignal.await();

                        runSimulatedUser(url, result);

                        // indicate that this thread has completed
                        doneSignal.countDown();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }

        // Start all simulated user threads
        startSignal.countDown();

        // Wait for all simulated user threads to complete the test
        doneSignal.await();

        // Dispose all threads
        threadPool.shutdownNow();
        return result;
    }

    private static void runSimulatedUser(String url, Result result) {
        // run repeatedly ..
        while (true) {
            try {
                // hitting the URL, marking success and failure
                // until nRequests requests are made in total
                makeRequest(url);
                if (! result.success()) {
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
                if (! result.failure()) {
                    break;
                }
            }
        }
    }

    private static void makeRequest(String url) {
        // TODO: post the XML document to the URL etc
        System.out.println("Making request");
    }

    public static class Result {
        private final AtomicInteger nSuccess = new AtomicInteger();
        private final AtomicInteger nFailure = new AtomicInteger();
        private final AtomicInteger nTotal;

        public Result(int nTotal) {
            this.nTotal = new AtomicInteger(nTotal);
        }

        boolean success() {
            nSuccess.incrementAndGet();
            return nTotal.decrementAndGet() > 1;
        }

        boolean failure() {
            nFailure.incrementAndGet();
            return nTotal.decrementAndGet() > 1;
        }

        int getSuccessCount() {
            return nSuccess.get();
        }

        int getFailureCount() {
            return nFailure.get();
        }
    }

    public static void main(String[] args) throws Exception {
        // generate 10 requests on 2 threads
        LoadGen.generateLoad("http://myurl.com", 2, 10);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文