Comment puis-je échelle ma demande Scala REST qui utilise Akka?
-
30-09-2019 - |
Question
J'ai une application Scala en utilisant Akka qui reçoit des requêtes REST, fait quelques opérations contre une base de données, et répond avec quelques informations au client. Comme il est, mes opérations db prennent beaucoup de temps et mon acteur REST compatible est incapable de répondre à de nouvelles demandes dans l'intervalle, même si je pouvais courir beaucoup d'opérations en même temps contre la DB. J'utilise les annotations de javax.ws.rs à REST permettent les méthodes de mon acteur.
La question; quelle est la meilleure façon de permettre à ma demande de traiter un grand nombre de requêtes simultanées?
EDIT :. Je vais ajouter quelques exemples de 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 : Voici ce que je reçois dans le journal. J'envoie les trois demandes de mon navigateur aussi vite que je peux passer d'un onglet et appuyez sur F5, mais le haricot RS attend toujours la première demande de terminer avant de manipuler l'autre.
[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
La solution
Alors que je réalise que ce fil est 4 + mois rassis maintenant, il est intéressant de noter que Akka a une nouvelle implémentation du module HTTP qui transfère la demande en un acteur efficace. Cette approche tire parti de l'API Servlet asynchrone (fonctionne également avec continuations Jetty) pour permettre la demande suspendue à passer à travers le système comme un message et repris à tout moment; en éliminant, par exemple, la nécessité d'utiliser !! pour déclencher le travail d'acteur et de répondre dans le POJO annotée. De même, étant donné que la demande est suspendue dans le récipient, et le contexte est basculée en un acteur aussi vite que possible, il n'y a pas de blocage des fils pour gérer la réponse ou future.
Une façon naïve l'exemple ci-dessus peut être réécrite aujourd'hui:
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")
}
}
Plus de documentation sont disponibles sur le site akka: http://doc.akkasource.org/http
Autres conseils
Une fois que vous recevez une demande, vous devez créer un nouvel acteur pour gérer cette demande. Passez à l'expéditeur d'origine si l'acteur nouvellement créé qui sait répondre à.
Bien que ce fil est vieux, je voudrais ajouter au mélange Spiffy (bouchon!):
https://github.com/mardambey/spiffy
Qu'est-ce que Spiffy?
Spiffy ...
- est écrit en Scala
- utilise la bibliothèque fantastique et acteurs Akka à l'échelle
- utilise l'API Servlet 3.0 pour le traitement des requêtes asynchrones
- est modulaire (remplacement des composants est simple)
- utilise DSLs pour réduire le code où vous ne voulez pas
- supports des demandes de crochets autour de contrôleurs
Spiffy est un framework web en utilisant Scala, Akka (une mise en œuvre de l'acteur Scala), et l'API Java Servelet 3.0. Il utilise l'interface async et vise à fournir un environnement massivement parallèle et évolutive pour les applications web. divers composants de Spiffy sont tous basés sur l'idée qu'ils doivent être des modules indépendants qui font minimalistes de petites quantités de travail très rapidement et main de la demande à la composante suivante dans le pipeline. Après le dernier composant est effectué le traitement de la demande, il signale le conteneur de servlet par « remplir » la demande et l'envoyer au client.