Reactive Programming Funktionale Programmierung Christoph Knabe FB VI 10.12.2014
Inhalt Reactive Programming Was ist Reactive Programming Geschichte der asynchronen Programmierung Wo bleibt die Zeit? Wartefreies Arbeiten Probleme von Threads Parallelitätswahn Das Aktorenmodell, Actor-Bibliotheken, Akka Ein Ping-Pong-Beispiel Nachrichten definieren, verarbeiten, senden ActorRef, ActorSystem, ActorContext, Scheduler Zusammenfassung 2
Reactive Programming Was ist Reactive Programming Moderner Architekturstil In Gartner: Hype Cycle for Application Architecture, 2014 als On the Rise eingestuft Beschrieben in The Reactive Manifesto V2 http://www.reactivemanifesto.org/ Deutlich detaillierter in V1 Eigenschaften: Responsive, kurze Antwortzeiten Resilient unverwüstlich, antwortet auch im Fehlerfall Elastic antwortet auch bei hoher Belastung Message Driven basiert auf asynchroner Nachrichtenübermittlung. 3
Reactive Programming Geschichte der asynchronen Programmierung Computer begannen synchron Zuse 22 (1957, ca. 200.000DM): Bild: https://de.wikipedia.org/wiki/zuse_z22#mediaviewer/file:zusez22berlintechnikmuseum.jpg Befehle kamen direkt vom Trommelspeicher 0,6ms pro Befehl (Int-Addition) Kein Zeitverlust, wenn Befehle nur sequentiell Zeitverlust Ø ½ Umdrehung = 9,6 ms bei Sprung CPU schnell, Ein/Ausgabe langsam Multiprogramming (LEO III, 1961) Wartezeiten überbrücken durch Context Switch Multi-Tasking (pdp-8, 1965) Mehrbenutzerbetrieb, unabhängige Prozesse, regelmäßiger Context Switch für Antwortzeitgarantie 4
Wo bleibt die Zeit? Reactive Programming Wartezeiten nach Peter Norvig Latency numbers every programmer should know: 0.5 ns L1 cache reference 7 ns L2 cache reference 100 ns Main memory reference 150 µs SSD random read 10 ms Hard Disk seek 150 ms Send package US-CA NL CA Punktediagramm ansehen in https://gist.github.com/hellerbarde/2843375 Ausprobieren ping java.sun.com 5
Reactive Programming Wie kann ich mir das vorstellen? Übersetzt in menschliche Dimensionen * 10 9 Würden Sie gern so lange warten? http://architects.dzone.com/articles/every-programmer-should-know 0.5 Sek. L1 cache reference 7 Sek. L2 cache reference 100 Sek. Main memory reference 1,7 Tage SSD random read 16,5 Wochen Disk seek 4,8 Jahre Send package US-CA NL CA 6
Wartefreies Arbeiten Reactive Programming Multi-Tasking (z.b. Unix) Unabhängige Prozesse mit je eigenem Speicher Kommunikation durch Mailboxen oder Dateisystem Sicher, aber aufwändig (Speicher, Prozesswechsel) Multithreading In einem Prozess laufen mehrere Threads parallel. Gemeinsamer Arbeitsspeicher und Dateideskriptoren Eigener Registersatz und Call-Stack Viel sparsamer als unabhängige Prozesse Synchronisationsbedarf wegen gemeinsam genutzter Ressourcen. 7
Reactive Programming Viele Köche verderben den Brei In Java parallele Programmierung mit Threads: Thread = sequentieller Ablauffaden parallele Ausführung mehrerer Threads gemeinsame Daten müssen in synchronized-objekt versteckt werden. Folgt C.A.R. Hoare: Monitors: An Operating System Structuring Concept, 1974 Probleme: Inkonsistenzen, wenn Zugriff auf gemeinsame Daten nicht synchronized läuft. Verlangsamung wegen Wartens auf synchronized-objekt Deadlocks bei gegenseitigem Warten Starvation (Verhungern) bei ungerechtem Scheduling und mehreren Wartenden. 8
Im Parallelitätswahn Reactive Programming Auf Java Servlet Platform (JEE): Jeder Request erhält eigenen Thread. Belegt diesen, bis die Antwort abgeliefert ist. Also ca. 150 ms ( 5 Jahre!) Davon das meiste Wartezeit! Ein Thread belegt ca. 1 MB. Parallelitätsbedarf: Google: Wieviel Requests pro Sekunde? Google-Antwortzeit? time wget http://www.google.de?q=semaphor Dividieren 9
Ein Aktor steht höher Reactive Programming Monitor-Konzept kam aus Betriebssystemen. Aktorenmodell kam aus der Künstlichen Intelligenz Carl Hewitt, Peter Bishop, Richard Steiger: A Universal Modular Actor Formalism for Artificial Intelligence, 1973 höherwertige Abstraktion kein geteilter Zustand Aktor-Eigenschaften Läuft parallel zu anderen Aktoren. Reagiert auf Nachrichten sequentiell. Kann Nachrichten versenden. Verpackt eigenen Zustand. Alle zusammen benötigen nur 1 Thread je CPU-Kern. Aufgabe: Wieviel Threads bzw. Actors können Sie im gleichen Arbeitsspeicher erzeugen? 10
Aktor-Praxis Reactive Programming Act-1 (MIT, 1981, Henry Liebermann) Jedes Objekt war ein Aktor. Benutzt für Künstliche Intelligenz. Erlang (Ericsson, 1987, Joe Amstrong) Funktionale Sprache Aktor ist Teil der Sprache. Zustand nur im Aktor Einsatz im Telekommunikationsbereich Äußerst geringe Ausfallquote Vorbild für Scala-Aktoren. 11
Reactive Programming Aktor-Bibliotheken in Scala Package scala.lang.actors Zunächst einzige Aktor-Implementierung in Scala Seit Scala 2.10 deprecated. Lift Actors Wurden im Web-Framework Lift wegen Performanzproblemen der scala.lang.actors eingeführt. Sehr leichtgewichtig Akka Actors Populärste Scala-Aktor-Bibliothek Mit Scala- und Java-API Hierarchisches Aktor-Modell Wenn Aktor ausfällt, Neustart durch Mutter-Aktor 12
Reactive Programming Akka-Aktoren anfordern in build.sbt Scala-Version festlegen: scalaversion := "2.10.4" Abhängigkeit von Akka-Aktoren angeben: librarydependencies ++= Seq( "com.typesafe.akka" %% "akka-actor" % "2.3.5" ) 13
Reactive Programming Wir wollen Ping-Pong spielen Ein Reflector soll Ping-Nachrichten verstehen: object Reflector { case class Ping(id: Int) } Ein Reflector ist ein Actor: class Reflector extends Actor with ActorLogging Ein Actor startet sofort nach Erzeugung. Ein Actor darf Zustand haben: var count = 0 14
Reactive Programming Nachrichtenverarbeitung im Aktor Er erhält seine Nachrichten sequentiell Nachrichtenverarbeitung wirkt wie Transaktion auf seinen Zustand: count += 1 Ein Actor lauscht auf Nachrichten mit receive: def receive: Receive = { case p: Ping => count += 1 log.debug(s"received $p as #$count.") } Typ Receive ist partielle Abbildung Any => Unit 15
Nachrichten senden Reactive Programming Der Thrower muss wissen, wohin Ping senden: class Thrower(reflector: ActorRef) extends Actor with ActorLogging Er soll 100 Ping-Nachrichten senden: for(i <- 1 to 100) { reflector! Reflector.Ping(i) }! sendet asynchron. Man nennt es den Bang-Operator. 16
Aktoren erzeugen Reactive Programming Wir brauchen zuerst ein ActorSystem: Im ActorSystem leben die Aktoren. val system = ActorSystem("PingPong") Erzeugen des parameterlosen Reflector-Aktors: val reflector: ActorRef = system.actorof(props[reflector], "Reflector") Erzeugen des parametrierten Thrower-Aktors: system.actorof( Props(classOf[Thrower], reflector), "Thrower" ) 17
Aktor-Regeln Reactive Programming Nie Referenz auf ein Actor-Objekt weitergeben. Das ActorSystem muss die Fäden in der Hand behalten. val system = ActorSystem("PingPong") Nicht warten im Actor: Kein Thread.sleep()! Keine Aufrufe von blockierenden Methoden wie in java.io oder traditionellen Datenbanktreibern! Verzögerte Aktionen mit Scheduler einplanen. Nur unveränderliche Objekte versenden! 18
Reactive Programming Actor-Methoden im Trait Actor ActorRef auf eigenen Actor liefern: self Bsp. Nachricht an sich selbst senden: self! Nachricht(...) ActorRef auf Absender-Actor liefern: sender Bsp. Antwort an Absender senden: sender! Antwort(...) Kontext des Actors liefern: context Nur im aktuellen Aktor gültig! 19
Reactive Programming Kontext-Methoden im Trait ActorContext Das ActorSystem liefern: context.system Bsp. System herunterfahren: context.system.shutdown() ActorRef auf Mutter-Actor liefern: context.parent Aktuelles Verhalten durch neues ersetzen: context become newreceivemethod Tod eines anderen Aktors überwachen: context watch otheractorref 20
Der Scheduler Reactive Programming Dient zum Einplanen von Nachrichtenlesen und Aktionen. Siehe http://doc.akka.io/docs/akka/2.3.5/scala/scheduler.html Einmalige Nachricht an sich einplanen, Bsp.: import scala.concurrent.duration._ context.system.scheduler.scheduleonce( 5.millis, self, "Shutdown" )(context.dispatcher, self) Regelmäßige Nachricht mittels schedule 21
Zusammenfassung Reactive Programming Reactive Systems: Schnelle, unverwüstliche, skalierbare Systeme basierend auf asynchronem Nachrichtenversand Aktorenmodell: Kein geteilter Zustand Kein Warten, sondern bei Nachricht reagieren mittels asynchronem Nachrichtenversand gut parallelisierbar und skalierbar 22
Quellen Reactive Programming Gartner-Analyse zum Hypecycle in Appl.Arch. 2014 https://www.gartner.com/doc/2810117/hype-cycle-application-architecture- The Reactive Manifesto V2 http://www.reactivemanifesto.org/ höherwertige Abstraktion kein geteilter Zustand Aktor-Eigenschaften Läuft parallel zu anderen Aktoren. Reagiert auf Nachrichten. Kann Nachrichten versenden. Verpackt eigenen Zustand. Benötigen nur 1 Thread je CPU. Auf JVM: Mio. Aktoren vs. Tsd. Threads möglich. 23
Quellen: Vielen Dank