Akka Actors app hangs under high volume - scala

I am working on a load generator app using akka actors. The app worked fine for few million requests but when increasing the load to more than say 10 million requests or run the load for a duration ( instead of number of requests) using a infinite loop the application hangs. Below is a simplified implementation and it just prints the command being tested. I also notice that the stats are not logged or the app does'nt shutdown when the time is over. I use the schedulers to dump stats every 30 secs and shutdown the app after 2hrs. Tested with small interval and do not see the processing of the "stats" and "Shutdown" messages.
Any idea what may be causing the application to hang ?
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..")
}

Well, your actor can't process more than one message at a time, and you just set it to be busy forever sending messages. Working as designed. Remove the endless loop and send batches of messages to the loadRouter and send yourself continuation-messages to keep sending more messages.
case SendBatch =>
(1 to batchSize) foreach { router ! message }
self ! SendBatch

Related

Akka Router increment counter on message arrival from routees

I'm trying to keep counting on each successful import. But here is a problem - Counter works if the router receives a message from its parent but if I'm trying to send a message from its children it receives it but doesn't update the global variable that is out of the scope.
I know it sounds complicated. Let me show you the code.
Here is the router
class Watcher(size: Int) extends Actor {
var router = {
val routees = Vector.fill(size) {
val w = context.actorOf(
Props[Worker]
)
context.watch(w)
ActorRefRoutee(w)
}
Router(RoundRobinRoutingLogic(), routees)
}
var sent = 0
override def supervisorStrategy(): SupervisorStrategy = OneForOneStrategy(maxNrOfRetries = 100) {
case _: DocumentNotFoundException => {
Resume
}
case _: Exception => Escalate
}
override def receive: Receive = {
case container: MessageContainer =>
router.route(container, sender)
case Success =>
sent += 1
case GetValue =>
sender ! sent
case Terminated(a) =>
router.removeRoutee(a)
val w = context.actorOf(Props[Worker])
context.watch(w)
router = router.addRoutee(w)
case undef =>
println(s"${this.getClass} received undefinable message: $undef")
}
}
Here is the worker
class Worker() extends Actor with ActorLogging {
var messages = Seq[MessageContainer]()
var received = 0
override def receive: Receive = {
case container: MessageContainer =>
try {
importMessage(container.message, container.repo)
context.parent ! Success
} catch {
case e: Exception =>
throw e
}
case e: Error =>
log.info(s"Error occurred $e")
sender ! e
case undef => println(s"${this.getClass} received undefinable message: $undef")
}
}
So on supervisor ? GetValue I get 0 but suppose to have 1000.The strangest thing is that when I debug it with the breakpoint right on the case Success => ... the value is incremented every time the new message arrives. But supervisor ? GetValue still returns 0.
Let's assume I want to count on case container: MessageContainer => ... and it will magically work; I'll get desirable number, but it doesn't show if I actually imported anything. What's going on?
Here is the test case.
#Test
def testRouter(): Unit = {
val system = ActorSystem("RouterTestSystem")
// val serv = AddressFromURIString("akka.tcp://master#host:1334")
val supervisor = system.actorOf(Props(new Watcher(20)))//.withDeploy(akka.actor.Deploy(scope = RemoteScope(serv))))
val repo = coreSession.getRepositoryName
val containers = (0 until num)
.map(_ => MessageContainer(MessageFactory.generate("/"), repo))
val watch = Stopwatch.createStarted()
(0 until num).par
.foreach( i => {
supervisor ! containers.apply(i)
})
implicit val timeout = Timeout(60 seconds)
val future = supervisor ? GetValue
val result = Await.result(future, timeout.duration).asInstanceOf[Int]
val speed = result / (watch.elapsed(TimeUnit.MILLISECONDS) / 1000.0)
println(f"Import speed: $speed%.2f")
assertEquals(num, result)
}
Can you please explained it in details. Why is it happening? Why only on message received from the children? Another approach?
Well... there can be many potential problems hidden in the parts of code that you have not shared. But, for the sake of this discussion I will assume that everything else is fine and we will just discuss problems with your shared code.
Now, let me explain a bit about Actors. To put things simply, every actor has a mailbox (where it keeps messages in the sequence they were received) and processes them one by one in the order they were received. Since the mailbox is used like a Queue we will refer to it as a Queue in this discussion.
Also... I don't know what this container.apply(i) is going to return... so I will refer to the return value of that container.apply(1) as MessageContainer__1
In your test runner you are first creating an instance of Watcher,
val supervisor = system.actorOf(Props(new Watcher(20)))
Now, lets say that you are sending these 2 messages (num = 2) to supervisor,
So supervisor's mailbox will look something like,
Queue(MessageContainer__0, MessageContainer__1)
Then you send it another message GetValue so the mailbox will look like,
Queue(MessageContainer__0, MessageContainer__1, GetValue)
Now the actor will process the first message and pass it to the workers, the mail-box will look like,
Queue(MessageContainer__1, GetValue)
Now even if your worker is ultra-fast and instantaneous in sending the reply the mailbox will look like,
Queue(MessageContainer__1, GetValue, Success)
And now since your worker super-ultra-fast and instantaneously replies with a Success, the state after passing the second MessageContainer will look like,
Queue(GetValue, Success, Success)
And... here is the root of your problem. The Supervisor sees the GetValue massage before any Success messages, no matter how fast your workers are.
And thus it will process GetValue and reply with current value of sent which is 0.

