SlideShare une entreprise Scribd logo
1  sur  28
Télécharger pour lire hors ligne
Markus Klink, @joheinz, markus.klink@oose.de

Reactive
Applications	
!

Scala, Play2 !
und Akka
All in one
Microservices
Kommunikation für REST
Schnittstellen!
viele kleine Systeme!
Technologiemix
Reactive Applications
http://reactivemanifesto.org

•

ereignisgetrieben!

•

skalierbar!

•

widerstandsfähig!

•

reaktionsschnell

•

HTML5/Javascript /
Akteure!

•

zustandslos!

•

fehlerresistent /
ausfallsicher
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
Play
Framework

Fast
Redeployment

Zustandslos

JSON
Asynchron

Scala
& Java
Websockets

HTTP
Fallbeispiel: „Simple Mechanical Turk“
Server

Client

Client

Client

Master

Server

Server
Play
•

Asynchron, non blocking!

•

keine Abstraktion über HTTP Standard!

•

JSON friendly!

•

zustandslos!

•

Akka built in!

•

Websockets, Eventsource, Comet, …
Fallbeispiel

!

•

3 Rollen: Client, Master, Server!

•

interne Kommunikation über Akteure!

•

externe Kommunikation über Akteure und Rest/Webservices
Was ist ein Akteur?
Akteure kapseln Zustand, Verhalten, besitzen eine Mailbox
und bilden

Hierarchien.!

!

Akteure kommunizieren über Nachrichten.!
!
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!

Nachrichten empfangen

!

case ImageActor.TimeOutImageEvaluation =>!
log.info("Image Expired, received time out")!
log.info("sending parent a ExpiredImageEvaluation message")!
directoryActorRef ! CommonMsg.ExpiredImageEvaluation(id)!
}!
}

Nachrichten senden
Akteur Hierarchien
Controller

reply

REST
Client

Controller

Master
RequestImage

REST

RequestImage

forward RequestImage	

via Router

Server

ImageClient

Server

ImageMaster

Response

Directory

create ImageActor

Server

Image

Image

ImageServer

erzeugt Timer

Image
Tell-Pattern
Sender

•

Empfänger ! SomeMessage!

•

„fire & forget“

Empfänger

// ImageServer	
def die(msg: String) = Action {	
directoryActor ! msg	
Ok	
}
Ask-Pattern
Sender

•

Empfänger ? SomeMessage!

•

erwarte direkte Antwort vom Empfänger

Empfänger

// ImageMaster	
def 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))	
}	
}
Forward
Sender

Intermediary

Empfänger

•

sender forward SomeMessage!

•

der ursprüngliche Sender wird „weitergereicht“
Router
Round Robin Router
Routee
!

!

Sender

Router

Routee

!

Routee

•

router ! SomeMessage!

•

sendet an einen ausgewählten Routee!

•

Round Robin Router beinhaltet die Auswahllogik
Codebeispiel
class MasterActor(serverNames: List[String]) 	
extends Actor with ActorLogging with Configured {	

Bekommt der MasterActor eine Anfrage nach einer ImageId, !
sendet er die Anfrage an den RoundRobinRouter weiter.

!

… 	
val roundRobinRouter =	
context.actorOf(Props.empty.withRouter(	
RoundRobinRouter(routees = serverRoutees)),	
"RoundRobinRouter")	

Konfiguration

!

	
def receive = LoggingReceive {	
case RequestImageId =>	
roundRobinRouter forward RequestImageId	
case … => …	
}	
!

}

Verwenden
BroadCast Router
Routee

Sender

Router

Routee

Routee
!

•

router ! SomeMessage!

•

sendet einen Broadcast an alle Routees
Codebeispiel
class 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	
}	
!
}

Der MasterActor fragt die einzelnen Server periodisch ab!
und leitet Ping Anfragen an alle Server weiter.

Konfiguration

Verwenden
ScatterGather Router
Routee

Sender

Router

Routee

Routee

•

router ! SomeMessage!

•

