2010-08-21 9 views
12

Tengo una aplicación Scala que utiliza Akka que recibe solicitudes REST, realiza algunas operaciones contra una base de datos y responde con cierta información al cliente. Tal como están las cosas, mis operaciones de DB tardan mucho y mi actor REST habilitado no puede responder a las nuevas solicitudes mientras tanto, aunque podría ejecutar muchas operaciones al mismo tiempo contra el DB. Estoy usando las anotaciones javax.ws.rs para REST-enable methods en mi actor.¿Cómo escalo mi aplicación Scala REST que usa Akka?

La pregunta; ¿Cuál es la mejor manera de permitir que mi aplicación maneje una gran cantidad de solicitudes simultáneas?

EDIT: Voy a agregar un código de muestra.

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: Esto es lo que estoy haciendo en el registro. Estoy enviando las tres solicitudes desde mi navegador tan rápido como puedo cambiar de pestañas y presiono F5, pero el bean RS todavía espera que la primera solicitud se complete antes de manipular la siguiente.

[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 
+0

Es posible que desee buscar en Apache Bench en lugar de presionar F5 tanto Gran herramienta para la prueba de concurrencia. http://httpd.apache.org/docs/2.2/programs/ab.html – cbmeeks

Respuesta

6

Si bien me doy cuenta de que este hilo tiene más de 4 meses de actualidad, vale la pena señalar que Akka tiene una nueva implementación de módulo HTTP que transfiere la solicitud a un actor de manera eficiente. Este enfoque aprovecha la API de servlet asíncrona (también funciona con continuaciones de Jetty) para permitir que la solicitud suspendida pase a través del sistema como un mensaje y se reanude en cualquier punto; eliminando, por ejemplo, la necesidad de usar !! para activar el trabajo del actor y responder en el POJO anotado. Del mismo modo, como la solicitud se suspende en el contenedor y el contexto se invierte en un actor lo más rápido posible, no hay ningún bloqueo de subprocesos para manejar la respuesta o el futuro.

Una forma ingenua el ejemplo anterior podría reescribirse hoy:

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") 
    } 
} 

Más documentación se puede encontrar en el sitio akka: http://doc.akkasource.org/http

3

Una vez que obtenga una solicitud, debe crear un nuevo actor para manejar esa solicitud. Pase el remitente original para que el actor recién creado sepa a quién responder.

+0

En una situación de actor "normal", esperaría que funcionara. Pero en mi caso, ¿realmente no puedo pasar el "remitente" en el método de estado() del ejemplo de código agregado? Supongo que cualquier cosa que haga en el método de recepción, el actor no estará listo para más solicitudes de REST, siempre que el método de estado() no se haya completado. – Magnus

+0

¿Qué le parece mantener al actor por sesión de usuario? – andreypopp

7

parece que está utilizando una versión anterior de Akka.

recomiendo actualizar a 0,10 (que separa Actores y los RS-Beans), entonces se puede utilizar LoadBalancer 1 (y 2) para estrangular la carga de trabajo, o tomar ventaja de la WorkStealingDispatcher 3 (y 4)

¿Eso ayuda?

+0

Eso parece prometedor. Voy a probar 0.10. – Magnus

+0

No pude encontrar una versión 0.10 de akka-rest, al menos en el repositorio maven2. ¿Debería usar la versión 0.8? – Magnus

+0

@Magnus Vea http://doc.akkasource.org/getting-started#The%20Next%20Steps-Using%20Akka%20with%20Maven –

1

pesar de que este hilo es viejo, me gustaría añadir Spiffy (enchufe!) a la mezcla:

https://github.com/mardambey/spiffy

lo que es Spiffy?

Spiffy ...

  • está escrito en Scala
  • utiliza la fantástica biblioteca de Akka y actores a escala
  • utiliza API servlet 3.0 para el manejo de solicitud asincrónica
  • es modular (en sustitución de los componentes es sencillo)
  • utiliza DSL para reducir el código en el que no desea que
  • soporta ganchos de solicitud de alrededor de controladores

Spiffy es un marco web que usa Scala, Akka (una implementación del actor Scala) y la API Java Servelet 3.0. Hace uso de la interfaz async y tiene como objetivo proporcionar un entorno masivamente paralelo y escalable para aplicaciones web. Los diversos componentes de Spiffy se basan en la idea de que necesitan ser módulos minimalistas independientes que hagan pequeñas cantidades de trabajo muy rápidamente y entreguen la solicitud al próximo componente de la cartera. Después de que el último componente termine de procesar la solicitud, señala al contenedor del servlet "completando" la solicitud y enviándola al cliente.

Cuestiones relacionadas