Scala counter not updating when Akka message is received

I'm trying to make a small Akka example work using the following code:
class Sender extends Actor {
#volatile var numEchoes = 0
def receive = {
case Echo => {
numEchoes += 1
println(numEchoes)
if(numEchoes < Main.NUMBER_OF_ECHOES) {
println("Heard an echo...")
}
else {
// all echoes have been received.
println("All echoes heard.")
context.system.terminate
}
}
}
}
This actor is going to receive Echo messages from several Receiver actors:
class Receiver extends Actor {
def receive = {
case Echo => sender ! Echo
}
}
However, numEchoes always prints out 1. If I was doing something wrong, I'd expect 0, but this value makes me believe something else is at play here, but I'm unable to figure out what it is.
The rest of the code is just sending this specific actor a certain number of messages (lets assume 10). I see Heard an echo... printed out 10 times, but the value of this variable does not change.
#wheaties was correct. The error was in the Main object, due to some late and careless copy pasting... When I was creating 1 Sender and 10 Receiver actors, this is the code I was using:
// Create the actor that will send out the messages
val sender = actorSystem.actorOf(Props[Sender], "sender")
var actorList = List[ActorRef]()
for(i <- 1 to NUMBER_OF_ECHOES) {
val receiver = actorSystem.actorOf(Props[Sender], "receiver"+i)
actorList ::= receiver
}
Of course, creating the receivers as Senders is completely wrong, so all I had to do was fix the typo and correctly spawn the actors:
// Create the actor that will send out the messages
val sender = actorSystem.actorOf(Props[Sender], "sender")
var actorList = List[ActorRef]()
for(i <- 1 to NUMBER_OF_ECHOES) {
val receiver = actorSystem.actorOf(Props[Receiver], "receiver"+i)
actorList ::= receiver
}

scala akka: random deadLetters while no actor is asked to stop