sendet an alle Routees, und leitet die erste Antwort zurück.
Codebeispiel
Erhält der MasterActor eine Evaluation (d.h. eine Liste vonTags für ein Bild),!
leitet er die Anfrage weiter !
class MasterActor(serverNames: List[String]) 	
und bekommt eine Antwort vom ersten Server, !
extends Actor with ActorLogging with Configured {	
!
der sich dafür zuständig erklärt.
…	
val scatterGatherRouter =	
context.actorOf(Props.empty.withRouter(	
ScatterGatherFirstCompletedRouter(routees = serverRoutees, 	
within = appConfig.defaultTimeout)),	
"ScatterGatherRouter")	

Konfiguration

!

case e: Evaluation =>	
log.info("""	
forwarding evaluation to scatterGatherRouter	
	
""")	
scatterGatherRouter forward e	
!

}	
!
}

Verwenden
Circuit Breaker => Failure
Open

Closed

Halfopen

•

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
Codebeispiel
Der Master verlangt vom ImageServer eine neue ImageId.!
!
!

/**	
Schlägt der Aufruf 3x fehl (maxFailures),
* Represents a server serving images.	
werden weitere Aufrufe sofort mit Fehler zurückgemeldet,
*	
*/	
bis sich der CirucitBreaker wieder schliesst.
class ServerActor(url: String) extends Actor with ActorLogging {	
…	
val breaker =	
new CircuitBreaker(context.system.scheduler,	
Konfigurieren
maxFailures = 3,	
callTimeout = 1 seconds,	
resetTimeout = 30 seconds)	
	
def receive = LoggingReceive {	
case RequestImageId =>	
breaker.withCircuitBreaker(WS.url(imageUrl).get) pipeTo sender	
!
Verwenden
case …	
}	
}
Akteur Supervisor => Failure
!

Controller

reply

REST
Client

Master

Jeder Akteur hat einen zugewiesenen
Supervisor.!

RequestImage

•

OneForOneStrategy: Supervisor
behandelt den Fehler für den
fehlgeschlagenen Akteur!

•

AllForOneStrategy: Supervisor
behandelt den Fehler für alle
„Siblings“

forward RequestImage	

Exception
via Router

Server

Server

Server
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
case _: ActorKilledException
case _: Exception

Escalate	

}	
…

Exceptions

Restart	
Stop	

Konfiguration
Apache Camel
Framework 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"
!

}	
…	
// send Json as Inputstream to CamelActor	
val is = IOUtils.toInputStream(Json.prettyPrint(Json.toJson(eval)))	
val headerMap = Map(Exchange.FILE_NAME -> extractFileName(id))	
camelActor ! CamelMessage(body = is, headers = headerMap)	

or „file://tmp/camel/…“
Code

Contenu connexe

Similaire à Reaktive Applikationen mit Scala, Play und Akka

HTML5 und node.js Grundlagen
HTML5 und node.js GrundlagenHTML5 und node.js Grundlagen
HTML5 und node.js Grundlagen
Mayflower GmbH
 
Ruby on Rails in a metro session
Ruby on Rails in a metro sessionRuby on Rails in a metro session
Ruby on Rails in a metro session
Virttoo org
 
Fanstatic pycon.de 2012
Fanstatic pycon.de 2012Fanstatic pycon.de 2012
Fanstatic pycon.de 2012
Daniel Havlik
 
130605 blog - drools
130605   blog - drools130605   blog - drools
130605 blog - drools
java-pe
 

Similaire à Reaktive Applikationen mit Scala, Play und Akka (20)

Rufen Sie nicht an – wir rufen Sie an! | Server-sent Events und Web-Sockets i...
Rufen Sie nicht an – wir rufen Sie an! | Server-sent Events und Web-Sockets i...Rufen Sie nicht an – wir rufen Sie an! | Server-sent Events und Web-Sockets i...
Rufen Sie nicht an – wir rufen Sie an! | Server-sent Events und Web-Sockets i...
 
HTML5 und node.js Grundlagen
HTML5 und node.js GrundlagenHTML5 und node.js Grundlagen
HTML5 und node.js Grundlagen
 
Javascript auf Client und Server mit node.js - webtech 2010
Javascript auf Client und Server mit node.js - webtech 2010Javascript auf Client und Server mit node.js - webtech 2010
Javascript auf Client und Server mit node.js - webtech 2010
 
Ruby on Rails in a metro session
Ruby on Rails in a metro sessionRuby on Rails in a metro session
Ruby on Rails in a metro session
 
Best Practices für TDD in JavaScript
Best Practices für TDD in JavaScriptBest Practices für TDD in JavaScript
Best Practices für TDD in JavaScript
 
