문제

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
도움이 되었습니까?

해결책

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

다른 팁

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?

Once you get a request, you should create a new actor to handle that request. Pass on the original sender so the newly created actor knows who to answer to.

Although this thread is old, I'd like to add Spiffy (plug!) to the mix:

https://github.com/mardambey/spiffy

What is Spiffy?

Spiffy...

  • is written in Scala
  • uses the fantastic Akka library and actors to scale
  • uses servlet API 3.0 for asynchronous request handling
  • is modular (replacing components is straight forward)
  • uses DSLs to cut down on code where you don't want it
  • supports request hooks around controllers

Spiffy is a web framework using Scala, Akka (a Scala actor implementation), and the Java Servelet 3.0 API. It makes use of the the async interface and aims to provide a massively parallel and scalable environment for web applications. Spiffy's various components are all based on the idea that they need to be independent minimalistic modules that do small amounts of work very quickly and hand off the request to the next component in the pipeline. After the last component is done processing the request it signals the servlet container by "completing" the request and sending it back to the client.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top