Scala Akka演员应用程序在高音量下挂起

Scala Akka演员应用程序在高音量下挂起,scala,actor,akka,Scala,Actor,Akka,我正在使用akka actors开发一个load generator应用程序。该应用程序在数百万个请求下运行良好,但当将负载增加到1000万个请求以上或使用无限循环运行负载一段时间(而不是请求数)时,应用程序将挂起。下面是一个简化的实现,它只打印正在测试的命令。我还注意到,统计数据没有被记录,或者应用程序没有在时间结束后关闭。我使用调度程序每30秒转储一次统计数据,并在2小时后关闭应用程序。以小间隔进行测试,没有看到“stats”和“Shutdown”消息的处理 case SendBatch =

我正在使用akka actors开发一个load generator应用程序。该应用程序在数百万个请求下运行良好,但当将负载增加到1000万个请求以上或使用无限循环运行负载一段时间(而不是请求数)时,应用程序将挂起。下面是一个简化的实现,它只打印正在测试的命令。我还注意到,统计数据没有被记录,或者应用程序没有在时间结束后关闭。我使用调度程序每30秒转储一次统计数据,并在2小时后关闭应用程序。以小间隔进行测试,没有看到“stats”和“Shutdown”消息的处理

case SendBatch =>
  (1 to batchSize) foreach { router ! message }
  self ! SendBatch
知道是什么导致应用程序挂起吗

import akka.actor._
import akka.util.duration._
import akka.routing.RoundRobinRouter
import com.test.redload.util.CommandGenerator
import org.apache.log4j.Logger
import akka.util.Duration

class LoadWorker extends Actor {
  val log = Logger.getLogger(this.getClass().getName())
  def receive = {
    case "PUT" => sender ! PUT
    case "GET" => sender ! GET
    case "DELETE" => sender ! DELETE
    case "POST" => sender ! POST
    case "HEAD" => sender ! HEAD
  } 
  def PUT():Boolean = {println("PUT");return true}
  def GET():Boolean = {println("GET");return true}
  def DELETE():Boolean = {println("DELETE");return true}
  def POST():Boolean = {println("POST");return true}
  def HEAD():Boolean = {println("HEAD");return true}
}

class LoadGenerator(nrOfWorkers:Int, noOfMessages:Int) extends Actor {

  val log = Logger.getLogger(this.getClass().getName())
  val start:Long = System.currentTimeMillis
  var noOfMessageRcvd:Int = 0
  val r = new CommandGenerator// <- is basically are list implementation that iterates and returns the next command
  r.addCommand("PUT",5) r.addCommand("GET",2) r.addCommand("DELETE",2)
  r.addCommand("POST",2) r.addCommand("HEAD",1) r.addCommand("LBRPOP",1)

  val loadRouter = context.actorOf(Props[LoadWorker].withRouter(RoundRobinRouter(nrOfWorkers)),name ="loadRouter")

  def receive = {
    case "start" => {
      if(noOfMessages > 1) {
        for( i <- 0 until noOfMessages) loadRouter ! r.getRandomCommand()
      } else {
        log.info("Time bound Load run..")
        //for( i <- 0 until 10000000) { //<- For any number greater than few millions that app hangs after few messages
        while(true){loadRouter ! r.getRandomCommand() //<- with while loop the app hangs as soon as it begins
        }
      }
    }
    case true => {
          noOfMessageRcvd +=1
          if(noOfMessages == noOfMessageRcvd){
             self ! "shutdown"
          }
    }
    case "stats" => {
          logStats()
    }
    case "shutdown" => {
          logStats()
          log.info("Shutting Down!")
          context.system.shutdown()
    }
  }
  def logStats(){
    var duration = (System.currentTimeMillis - start)/1000
    if( duration > 0) {
        log.info(noOfMessageRcvd+" messages processed in "+duration +" seconds "
         + "at "+ noOfMessageRcvd/duration +" TPS" )
    } else {
        log.info(noOfMessageRcvd+" messages processed in less than a second ")
    }
  }
}

object RedLoad extends App{
    val log = Logger.getLogger(this.getClass().getName())
    val system = ActorSystem("LoadGeneratorApp");
    // -1 is if we want to run for a period of time and > 1 the run will end after the messages are procesed
    val lg = system.actorOf(Props(new LoadGenerator(100,-1)),"LG")
    //Log the stats every 30 seconds
    system.scheduler.schedule(0 seconds,30 seconds,lg,"stats")
    //Shutdown the load run after 2 hours, if no of message is  > -1 then it will shutdown after
    //all messages are processed
    system.scheduler.scheduleOnce(2 hours,lg,"shutdown")
    lg ! "start"
    log.info("Started..")
}
导入akka.actor_
导入akka.util.duration_
导入akka.routing.RoundRobinRouter
导入com.test.redload.util.CommandGenerator
导入org.apache.log4j.Logger
导入akka.util.Duration
类LoadWorker扩展了Actor{
val log=Logger.getLogger(this.getClass().getName())
def接收={
案例“放置”=>发送方!放置
案例“获取”=>发送者!获取
案例“删除”=>发件人!删除
案例“POST”=>发件人!POST
案例“HEAD”=>发送方!HEAD
} 
def PUT():Boolean={println(“PUT”);return true}
def GET():Boolean={println(“GET”);return true}
def DELETE():布尔={println(“DELETE”);返回true}
def POST():布尔={println(“POST”);返回true}
def HEAD():Boolean={println(“HEAD”);返回true}
}
类LoadGenerator(nrOfWorkers:Int,noOfMessages:Int)扩展了Actor{
val log=Logger.getLogger(this.getClass().getName())
val start:Long=System.currentTimeMillis
var noofmessagecvd:Int=0
val r=新命令生成器//{
if(noOfMessages>1){
对于(i 0){
log.info(noOfMessageRcvd+“在”+持续时间+秒内处理的消息”
+“在”+noOfMessageRcvd/持续时间+TPS时”
}否则{
log.info(noOfMessageRcvd+“在不到一秒钟内处理的消息”)
}
}
}
对象重新加载扩展应用程序{
val log=Logger.getLogger(this.getClass().getName())
val系统=ActorSystem(“LoadGeneratorApp”);
//-1表示我们希望运行一段时间,而>1则运行将在处理消息后结束
val lg=system.actorOf(Props(新的LoadGenerator(100,-1)),“lg”)
//每30秒记录一次统计数据
系统调度程序时间表(0秒,30秒,lg,“统计”)
//2小时后关闭负载运行,如果没有消息>-1,则它将在2小时后关闭
//所有消息都已处理
system.scheduler.scheduleOnce(2小时,lg,“关机”)
lg!“开始”
log.info(“已启动…”
}

好吧,您的参与者一次不能处理多条消息,您只需将其设置为永远忙于发送消息。按设计工作。删除无休止的循环,将一批消息发送到loadRouter,并向自己发送继续消息,以继续发送更多消息

case SendBatch =>
  (1 to batchSize) foreach { router ! message }
  self ! SendBatch

请粘贴您的参与者配置。我怀疑线程不足。我添加到JVM中的唯一配置是“-Dactors.corePoolSize=20”,您能解释一下关于“发送您自己的继续消息”的更多信息吗。我可以对我的脚本做一些改进,但您的回答解决了这个问题。谢谢