terracotta jug milano

Download Terracotta JUG Milano

If you can't read please download the document

Upload: guido-anselmi

Post on 20-May-2015

579 views

Category:

Documents


0 download

DESCRIPTION

Presentazione del 27 01 2011

TRANSCRIPT

  • 1. Clustering di applicazioni Java SEcon Terracotta Guido Anselmi [email_address] Java User Group Milano http://www.jugmilano.it

2. Sommario

  • Cos' Terracotta ed a cosa serve

3. Ambiti di utilizzo 4. Le basi del clustering in Terracotta 5. Object Roots e Clustered Objects 6. Virtual Heap 7. Thread coordination e Locks 8. Esempi di sincronizzazione/coordinamento tra JVM diverse 9. Casi d'uso e definizioni Terracotta is a transparent clustering service for Java applications I tipici casi d'uso di Terractotta possono rientrare nelle seguenti macro categorie: Distributed cache Database offload Session replication Workload partitioning 10. Overview Terracotta unserviziodiclustering trasparente . Trasparente riferito al linguaggio Java, in cui il clustering ottenuto senza alcun modello di programmazione o API specifiche. Clustering indica la capacit di consentire a macchine e processi Java multipli di lavorare insieme sugli stessi dati e di poter comunicare tra di loro utilizzando semplicamente oggetti in memoria e threading logic.Terracotta consente alle applicazioni Java di girare su quante macchine necessario, senza alcuna modifica specifica. Non vienealcun modello specifico di programmazione come clustered caching, EJB, o anche Hibernate o Spring.Terracotta pu prendere un'applicazione esistente e scalarla trasparentemente su molte macchine. 11. POJO Clustering-Instrumented classes Affinch Terracotta possa effettivamente operare sul nostro codice ( bytecodein realt), occorre indicare nella configurazione quali classi devono essere ispezionate e controllate. Questo avviene tramite il file di configurazione, nella seguente sezione: < instrumented-classes > < include > < class-expression > it.jugmilano.terracotta.example1 ..* class-expression > include > instrumented-classes > Quali classi devono essere instrumented?Per ragioni di performance bene limitare l'insieme a quello delle classi che usano root objects. 12. POJO Clustering - Roots Un oggetto definito come root l'elemento radice di un grafo di oggetti clusterizzati.Qualunque variabile di una classe pu esere dichiarata come root. La prima volta che nel codice java viene assegnato un valore ad un oggetto root, Terracotta trasforma lo stesso in clustered object, allocandolo sullo heap condiviso. In questo processo, Terracotta naviga l'intero grafo degli oggetti raggiungibili dalla root, ed essi vengono a loro volta allocati sullo heap condiviso. Le roots sono dichiarate nel file di configurazione di Terracotta ... my.package.MyClass.myRootField 13. POJO Clustering - Roots I fields dichiarati come root assumono una speciale semantica 1) La prima volta che un field root viene assegnato da una JVM, la root creata nel cluster Terracotta. 2) Una volta assegnato, il valore di un field rootnon puessere cambiato. Tutti i successivi assegnamenti, di qualunque JVM,vengono ignorati . 3) L'oggetto top level di un grafo root, non viene mai reclamato dal garbage collector distribuito di Terracotta. Il server Terracotta ha un garbage collector distribuito che rimuove i clustered objects non pi referenziati, ossia non pi raggiungibili da nessuna root (non facenti parte del grafo di nessuna root) Le roots hanno lo stesso ciclo di vita del clustered heap, e non sono legate alla singola JVM. 14. POJO Clustering - Roots Ma come fa terracotta a trasformare in maniera trasparente una variabile d'istanza o statica in un oggetto condiviso? Terracotta opera esclusivamente a livello di bytecode. Guidato da quanto indicato nella sezione instrumented-classes, opera una ricerca sulla presenza di oggetti root, e ne trasforma il bytecode. Terracotta si inserisce tra la logica applicativa e la memoria della JVM, ispezionando tutte le chiamate allo heap che coinvolgono roots objects. In particolare, tutte le letture/scritture sullo heap che coinvolgono root objects vengono sostituite da letture/scritture sul clustered heap. HEAPREAD() -> CLUSTEREDHEAPREAD() HEAPWRITE() -> CLUSTEREDHEAPWRITE() 15. POJO Clustering - Locks Quando diversi threads accedono concorrentemente gli stessi dati sullo heap, speciali precauzioni devono essere prese per evitare interferenze distruttive tra di essi. Naturalmente la cosa ancora valida quandodiversi threads su diverse jvmaccedono contemporaneamente lo stesso oggetto sul clustered heaps. Su singola JVM, java sin dagli albori offre meccanismi integrati di mutua esclusione e collaborazione, nella forma del costruttosynchronizede dei metodi di Objectwaitenotify.Nelle ultime versioni del linguaggio stato inoltre integrato il packagejava.util.concurrent , rendendo java un linguaggio con un supporto di primissimo livello al multithreading. 16. POJO Clustering - Locks Cosa deve cambiarenel codice quando mutua escliusione e collaborazione assumono una valenza a livello di cluster?Assolutamente nulla! Terracotta fornisce esattamente le stesse garanzie di serializzazione degli accessi, coordinamento e visibilit a thread in differenti JVM rispetto a quanto fa la singola JVMsui suoi threads/heap. I meccanismi che Terracotta utilizza per ottemperare a queste semantiche sono i locks. Terracotta amplia la semantica dei lock built in di Java in modo da dargli un effetto a livello di cluster. Il lock clusterizzato iniettato nel bytecode in base a quanto specificato nella sezione lock 17. POJO Clustering - Locks writevoid HelloWorld.method(..) Questa configurazione istruisce terracotta di ispezionare tutti i metodi che matchano la method-expression dentro le instrumented-classes, verificare se al loro interno ci sono accessi synchronized a fields root e, nel caso, sostituire il lock jvm con uno clustered. In luogo di possibile specificare dei La differenza tra i due che il secondo agisce sempre a livello di intero metodo, mentre il primo onora i blocchi synchronized presenti dentro i metodi. 18. POJO Clustering - Locks A differenza di Java, i lock di Terracotta hanno diversi livelli: write synchronous-write readlocks Write locks:sono i classici lock di mutua esclusione: essi garantiscono che solo un thread nell'intero cluster possa ottenere l'accesso all'oggetto protetto. Synchronous write locksaggiungono la garanzia che il lock non sia rilasciato fin quando le modifiche effettuate dal thread corrente non siano effettivamente propagate al cluster. Read locks:consentono a diversi thread di acquisire il lock sull'oggetto, a patto di non effettuare nessun operazione di scrittura (pena eccezione runtime) Nessun thread pu acquisire un lock a livello write se altri thread detengono un lock a livello read.Inoltre a nessun thread consentito di ottenere un lock read se un altro thread detiene un lock a livello write. 19. Esempio1 Immaginiamo di avere un insieme di threads il cui compito consiste unicamente nell'estrarre dei Job da un coda condivisa, elaborarli e cambiarne lo stato una volta terminato. Tali threads non devono necessariamente essere eseguiti sulla stessa JVM Job1 Job1 Job1 Job1 Job1 Job1 Jobn Job4 Job3 Job2 JVM1 thread1-3 thread1-2 thread1-1 JVM2 thread2-3 thread2-2 thread2-1 JVM3 thread3-3 thread3-2 thread3-1 20. Esempio1 La coda evidentemente un oggetto condiviso, quindi va protetta dall'accesso concorrente da parte di thread differenti (che siano sulla stessa o su diverse JVM) Una prima, molto semplificata, soluzione la seguente: public class SimpleJobQueue implements JobQueue { private List jobs = new ArrayList(); public SimpleJobQueue(int size){ for (int i=0;i < con:tc-config xmlns:con = "http://www.terracotta.org/config" > < system > < configuration-model > development configuration-model > system > < servers > < server name = "localhost" > < dso-port > 9510 dso-port > < jmx-port > 9520 jmx-port > < data > terracotta/server-data data > < logs > terracotta/server-logs logs > server > servers > < clients > < logs > terracotta/client-logs logs > clients > con:tc-config > 26. Esempio1 < application > < dso > < instrumented-classes > < include > < class-expression > *..* class-expression > include > instrumented-classes > < locks > < autolock > < method-expression > * *..*(..) method-expression > < lock-level > write lock-level > autolock > locks > < roots > < root > < field-name > it.jugmilano.terracotta.example1.main.SimpleMain.queue field-name > root > < root > < field-name > it.jugmilano.terracotta.example1.main.SimpleMain.barrier field-name > root > roots > dso > application > 27. Esempio1 A questo punto lanciamo il server Trerracotta ed infine, mandiamo in esecuzione il nostro esempio set /p base=Please enter thread name base: cd C:programmijavaworkspacesJugTerracottatargetclasses dso-java -Dtc.config=../tc-config-simple-worker.xml it.jugmilano.terracotta.example1.main.SimpleMain %base% Lanciamo questo semplice script in tre diverse shell ed il gioco fatto Quando il server Terracotta in esecuzione, lanciare un main Java con Terracotta abilitato comporta semplicemente lanciare l'interprete java con pochi JVM arguments. Se vogliamo risparmiarci questa incombenza, possiamo utilizzare lo scriptdso-javache lo fa automaticamente 28. Esempio1 Prendiamo in esame le prime linee di codice significative JobQueue queue = new SimpleJobQueue ( 10 ); CyclicBarrier barrier = new CyclicBarrier ( 33 ); In esse vengono sullo heap due diversi oggetti;ma su quale heap? E' chiaro che senza Terracotta, le tre vm in esecuzione lavorerebbero su tre spazi di memoria completamente separati, e quindi non ci sarebbe modo di far condividere la coda e la barriera a tutti i threads in esecuzione. E' evidente che questi due oggetti devono essere delle root, ossia oggetti che Terracotta costruisce sullo heap condiviso e sui quali ha pieno controllo. In tal modo, alla prima assegnazione, Terracotta alloca sul clustered heap entrambi gli oggetti. 29. Esempio1 Primo main esegue: JobQueue queue = new SimpleJobQueue ( 10 ); La variabile queue dichiarata come root, Terracotta verifica che sullo heap condiviso essa non ancora mai stata assegnata e procede alla sua istanziazione. Quando il secondo ed il terzo main eseguono la stessa operazione, Terracotta accede al clustered heap, verifica che la root queue gi stata assegnata, edignoral'istruzione. Tutte le successive operazioni sulla variabile queue(e sul grafo di oggetti ad essa collegati)avvengono sul clustered heap e NON sul local heap. 30. Esempio1 JVMX augmented bytecode bytecode 31. Esempio2 Il nostro primo esempio ha diversi difetti In particolare la gestione della sincronizzazione un evidente collo di bottiglia synchronized ( queue ) { job = queue.getJobAt( index ); status = job.getStatus(); log("Extracted Job " +index+ " in status " + status); } Questo codice guadagna un lock esclusivo sull'oggetto queue, impedendo ad ogni altro thread di accedervi (altri eventuali thread si bloccano nell'entry set). Essendo tuttavia queue definito come root ed essendo la classe SimpleWorker una instrumented class,tutti i thread di tutte le Jvm in esecuzione nel cluster devono onorare tale lock!! 32. Esempio2 Proviamo a fare di meglio, diminuendo le contese. In particolare, poich nel nostro esempio semplificato ciascun thread sa a priori a quale Job della coda deve accedere, potremmo dividere la politica di locking a livello del singolo job. public classConcurrentJobQueueimplementsJobQueue{ privateList jobs =newArrayList(); privateList locks =newArrayList() ; publicConcurrentJobQueue( intsize){ for( inti=0;i < dso > < instrumented-classes > < include > < class-expression > *..* class-expression > include > instrumented-classes > < roots > < root > < field-name > it.jugmilano.terracotta.example2.main.ConcurrentMain.queue field-name > root > < root > < field-name > it.jugmilano.terracotta.example2.main.ConcurrentMain.barrier field-name > root > roots > dso > application > 35. Esempio3 Complichiamo ancora lo scenario; finora i nostri threads lavorano in esclusione; il primo che guadagna l'accesso al job (entry della coda condivisa) effettua tutto il lavoro, gli altri aspettano passivamente. In uno scenario pi realistico, diversi threads potrebbero lavorare in collaborazione tra loro.Ad esempio il primo che guadagna l'accesso effettua un primo cambio di stato, il secondo un altro e cos via fino ad arrivare nello stato finale ove il job effettivamente stato completato. Per rendere le cose pi interessanti, scriviamo un worker generico in grado di riconoscere lo stato del job corrente e di comportarsi di conseguenza. Questo comporta lanecessit di ripensare leggermente i diversi attori. 36. Condition Le Condition, a differenza dei classici metodi di Object, consentono al singolo oggetto di comportarsi come se avesse wait-set multipli,Lock->rimpiazza synchronized Condition-> rimpiazza i metodi dei monitor di Object Le Conditions danno ai threads un mezzo a per sospendere la propria esecuzione (" wait ") fin quando notificati ( signal ) da un altro thread.La Condition stessa una shared resource, e per tale motivo dev'essere protetta da un lock.Mettersi in wait su una Condition rilasciaatomicamenteil lock detenuto su di essa. Lock lock = new ReentrantLock(); Condition cA = lock.newCondition();Condition cB = lock.newCondition(); 37. Condition I metodi offerti da Condition sono analoghi a quelli di Object: void await()sospende il thread corrente finquandosignalledointerrupted . Il lock associato con la Condition atomicamente rilasciato ed il thread corrente diventa non pi utilizabile dallo scheduler della JVM Il thread ritorna schedulabile solo quando un altro thread invocasignal()osignalAll()sulla stessa Condition,Se il thread ritorna schedulabile, esso in contesa per guadagnare il Lock. Prima che await() possa ritornare, il thread corrente deve riguadagnare il lock associato con la Condition.Quando il thread riprende l'esecuzione, garantito che detenga il lock . 38. Esempio3 Per prima cosa il Job cambia definizione: public interfaceCollaborativeJob { public static final int INITIAL_STEP= 0; public static final int STEP_1= 1; public static final int STEP_2= 2; public static final int FINAL_STEP= 3; public voidchangeStatus( intstatus); public intgetStatus(); } public classSimpleCollaborativeJobimplementsCollaborativeJob { private intjobStatus; publicSimpleCollaborativeJob(){ jobStatus =INITIAL_STEP ; } public voidchangeStatus( intstatus) { this .jobStatus = status; } public intgetStatus() { returnjobStatus; } } 39. Esempio3 Anche la coda necessita di essere modificata, aggiungendo le strutture necessarie ad implementare i meccanismi di collaborazione public classCollaborativeJobQueueimplementsJobQueue{ privateList jobs =newArrayList(); privateList locks =newArrayList(); privateList waitSets =newArrayList(); publicCollaborativeJobQueue( intsize){ for( inti=0;i 1) { log("Extracted Job " + index + " in status " + job.getStatus() + " waitingdesiredstatus= " + desiredStatus); queue.getWaitSetAt(index).await(); } Thread. sleep (1000); job.changeStatus(desiredStatus); log("Worked on Job " + index + " new status= " + job.getStatus() + " desiredstatus= " +desiredStatus); log("Job " + index + " completed "); queue.getWaitSetAt(index).signalAll(); queue.getLockAt(index).unlock(); }else{ log("Nothing TO DO status= " + job.getStatus() + " desiredstatus= " + desiredStatus); queue.getLockAt(index).unlock(); } }catch(InterruptedException e) { queue.getLockAt(index).unlock(); e.printStackTrace(); } } 41. Esempio3 Come cambia la configurazione di Terracotta? In nessun modo! Terracotta onora la semantica di java.util.concurrent, non occorre nessuna configurazione particolare. L'unico compito richiesto allo sviluppatore la correttezza del comportamento run time e l'assenza dirace-conditionsed erroritime-depending , esattamente come se si programmasse in un ambiente concorrente puro. Quest'ultimo esempio illustra perfettamente la totale trasparenza di Terracotta nel fornire allo sviluppatore un ambiente clusterizzato ed unreale parallelismo tra i threads java. Si pensi per contro a quanto sarebbe stato pi complicato edinvasivorealizzare questa stessa soluzione utilizzando altre soluzioni del mondo Java (database, JMS, RMI...) 42. Struttura esempi 43. Conclusioni Terracotta uno strumento estremamente complesso e potente, ma allo stesso tempo semplice da utilizzare, avendo esperienza di programmazione concorrente. I concetti illustrati sono alla base di soluzioni digrid computing , realizzabili con basso costo e difficolt ridotta implementativa. Ad esempio, tramite terracotta ed i concetti diroot, lock ed instrumented-classes abbastanza semplice realizzare un effettivo patternmaster-worker , utilizzabile per sistemi di produzione ad alta affidabilit ed in grado di rispondere ad elevate esigenze prestazionali. 44. Titolo --- 45. Titolo --- 46. Titolo --- 47. Titolo --- 48. Titolo ---