Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I scale my Scala REST application that uses Akka?

I have a Scala application using Akka that receives REST requests, makes some operations against a database, and responds with some information to the client. As it is, my db operations take a long time and my REST-enabled actor is unable to respond to new requests in the meantime, even though I could run lots of operations concurrently against the DB. I'm using the javax.ws.rs annotations to REST-enable methods in my actor.

The question; what is the best way to enable my application to handle a large number of concurrent requests?

EDIT: I'll add some sample code.

  import se.scalablesolutions.akka.actor._
  import javax.ws.rs._

  @Path("/test")
  class TestService {

    @GET
    def status() = 
      actorPool !! Status(session).
        getOrElse(<error>Unable to connect to service</error>)
  }

  class TestActor {

    def receive = {
      case Status() => {
        reply(SomeObject.slowDBMethod)
      }
    }
  }

  case class Status()

EDIT2: This is what I'm getting in the log. I'm sending the three requests from my browser as fast as I can switch tabs and press F5, but the RS bean still waits for the first request to complete before handling the next.

[INFO] [2010-08-29 16:27:03,232] [akka:event-driven:dispatcher:global-15] c.n.StatusActor: got Slow request
[INFO] [2010-08-29 16:27:06,916] [akka:event-driven:dispatcher:global-10] c.n.StatusActor: got Slow request
[INFO] [2010-08-29 16:27:10,589] [akka:event-driven:dispatcher:global-3] c.n.StatusActor: got Slow request
like image 973
Magnus Avatar asked Aug 21 '10 22:08

Magnus


2 Answers

you seem to be using an older version of Akka.

I recommend to upgrade to 0.10 (which separates Actors and the RS-Beans), then you can use LoadBalancer1 (and2) to throttle the workload, or take advantage of the WorkStealingDispatcher3 (and4)

Does that help?

like image 65
Viktor Klang Avatar answered Oct 24 '22 17:10

Viktor Klang


While I realize this thread is 4+ months stale now, it's worth noting that Akka has a new HTTP module implementation that transfers the request into an actor efficiently. This approach leverages the asynchronous servlet API (also works with Jetty continuations) to enable the suspended request to be passed through the system as a message and resumed at any point; eliminating, for instance, the need to use !! to trigger actor work and respond in the annotated POJO. Likewise, since the request is suspended in the container, and the context is flipped into an actor as quick as possible, there are no threads blocking to handle the response or future.

One naive way the above example might be rewritten today:

class TestEndpoint extends Actor with Endpoint {
   def hook(uri:String) = uri == "/test"
   def provide(uri:String) = actorOf[TestService].start

   override def preStart = {
     ActorRegister.actorsFor[classOf[RootEndpoint]).head ! Endpoint.Attach(hook, provide)
   }

   def receive = handleHttpRequest
}

class TestService extends Actor {
   def receive = {

     case get:Get => 
       get.timeout(SomeObject.TimeoutInSeconds) // for example
       get.OK(SomeObject.slowDBMethod)

     case other:RequestMethod =>
      other.NotAllowed("Invalid method for this endpoint")
   }
}

More documentation can be found on the akka site: http://doc.akkasource.org/http

like image 30
Garrick Evans Avatar answered Oct 24 '22 16:10

Garrick Evans