如何编写类似Apache Bench的东西是Scala(多线程方式来打网页)

时间:2011-11-02 15:24:05

标签: java scala

在给定输入的情况下,如何编写scala脚本来执行以下操作:

url
total requests
total connections (threads)

因此request x来自给定url的x个网页,使用x个threads

它应该查看请求的响应,以确保它是正常的(不是失败的请求)。

我猜这在Scala中比在Java中更容易,因为我听说在Scala中编写多线程应用程序要容易得多。

所以:

>scalac -url localhost:8080/ -requests 1000 -connections 10

会产生1000个请求,但同时用10个线程命中它。

2 个答案:

答案 0 :(得分:2)

我已经编写了一个scala应用程序来做这件事,虽然它是围绕压力测试我正在开发的API构建的。使用actor执行并发请求非常容易。一般的想法是你想创建一个actor,当给出一个消息时,执行一个请求。然后,您创建actor的多个实例,并使用负载均衡器将请求分发给它们。

这是一个非常简单的实现,可以给你一个想法(使用Akka actor):

case class MakeRequest(url: String)
class RequestActor extends Actor {

  //force the actor to run in it's own thread
  self.dispatcher = akka.dispatch.Dispatchers.newThreadBasedDispatcher(self)

  def receive = {
    case MakeRequest(url) => //perform the request
  }
}

val totalRequests = 1000
val url = "http://..."
val totalConections = 4

//create one actor per connection and wrap them in a load balancer
val actors = (0 to totalConnections).map{i => actorOf[RequestActor].start}
val requestBalancer = loadBalancerActor(new CyclicIterator(actors))

//start sending requests
for (i <- 0 to totalRequests) {
  requestBalancer ! MakeRequest(url)
}

//send a poison pill to stop the actors after they've finished all the requests
requestBalancer ! Broadcast(PoisonPill)

//wait for the actors to finish
while (actors.foldLeft(false){ (b, a) => b || !a.isShutdown}) {
  Thread.sleep(300)
}

//stop the load balancer
requestBalancer ! PoisonPill

正如您所看到的,我正在向负载均衡器发送MakeRequest消息,负载均衡器将它们分配给各个角色。每个actor都有一个消息队列,所以一个actor会一次发出一个请求,但是actor会同时发出请求。

此示例没有提供计数响应的方法,并且您冒着溢出actor的队列的风险,但这些很容易修复。我已经用这个一般的想法进行了广泛的压力测试和基准测试,取得了巨大的成功。

答案 1 :(得分:0)

这是Scala 2.9+中一种简单,天真的方式,正如Daniel建议的那样,忽略了线程:

val url: String
val totalRequests: Int
def makeRequest(url: String): Boolean

val requests = (1 to totalRequests).par.map(i => makeRequest(url))
val successes = requests.count(r => r)
val failures = requests.count(r => !r)