Ist GraphQL das bessere REST
Ist GraphQL das bessere RESTIst GraphQL das bessere REST
Ist GraphQL das bessere REST
 
Fanstatic pycon.de 2012
Fanstatic pycon.de 2012Fanstatic pycon.de 2012
Fanstatic pycon.de 2012
 
Never Code Alone: Von Symfony Forms zu einer SPA auf APIs
Never Code Alone: Von Symfony Forms zu einer SPA auf APIsNever Code Alone: Von Symfony Forms zu einer SPA auf APIs
Never Code Alone: Von Symfony Forms zu einer SPA auf APIs
 
Cloud-native and Enterprise Java? Hold my beer!
Cloud-native and Enterprise Java? Hold my beer!Cloud-native and Enterprise Java? Hold my beer!
Cloud-native and Enterprise Java? Hold my beer!
 
Wie skaliert man Software as a Service Applikationen in der Windows Azure Cloud
Wie skaliert man Software as a Service Applikationen in der Windows Azure CloudWie skaliert man Software as a Service Applikationen in der Windows Azure Cloud
Wie skaliert man Software as a Service Applikationen in der Windows Azure Cloud
 
Legacy WebApps mit AngularJS pimpen
Legacy WebApps mit AngularJS pimpenLegacy WebApps mit AngularJS pimpen
Legacy WebApps mit AngularJS pimpen
 
2006 - NRW Conf: Asynchronous asp.net
2006 - NRW Conf: Asynchronous asp.net2006 - NRW Conf: Asynchronous asp.net
2006 - NRW Conf: Asynchronous asp.net
 
Ajax hands on - Refactoring Google Suggest
Ajax hands on - Refactoring Google SuggestAjax hands on - Refactoring Google Suggest
Ajax hands on - Refactoring Google Suggest
 
An Introduction to Ruby On Rails
An Introduction to Ruby On RailsAn Introduction to Ruby On Rails
An Introduction to Ruby On Rails
 
Microservices mit Rust
Microservices mit RustMicroservices mit Rust
Microservices mit Rust
 
Backend-Services mit Rust
Backend-Services mit RustBackend-Services mit Rust
Backend-Services mit Rust
 
Das Repository-Pattern und der O/R-Mapper: Geniale Kombination oder vergebene...
Das Repository-Pattern und der O/R-Mapper: Geniale Kombination oder vergebene...Das Repository-Pattern und der O/R-Mapper: Geniale Kombination oder vergebene...
Das Repository-Pattern und der O/R-Mapper: Geniale Kombination oder vergebene...
 
130605 blog - drools
130605   blog - drools130605   blog - drools
130605 blog - drools
 
