reaktive applikationen mit scala, play und akka
DESCRIPTION
Dieser Vortrag stellt mit Play2, Scala und Akka einen Technologiestack vor, der es ermöglicht relativ einfach eine skalierbare Webarchitektur aufzubauen, die mit dem Web und nicht gegen das Web arbeitet. Insbesondere der Einsatz von Akka als flexible Messagingplattform bietet dabei einige Vorteile gegenüber konventionellen Thread basierten Lösungen in Bezug auf die horizontale Skalierung der Applikation.TRANSCRIPT
![Page 2: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/2.jpg)
All in one
![Page 3: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/3.jpg)
MicroservicesKommunikation für REST Schnittstellen!
viele kleine Systeme!
Technologiemix
![Page 4: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/4.jpg)
Reactive Applications
• ereignisgetrieben!
• skalierbar!
• widerstandsfähig!
• reaktionsschnell
• HTML5/Javascript / Akteure!
• zustandslos!
• fehlerresistent / ausfallsicher
http://reactivemanifesto.org
![Page 5: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/5.jpg)
Failures & Scalability
Hardware Software Network DAU
• Dinge scheitern!
• Scaling: Je mehr Dinge wir haben, desto mehr wird scheitern!
• Scheitern muss in das System eingebaut sein
=> Resilient Systems ermöglichen es zu skalieren
![Page 6: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/6.jpg)
Play Framework
Asynchron
JSON
Zustandslos
HTTP
Fast Redeployment
Scala & Java
Websockets
![Page 7: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/7.jpg)
Fallbeispiel: „Simple Mechanical Turk“
Client
Client
Client
Master
Server
Server
Server
![Page 8: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/8.jpg)
Play
• Asynchron, non blocking!
• keine Abstraktion über HTTP Standard!
• JSON friendly!
• zustandslos!
• Akka built in!
• Websockets, Eventsource, Comet, …
![Page 9: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/9.jpg)
Fallbeispiel
!
• 3 Rollen: Client, Master, Server!
• interne Kommunikation über Akteure!
• externe Kommunikation über Akteure und Rest/Webservices
![Page 10: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/10.jpg)
Was ist ein Akteur?Akteure kapseln Zustand, Verhalten, besitzen eine Mailbox und bilden Hierarchien.!!
Akteure kommunizieren über Nachrichten.!!
![Page 11: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/11.jpg)
Codebeispiel
class ImageActor(id: String, directoryActorRef: ActorRef) extends Actor {! ! implicit val ec = context.dispatcher!! val ticker = context.system.scheduler.scheduleOnce(3.minutes, self, ImageActor.TimeOutImageEvaluation)!! def receive = {! case ImageActor.Evaluation(_, tags) => ! ticker.cancel! log.info(s"received tags $tags for actor $self")! sender ! DirectoryActor.EvaluationAccepted!! case ImageActor.TimeOutImageEvaluation =>! log.info("Image Expired, received time out")! log.info("sending parent a ExpiredImageEvaluation message")! directoryActorRef ! CommonMsg.ExpiredImageEvaluation(id)! }!}
Nachrichten empfangen
Nachrichten senden
![Page 12: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/12.jpg)
Akteur Hierarchien
Master Direct-ory
Server Server Server Image ImageImage
Client
Cont-roller
Cont-roller
REST
REST
RequestImage
forward RequestImage via Router
RequestImage
create ImageActor
Response
reply
ImageClient ImageMaster ImageServer
erzeugt Timer
![Page 13: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/13.jpg)
Tell-Pattern
• Empfänger ! SomeMessage!
• „fire & forget“
Sender Emp-fänger
// ImageServerdef die(msg: String) = Action { directoryActor ! msg Ok }
![Page 14: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/14.jpg)
Ask-Pattern
Sender Emp-fänger
• Empfänger ? SomeMessage!
• erwarte direkte Antwort vom Empfänger
// ImageMasterdef image = Action.async { val responseFuture = (masterActor ? RequestImageId).mapTo[Response] responseFuture.map(response => response.status match { case 200 => Ok(response.body) case _ => BadRequest(response.body) }).recover { case connEx: Exception => (ServiceUnavailable(connEx.getMessage)) }}
![Page 15: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/15.jpg)
Forward
Sender
Inter-mediary Emp-
fänger
• sender forward SomeMessage!
• der ursprüngliche Sender wird „weitergereicht“
![Page 16: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/16.jpg)
Router
![Page 17: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/17.jpg)
Round Robin Router
!
!
!
• router ! SomeMessage!
• sendet an einen ausgewählten Routee!
• Round Robin Router beinhaltet die Auswahllogik
Router
Routee
Routee
Routee
Sender
![Page 18: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/18.jpg)
Codebeispielclass MasterActor(serverNames: List[String]) extends Actor with ActorLogging with Configured {! … val roundRobinRouter = context.actorOf(Props.empty.withRouter( RoundRobinRouter(routees = serverRoutees)), "RoundRobinRouter")! def receive = LoggingReceive { case RequestImageId => roundRobinRouter forward RequestImageId case … => … }!}
Konfiguration
Verwenden
Bekommt der MasterActor eine Anfrage nach einer ImageId, !sendet er die Anfrage an den RoundRobinRouter weiter.
![Page 19: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/19.jpg)
BroadCast Router
!
• router ! SomeMessage!
• sendet einen Broadcast an alle Routees
Router
Routee
Routee
Routee
Sender
![Page 20: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/20.jpg)
Codebeispielclass MasterActor(serverNames: List[String]) extends Actor with ActorLogging with Configured {! …! val broadCastRouter = context.actorOf(Props.empty.withRouter( BroadcastRouter(routees = serverRoutees)), "BroadCastRouter")! def receive = LoggingReceive { …! case Ping => broadCastRouter forward Ping }!}
Konfiguration
Verwenden
Der MasterActor fragt die einzelnen Server periodisch ab!und leitet Ping Anfragen an alle Server weiter.
![Page 21: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/21.jpg)
ScatterGather Router
• router ! SomeMessage!
• sendet an alle Routees, und leitet die erste Antwort zurück.
Router
Routee
Routee
Routee
Sender
![Page 22: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/22.jpg)
Codebeispielclass MasterActor(serverNames: List[String]) extends Actor with ActorLogging with Configured {! … val scatterGatherRouter = context.actorOf(Props.empty.withRouter( ScatterGatherFirstCompletedRouter(routees = serverRoutees, within = appConfig.defaultTimeout)), "ScatterGatherRouter")! case e: Evaluation => log.info(""" forwarding evaluation to scatterGatherRouter """) scatterGatherRouter forward e! }!}
Konfiguration
Verwenden
Erhält der MasterActor eine Evaluation (d.h. eine Liste vonTags für ein Bild),!leitet er die Anfrage weiter !
und bekommt eine Antwort vom ersten Server, !der sich dafür zuständig erklärt.
![Page 23: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/23.jpg)
Circuit Breaker => Failure
• Circuit Breaker haben einen definierten Timeout und einen Retry Counter!
• Alles gut? => Closed state!
• Timeout und Counter erreicht => Open State!
• Open State und Request => probiere einen Request alle andere werden abgelehnt!
• Half Open und Request => Alles Gut? => Closed sonst Open
Closed Open
Halfopen
![Page 24: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/24.jpg)
Codebeispiel/** * Represents a server serving images. * */class ServerActor(url: String) extends Actor with ActorLogging { … val breaker = new CircuitBreaker(context.system.scheduler, maxFailures = 3, callTimeout = 1 seconds, resetTimeout = 30 seconds) def receive = LoggingReceive { case RequestImageId => breaker.withCircuitBreaker(WS.url(imageUrl).get) pipeTo sender! case … }}
Konfigurieren
Verwenden
Der Master verlangt vom ImageServer eine neue ImageId.!Schlägt der Aufruf 3x fehl (maxFailures), !
werden weitere Aufrufe sofort mit Fehler zurückgemeldet, !bis sich der CirucitBreaker wieder schliesst.
![Page 25: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/25.jpg)
Akteur Supervisor => Failure
Master
Server Server Server
Client
Cont-roller
REST
RequestImage
forward RequestImage via Router
reply
!
Jeder Akteur hat einen zugewiesenen Supervisor.!
• OneForOneStrategy: Supervisor behandelt den Fehler für den fehlgeschlagenen Akteur!
• AllForOneStrategy: Supervisor behandelt den Fehler für alle „Siblings“
Exception
![Page 26: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/26.jpg)
Codebeispiel
// DirectoryActor receives Notification if it „died“ and the Supervisor handles the exception according// to the plan…override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) { case _: UnsupportedOperationException ⇒ Resume case _: FileNotFoundException ⇒ Restart case _: ActorKilledException ⇒ Stop case _: Exception ⇒ Escalate }…
Konfiguration
Exceptions
![Page 27: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/27.jpg)
Apache CamelFramework zur Umsetzung von Enterprise Integration Patterns!/** * Camel Producer endpoint which is configured via [[util.AppConfig.camelEndpoint]]. */class CamelActor extends Actor with Producer with Oneway with Configured with ActorLogging{! lazy val appConfig = configured[AppConfig] def endpointUri = appConfig.camelEndpoint // e.g. "activemq:evaluations" or „file://tmp/camel/…“!}…// send Json as Inputstream to CamelActorval is = IOUtils.toInputStream(Json.prettyPrint(Json.toJson(eval)))val headerMap = Map(Exchange.FILE_NAME -> extractFileName(id))camelActor ! CamelMessage(body = is, headers = headerMap)
![Page 28: Reaktive Applikationen mit Scala, Play und Akka](https://reader033.vdocuments.us/reader033/viewer/2022061202/547b5a07b4af9fe2158b4e88/html5/thumbnails/28.jpg)
Code