2011-12-14 83 views
2

我想在java中编写一个简单的基准测试工具,它将启动x个线程并总共打满一次url。在java中编写一个简单的基准测试工具

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

所以我想要做的是,分拆50个线程,并保持点击的网址,直到我提出了10K请求。

有人可以解释如何做到这一点,我相信使用Executor服务是要走的路。

有些事情要考虑:

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

你有什么这么远吗? – jtahlborn 2011-12-14 14:50:48

+0

你确定你不是指“加载模拟器”吗?基准测试通常会涉及到一些速度问题,这听起来有点像“我的10k时间,并看看有多少请求失败”。我问,因为如果你想要一个基准,而不是压力测试,结果会有所不同。 – jefflunt 2011-12-14 14:50:49

回答

3

是,ExecutorService是这个任务的最佳选择:

ExecutorService exec = Executors.newFixedThreadPool(50); 

开始计时,并请提交10K任务是:

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

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

在您必须等待执行完成结束:

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

现在停止计时。 awaitTermination()块直到全部任务已完成,但不超过给定时间(示例中为1分钟)。

一旦一个线程完成,我猜它会立即运行另一个任务是否正确?

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

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

您可以使用Callable<Boolean>Future<Boolean>来跟踪结果。此外,如果您仅使用SubmitToUrlTask的单个实例,则它可以具有两个变量AtomicInteger类型,用于跟踪成功和失败。如果您不需要跟踪单个结果,这将简单得多。

话虽如此,你有没有考虑过使用JMeter具有所有这些功能+更多的开箱即用?还有ab控制台实用程序。

1

这里是一个概述了一个战略,你可以使用注释的源代码:

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); 
    } 
}