I am chaining actors in akka-scala and at each step, the newly created actor will send a message to the supervisor actor. In response, the supervisor will increment a counter.
I don't understand why during this operations deadLetters are produced at random, sometimes no deadLetters, sometimes I get a few.
Moreover it appears that the supervisor does not increment the counter. Here's my code
import akka.actor._
object ScopeMessages{
case object AddChild
case object Counter
}
class ScopeSet(n: Int) extends Actor{
import ScopeMessages._
var root:ActorRef = context.actorOf(Props(classOf[ScopeActor],n, self))
var counter = 0
def receive:Receive = {
case AddChild => counter += 1
case Counter => sender ! counter
case _ => ()
}
}
class ScopeActor(id: Int, apex:ActorRef) extends Actor{
import ScopeMessages._
var sub:List[ActorRef] = Nil
if (id > 0){
sub = context.actorOf(Props(classOf[ScopeActor], id-1, apex))::Nil
apex ! AddChild
}
def receive:Receive = {case _ => ()}
}
object ScopeTest extends App {
import akka.testkit.TestProbe
import ScopeMessages._
implicit val system = ActorSystem("TestSys")
val p = TestProbe()
val n:Int = 10
val base_actor = system.actorOf(Props(classOf[ScopeSet], n))
p.send(base_actor, Counter)
p.expectMsg(n)
system.shutdown()
}
Thanks for help.
Remember that you have an asynchronous system here. The reason you are not seeing the correct count in your assertion is that the count is being checked before the entire tree of actors has been created. You can verify this by putting a sleep for a couple of seconds before the call to p.send. This is also probably the reason you are getting deadletters as you are shutting the system down before it's had time to set itself up. The apex actor is probably terminated but still receiving AddChild messages from the subordinates that are trying to be created while things are shutting down.
Everything cmbaxter said is true. Here's some hints on a way to fix it. Try constructing ScopeSet with the ActorRef of your TestProbe and adding a condition to you receive of AddChild. Also don't shut the actor system until the testProb has received the counter.
class ScopeSet(n: Int, testProb: ActorRef) extends Actor{
import ScopeMessages._
var root:ActorRef = context.actorOf(Props(classOf[ScopeActor],n, self))
var counter = 0
def receive:Receive = {
case AddChild => {
counter += 1
if (counter == n) { testProb ! counter }
}
case _ => ()
}
}

scala actors: drop messages if queue is too long?

I would like to drop messages from an actor's mailbox if it becomes too full. For example, if the queue size reaches 1000 messages, the oldest one should be deleted.
You cannot work with the mailbox directly, but you can implement Message Expiration pattern on top of the existing library.
Send a creation date with every message:
case class ExpirableMessage(msg: String, createdAt: Long)
Scan the mailbox with reactWithin(0), and filter out expired messages:
react{
case msg: ExpirableMessage =>
// handle the message
// clean the mailbox with nested react
reactWithin(0){
case ExpirableMessage(_, createdAt) if(currentTimeMillis - createdAt > INTERVAL) =>
case TIMEOUT =>
}
}
You can also reify an actor's queue on the heap and throttle its utilization by using a proxy actor. Then you can write something like the following:
// adder actor with a bounded queue size of 4
val adder = boundActor(4) {
loop {
react {
case x: Int => reply(x*2)
}
}
}
// test the adder
actor {
for (i <- 1 to 10) {
adder !! (i, { case answer: Int => println("Computed " + i + " -> " + answer) })
}
}
Here is the implementation of boundedActor. Note that a boundedActor must always reply to its sender, otherwise there is no way to track its queue size, and the boundedActor will freeze refusing to accept any further messages.
object ActorProxy extends scala.App {
import scala.actors._
import scala.actors.Actor._
import scala.collection.mutable._
/**
* Accepts an actor and a message queue size, and
* returns a proxy that drops messages if the queue
* size of the target actor exceeds the given queue size.
*/
def boundActorQueue(target: Actor, maxQueueLength: Int) = actor {
val queue = new Queue[Tuple2[Any, OutputChannel[Any]]]
var lastMessageSender: Option[OutputChannel[Any]] = None
def replyHandler(response: Any) {
if (lastMessageSender.get != null) lastMessageSender.get ! response
if (queue.isEmpty) {
lastMessageSender = None
} else {
val (message, messageSender) = queue.dequeue
forwardMessage(message, messageSender)
}
}
def forwardMessage(message: Any, messageSender: OutputChannel[Any]) = {
lastMessageSender = Some(messageSender)
target !! (message, { case response => replyHandler(response) })
}
loop {
react {
case message =>
if (lastMessageSender == None) {
forwardMessage(message, sender)
} else {
queue.enqueue((message, sender))
// Restrict the queue size
if (queue.length > maxQueueLength) {
val dropped = queue.dequeue
println("!!!!!!!! Dropped message " + dropped._1)
}
}
}
}
}
// Helper method
def boundActor(maxQueueLength: Int)(body: => Unit): Actor = boundActorQueue(actor(body), maxQueueLength)
}

Make Scala Remote Actors more stable