Kommunikations-APIs von JavaScript (International PHP Conference/WebTechCon 2...
Kommunikations-APIs von JavaScript (International PHP Conference/WebTechCon 2...Kommunikations-APIs von JavaScript (International PHP Conference/WebTechCon 2...
Kommunikations-APIs von JavaScript (International PHP Conference/WebTechCon 2...
 
Java Servlets und AJAX
Java Servlets und AJAX Java Servlets und AJAX
Java Servlets und AJAX
 

Reaktive Applikationen mit Scala, Play und Akka

  • 1. Markus Klink, @joheinz, markus.klink@oose.de Reactive Applications ! Scala, Play2 ! und Akka
  • 5. 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
  • 7. Fallbeispiel: „Simple Mechanical Turk“ Server Client Client Client Master Server Server
  • 8. Play • Asynchron, non blocking! • keine Abstraktion über HTTP Standard! • JSON friendly! • zustandslos! • Akka built in! • Websockets, Eventsource, Comet, …
  • 9. Fallbeispiel ! • 3 Rollen: Client, Master, Server! • interne Kommunikation über Akteure! • externe Kommunikation über Akteure und Rest/Webservices
  • 10. Was ist ein Akteur? Akteure kapseln Zustand, Verhalten, besitzen eine Mailbox und bilden Hierarchien.! ! Akteure kommunizieren über Nachrichten.! !
  • 11. 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! Nachrichten empfangen ! case ImageActor.TimeOutImageEvaluation =>! log.info("Image Expired, received time out")! log.info("sending parent a ExpiredImageEvaluation message")! directoryActorRef ! CommonMsg.ExpiredImageEvaluation(id)! }! } Nachrichten senden
  • 12. Akteur Hierarchien Controller reply REST Client Controller Master RequestImage REST RequestImage forward RequestImage via Router Server ImageClient Server ImageMaster Response Directory create ImageActor Server Image Image ImageServer erzeugt Timer Image
  • 13. Tell-Pattern Sender • Empfänger ! SomeMessage! • „fire & forget“ Empfänger // ImageServer def die(msg: String) = Action { directoryActor ! msg Ok }
  • 14. Ask-Pattern Sender • Empfänger ? SomeMessage! • erwarte direkte Antwort vom Empfänger Empfänger // ImageMaster def 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)) } }
  • 17. Round Robin Router Routee ! ! Sender Router Routee ! Routee • router ! SomeMessage! • sendet an einen ausgewählten Routee! • Round Robin Router beinhaltet die Auswahllogik
  • 18. Codebeispiel class MasterActor(serverNames: List[String]) extends Actor with ActorLogging with Configured { Bekommt der MasterActor eine Anfrage nach einer ImageId, ! sendet er die Anfrage an den RoundRobinRouter weiter. ! … val roundRobinRouter = context.actorOf(Props.empty.withRouter( RoundRobinRouter(routees = serverRoutees)), "RoundRobinRouter") Konfiguration ! def receive = LoggingReceive { case RequestImageId => roundRobinRouter forward RequestImageId case … => … } ! } Verwenden
  • 19. BroadCast Router Routee Sender Router Routee Routee ! • router ! SomeMessage! • sendet einen Broadcast an alle Routees
  • 20. Codebeispiel class 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 } ! } Der MasterActor fragt die einzelnen Server periodisch ab! und leitet Ping Anfragen an alle Server weiter. Konfiguration Verwenden
  • 21. ScatterGather Router Routee Sender Router Routee Routee • router ! SomeMessage! • sendet an alle Routees, und leitet die erste Antwort zurück.
  • 22. Codebeispiel Erhält der MasterActor eine Evaluation (d.h. eine Liste vonTags für ein Bild),! leitet er die Anfrage weiter ! class MasterActor(serverNames: List[String]) und bekommt eine Antwort vom ersten Server, ! extends Actor with ActorLogging with Configured { ! der sich dafür zuständig erklärt. … val scatterGatherRouter = context.actorOf(Props.empty.withRouter( ScatterGatherFirstCompletedRouter(routees = serverRoutees, within = appConfig.defaultTimeout)), "ScatterGatherRouter") Konfiguration ! case e: Evaluation => log.info(""" forwarding evaluation to scatterGatherRouter """) scatterGatherRouter forward e ! } ! } Verwenden
  • 23. Circuit Breaker => Failure Open Closed Halfopen • 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
  • 24. Codebeispiel Der Master verlangt vom ImageServer eine neue ImageId.! ! ! /** Schlägt der Aufruf 3x fehl (maxFailures), * Represents a server serving images. werden weitere Aufrufe sofort mit Fehler zurückgemeldet, * */ bis sich der CirucitBreaker wieder schliesst. class ServerActor(url: String) extends Actor with ActorLogging { … val breaker = new CircuitBreaker(context.system.scheduler, Konfigurieren maxFailures = 3, callTimeout = 1 seconds, resetTimeout = 30 seconds) def receive = LoggingReceive { case RequestImageId => breaker.withCircuitBreaker(WS.url(imageUrl).get) pipeTo sender ! Verwenden case … } }
  • 25. Akteur Supervisor => Failure ! Controller reply REST Client Master Jeder Akteur hat einen zugewiesenen Supervisor.! RequestImage • OneForOneStrategy: Supervisor behandelt den Fehler für den fehlgeschlagenen Akteur! • AllForOneStrategy: Supervisor behandelt den Fehler für alle „Siblings“ forward RequestImage Exception via Router Server Server Server
  • 26. 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 case _: ActorKilledException case _: Exception Escalate } … Exceptions Restart Stop Konfiguration
  • 27. Apache Camel Framework 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" ! } … // send Json as Inputstream to CamelActor val is = IOUtils.toInputStream(Json.prettyPrint(Json.toJson(eval))) val headerMap = Map(Exchange.FILE_NAME -> extractFileName(id)) camelActor ! CamelMessage(body = is, headers = headerMap) or „file://tmp/camel/…“
  • 28. Code