GO REACTIVE!
Applicazione anni 2000 Decine di server Tempi di risposta nell’ordine dei secondi Ore di downtime per manutenzione Dati nell’ordine dei Gigabyte PRINCIPI DI Accedute da dispositivi desktop Applicazione moderne (≥ 2010) REACTIVE PROGRAMMING Cluster di migliaia di processi multicore INGEGNERIA DEL SOFTWARE Tempi di risposta nell’ordine dei millisec Università degli Studi di Padova Dipartimento di Matematica 100% uptime Corso di Laurea in Informatica, A.A. 2013 – 2014 Dati nell’ordine dei Petabyte 2 Accedute da qualsiasi tipo di dispositivo
[email protected] Ingegneria del software mod. B Riccardo Cardin
GO REACTIVE! REACTIVE MANIFESTO • Real-time, engaging, reach, • Nessun redesing per Nuovi requisiti richiedono nuove tecnologie collaborative ottenere la scalabilità • Nessuna latenza nelle Reactive Application • Scalabilità on-demand risposte Orientate agli eventi • Risk-management
Scalabili "Readily responsive to a stimulus" responsive Resilienti Merriam-Webster Responsive
react to events react to load scalable resilient La natura event-driven abilita La scalabilità non deve dipendere alle altre qualità da risorse condivise event-driven • Downtime è perdita di denaro react to failure react to users • Parte del design Sistemi resilienti permettono I tempi di risposta non devono • Loosely coupled design di recuperare errori a tutti dipendere dal carico di lavoro • Communication orientation i livelli 3 4 • Uso efficiente delle risorse
Ingegneria del software mod. B Riccardo Cardin Ingegneria del software mod. B Riccardo Cardin MODELLO SINCRONO MODELLO SINCRONO
Il mondo sincrono è senza futuro... Il mondo sincrono è senza futuro... // Synchronous world (w/o Future) Esempio: recuperare il nome del file più pesante val session = socialNetwork.createSessionFor("user", credentials) // blocked on method, waiting for results (latency)... public String getBiggestFile(final File folder) { session.getFriends() long maxLength = 0L; // There are a lot of operation to do!!! :( String fileName = null; for (final File fileEntry : folder.listFiles()) { Frequenti operazioni di I/O if (maxLength < fileEntry.length()) { // Not so efficient fileName = fileEntry.getName(); Scarso utilizzo delle feature offerte dai processori moderni maxLength = fileEntry.length(); } Larga diffusione delle architetture multiprocessore } Cicli non ottimizzati return fileName ; } Scarso parallelismo o gestione difficoltosa Java fileEntry.length() // I/O if (maxLength… // computation Tipico dei linguaggi imperativi e ad oggetti C, C++, Java, ...... 5 6 Tempo totale di attesa CPU poco utilizzata, I/O sovrabbondante Ingegneria del software mod. B Riccardo Cardin Ingegneria del software mod. B Riccardo Cardin
MODELLO ASINCRONO MODELLO ASINCRONO
Callbacks Callbacks Funzioni da invocare al termine di una elaborazione CPU1 Gestione migliore della CPU CPU2 Ridotti tempi di attesa I/O è ancora presente, ma viene distribuito Più processi gestiscono più richieste CPU3 sull’elaborazione di più CPU Asynchronous JavaScript and XML (AJAX) CPU4 var callback = function(){ alert('I was called back asynchronously'); Tempo totale di attesa }; In attesa della risposta, è $.ajax({ Linguaggi o framework che gestiscano l’elaborazione type: 'GET', possibile continuare asincrona e concorrente url: 'http://example.com', l’elaborazione (rendering UI) done: callback, // positive case Node.js, jQuery, ... fail: anotherCallback // negative case 7 Ma...c’è sempre un ma... 8 }); jQuery
Ingegneria del software mod. B Riccardo Cardin Ingegneria del software mod. B Riccardo Cardin module.exports = function (dir, cb) { fs.readdir(dir, function (er, files) { if (er) return cb(er) Difficile gestire le var counter = files.length eccezioni con blocchi MODELLO ASINCRONO var errored = false try/catch var stats = []
Callbacks...HELL!!! files.forEach(function (file, index) { fs.stat(path.join(dir,file), function (er, stat) { if (errored) return if (er) { errored = true Innesto callback per gestire return cb(er) i flussi degli eventi } stats[index] = stat
if (--counter == 0) { var largest = stats .filter(function (stat) { return stat.isFile() }) .reduce(function (prev, next) { // [6] if (prev.size > next.size) return prev return next }) cb(null, files[stats.indexOf(largest)]) } }) // [1] Difficile da verificare }) // [2] 9 e manutenere 10 }) // [3] } node.js Ingegneria del software mod. B Riccardo Cardin Ingegneria del software mod. B Riccardo Cardin
FUTURES E PROMISES FUTURES E PROMISES
Futures Monad Tecnica per eseguire molte operazioni in parallelo, in Rappresenta un contesto di esecuzione (framework)
modo efficiente e non-blocking Amplificatore di tipi, computation builder
Stile dichiarativo Può racchiudere un tipo
Immutabile public class Monad
Componibili È componibile con altre monadi Implementano meccanismi per la gestione delle eccezioni Composizione (a.k.a. concatenazione) sul tipo racchiuso // With Futures (asynchronous world) val session = socialNetwork.createSessionFor("user", credentials) public class Monad
Ingegneria del software mod. B Riccardo Cardin Ingegneria del software mod. B Riccardo Cardin FUTURES E PROMISES FUTURES E PROMISES
Monad Future[T] è una monad È simile ad una bolla! Può racciudere Racchiudono l’elaborazione da eseguire in modo qualcosa asincrono (callback)
È qualcosa di Successfully completed / Failed with an exception non concreto Eventual execution: nessun vincolo temporale
import scala.util.{Success, Failure} // Asynchronous execution inside future context val f: Future[List[String]] = future { Può session.getRecentPosts evaporare, } è il risulato lasciando // Do something else... posts libero il f onComplete { dell’elaborazione // onSuccess contenuto case Success(posts) => for (post <- posts) println(post) // onFailure case Failure(t) => println("An error has occured: " + Può ricevere istruzioni su 13 t.getMessage) 14 } cosa fare del contenuto t è un’eccezione scala Ingegneria del software mod. B Riccardo Cardin Ingegneria del software mod. B Riccardo Cardin
FUTURES E PROMISES FUTURES E PROMISES Valore che rappresenta l’elaborazione Future[T] è una monad Promise[T] Composizione funzionale di più elaborazioni Single-assigment container (monad) / proxy
Non più callback hell!!! Un Future legge il risultato di un’elaborazione asincrona
Si riporta il modello asincrono al modello sincrono Una Promise scrive (completa) un Future
Se un future nella catena fallisce, fallisce l’intera catena val p = promise[T] scala // Future that is completed by the promise // First future execution val f = p.future val rateQuote = future { val consumer = future { connection.getCurrentValue(USD) startDoingSomething() } f onSuccess { // Bind second execution to first case r => doSomethingWithResult() r val purchase = rateQuote map { quote => } if (isProfitable(quote)) connection.buy(amount, quote) } produceSomething else throw new Exception("not profitable") val producer = future { } val r = produceSomething() startDoingSomething // Get final result p success r // Promise completes the Future purchase onSuccess { // It should be ‘p failure exception’ also 15 doSomethingWithResult 16 case _ => println("Purchased " + amount + " USD") continueDoingSomethingUnrelated() } scala } Ingegneria del software mod. B Riccardo Cardin Ingegneria del software mod. B Riccardo Cardin FUTURES E PROMISES FUTURES E PROMISES
Javascript promises (Q library) Java 8 promises: CompletableFuture
REACTIVE EXTENSIONS (RX) REACTIVE EXTENSIONS (RX)
Gestione sequenze di valori in modo asincrono Observables (RxJava) Observable sequences Event Iterable (pull) Observable (push) Single items Multiple items Retrieve data T next() onNext(T) T getData() Iterable
Observables (RxJava) Composizione Observables Monads Componibili
Mantengono la proprietà di asincronia originaria
21 22
Ingegneria del software mod. B Riccardo Cardin Ingegneria del software mod. B Riccardo Cardin
ACTOR MODEL ACTOR MODEL
Each actor is a form of reactive object, executing some Messaggi (task) computation in response to a message and sending out a Interfaccia di comunicazione dell’attore reply when the computation is done John C. Mitchell Variare nel tempo (comportamento) Elaborazione dei messaggi uno per volta Reactive Coda di messaggi (mail box)
Elaborazioni solo in risposta a stimoli esterni Nessuna garanzia sull’ordine di arrivo Dormiente / attivo Mail system
Non c’è un concetto esplicito di thread Ogni attore ha associato un mail address Tre azioni fondamentali Composti di tre parti Invio di un messaggio async a se stesso o altro attore tag target data Creazione nuovi attori Modifica del proprio comportamento 23 operazione email address del 24 Nessuno stato interno (...in teoria...) Immutabili receiver
Ingegneria del software mod. B Riccardo Cardin Ingegneria del software mod. B Riccardo Cardin ACTOR MODEL ACTOR MODEL
Esempio Akka Ad ogni cambio di stato viene creato un nuovo attore Toolkit e runtime che implementano attori su JVM
State change: no race conditions
Behavioural change Get_min
Min|1 Insert|2 A1:[1, 2, 4, 7] A1:[1, 4, 7]
A1:[2, 4, 7] 25 26 (c) http://akka.io
Ingegneria del software mod. B Riccardo Cardin Ingegneria del software mod. B Riccardo Cardin
AKKA AKKA scala type Receive = PartialFunction[Any, Unit] trait Actor { Esempio def receive: Receive // Actor actual behaviour Implementazione di un contatore con gli attori implicit val self: ActorRef // Reference to itself def sender: ActorRef // Reference to the sender of last message class Counter extends Actor { implicit val context: ActorContext // Execution context // State == explicit behaviour È possibile } def counter(n: Int): Receive = { abstract class ActorRef { modellare // Receive two types of messages: ‘incr’ and ‘get’ anche // Send primitives // ‘incr’ change actor’s behaviour def !(msg: Any)(implicit sender: ActorRef = Actor.noSender): Unit case ”incr” => context.become(counter(n + 1)) stati def tell(msg: Any, sender: ActorRef) = this.!(msg)(sender) // ‘get’ returns current counter value to sender interni // ... case ”get” => sender ! n } } trait ActorContext { def receive = counter(0) // Default behaviour // Change behaviour of an Actor } def become(behavior: Receive, discardOld: Boolean = true): Unit scala def unbecome(): Unit // Create a new Actor a!incr a!incr a!get sender!2 def actorOf(p: Props, name: String): ActorRef def stop(a: ActorRef): Unit // Stop an Actor // ... 27 a:[0] a:[1] a:[2] 28 }
Ingegneria del software mod. B Riccardo Cardin Ingegneria del software mod. B Riccardo Cardin sup sub1 AKKA sub2 AKKA
Error flow sub1.1 Supervisor Resilienza Actor lifecycle Contenimento e riposte automatiche agli errori An actor Start Gli attori in errore vengono terminati o riavviati new Actor La decisione è presa da un attore supervisore preStart
Gli attori con supervisione formano una struttura ad albero Le fasi di riavvio fail Il supervisore crea i suoi subordinati possono essere molteplici class Manager extends Actor { Restart // OneForOneStrategy restarts only actor which died override val supervisorStrategy = OneForOneStrategy() { preStart case _: DBException => Restart // reconnect to DB new Actor case _: ActorKilledException => Stop case _: ServiceDownException => Escalate ActorRef rimane } valido tra un // ... riavvio e l’altro stop context.actorOf(Props[DBActor], ”db”) Stop // ... 29 30 } postStop Ingegneria del software mod. B Riccardo Cardin Ingegneria del software mod. B Riccardo Cardin
BIBLIOGRAFIA BIBLIOGRAFIA
The Reactive Manifesto http://www.reactivemanifesto.org/ Monadic futures in Java 8 Promises in Node.js with Q – An Alternative to Callbacks http://zeroturnaround.com/rebellabs/monadic-futures-in- http://strongloop.com/strongblog/promises-in-node-js-with- java8/ q-an-alternative-to-callbacks/ Monads http://ericlippert.com/category/monads/ The Reactive Extensions (Rx) http://msdn.microsoft.com/en- us/data/gg577609.aspx Callback Hell http://callbackhell.com/ Futures and Promises http://docs.scala- CompletableFuture lang.org/overviews/core/futures.html http://www.slideshare.net/kojilin/completable-future Java concurrency (multi-threading) RxJava Wiki https://github.com/Netflix/RxJava/wiki http://www.vogella.com/tutorials/JavaConcurrency/article.h Functional Reactive Programming with RxJava tml#futures https://speakerdeck.com/benjchristensen/functional- Java 8: Definitive guide to CompletableFuture reactive-programming-with-rxjava-javaone-2013 http://nurkiewicz.blogspot.it/2013/05/java-8-definitive- guide-to.html Principle of Reactive Programming Taming asynchronous programming https://class.coursera.org/reactive-001 http://eamodeorubio.github.io/tamingasync/#/ 31 Actors 32 http://doc.akka.io/docs/akka/snapshot/scala/actors.html
Ingegneria del software mod. B Riccardo Cardin Ingegneria del software mod. B Riccardo Cardin