I was writing a little test program to try out some things with Remote Actors that I was going to need in a Scala project.
The basic goal was to write a test application of one server that could handle a bunch of clients and more important clients that can send multiple messages at the same time (like pings, requests for updates and user induced requests for data)
What I came up with was this:
brief overview: the client starts 3 different actors which again start actors in while loops with different offsets in order to simulate rather random messages.
import scala.actors.remote.RemoteActor
import scala.actors.remote.Node
import scala.actors.Actor
trait Request
trait Response
case object WhoAmI extends Request
case class YouAre(s:String) extends Response
case object Ping extends Request
case object Pong extends Response
case class PrintThis(s:String) extends Request
case object PrintingDone extends Response
object Server {
def main(args: Array[String]) {
val server = new Server
server.start
}
}
class Server extends Actor {
RemoteActor.alive(12345)
RemoteActor.register('server, this)
var count:Int = 0
def act() {
while(true) {
receive {
case WhoAmI => {
count += 1
sender ! YouAre(count.toString)
}
case Ping => sender ! Pong
case PrintThis(s) => {
println(s)
sender ! PrintingDone
}
case x => println("Got a bad request: " + x)
}
}
}
}
object Act3 extends scala.actors.Actor {
def act = {
var i = 0
Thread.sleep(900)
while (i <= 12) {
i += 1
val a = new Printer
a.start
Thread.sleep(900)
}
}
}
class Printer extends scala.actors.Actor {
def act = {
val server = RemoteActor.select(Node("localhost",12345), 'server)
server ! PrintThis("gagagagagagagagagagagagaga")
receive {
case PrintingDone => println("yeah I printed")
case _ => println("got something bad from printing")
}
}
}
object Act2 extends scala.actors.Actor {
def act = {
var i = 0
while (i < 10) {
i+=1
val a = new Pinger
a.start
Thread.sleep(700)
}
}
}
class Pinger extends scala.actors.Actor {
def act = {
val server = RemoteActor.select(Node("localhost",12345), 'server)
server ! Ping
receive {
case Pong => println("so I pinged and it fits")
case x => println("something wrong with ping. Got " + x)
}
}
}
object Act extends scala.actors.Actor {
def act = {
var i = 0
while(i < 10) {
i+=1
val a = new SayHi
a.start()
Thread.sleep(200)
}
}
}
class SayHi extends scala.actors.Actor {
def act = {
val server = RemoteActor.select(Node("localhost",12345), 'server)
server ! "Hey!"
}
}
object Client {
def main(args: Array[String]) {
Act.start()
//Act2.start()
Act3.start()
}
}
The problem is that things don't run as smoothly as I'd expect them to:
when I start only one of the client actors (by commenting the others out as I did with Act2in Client) things usually but not always go well. If I start two or more actors, quite often the printouts appear in bulk (meaning: there's nothing happening at once and then the printouts appear rather fast). Also the client sometimes terminates and sometimes doesn't.
This may not be the biggest problems but they're enough to make me feel quite uncomfortable. I did a lot of reading on Actors and Remote Actors but I find the available info rather lacking.
Tried to add exit statements where ever it seemed fit. But that didn't help.
Has anybody got an idea what I'm doing wrong? Any general tricks here? Some dos and donts?
My guess is that your issues stem from blocking your actor's threads by using receive and Thread.sleep. Blocking operations consume threads in the actors' thread pool, which can prevent other actors from executing until new threads are added to the pool. This question may provide some additional insight.
You can use loop, loopWhile, react, and reactWithin to rewrite many of your actors to use non-blocking operations. For example
import scala.actors.TIMEOUT
object Act extends scala.actors.Actor {
def act = {
var i = 0
loopWhile(i < 10) {
reactWithin(200) { case TIMEOUT =>
i+=1
val a = new SayHi
a.start()
}
}
}
}
Of course, you can eliminate some boilerplate by writing your own control construct:
def doWithin(msec: Long)(f: => Unit) = reactWithin(msec) { case TIMEOUT => f }
def repeat(times: Int)(f: => Unit) = {
var i = 0
loopWhile(i < times) {
f
i+=1
}
}
This would allow you to write
repeat(10) {
doWithin(200) {
(new SayHi).start
}
}
You may try Akka actors framework instead http://akkasource.org/