Supporto per servizi di File Hosting
Transcript
Supporto per servizi di File Hosting
Supporto per servizi di File Hosting Progetto per il corso di Reti di Calcolatori LS – a.a 2005-2006 Valerio Guagliumi – 0000236769 Abstract Questa relazione descrive il progetto realizzato di un sistema di supporto allo sviluppo di servizi di File Hosting affidabili e con bilanciamento del carico. Il sistema è indipendente dal contesto applicativo e dai protocolli utilizzati e propone una soluzione scalabile e con overhead limitato, che si adatta facilmente ai requisiti di progetto. 1. Introduzione La rapida espansione delle reti di calcolatori su larga scala negli ultimi decenni, ha incentivato molti fornitori di servizi a studiare e inventare nuove forme di comunicazione per venire incontro ai bisogni dei clienti. Tra le tecnologie di servizio sviluppatesi, molte sono nate per rispondere all’esigenza degli utenti di comunicare tra loro e condividere risorse e dati; queste tecnologie seguono quindi un modello di comunicazione consumer-to-consumer, che apre canali tra gli utenti stessi, piuttosto che tra l’erogatore ed il consumatore di un servizio. Oltre ai sistemi di messaggistica, che permettono agli utenti di inviare e ricevere informazioni sotto forma di messaggi testuali, un’altra branca di servizi di questo tipo è costituita dai sistemi di scambio di file, nei quali vengono trasmesse informazioni sotto forma di documenti generici. Una possibile realizzazione di servizi di questo tipo è quella del File Sharing: applicazioni distribuite tramite le quali gli utenti possono scambiare file in maniera sincrona e tipicamente solo uno-a-uno; prevedono cioè un solo mittente ed un solo ricevente, i quali devono essere entrambi presenti contemporaneamente per tutta la durata della trasmissione. Altri servizi, che prendono il nome di File Hosting, permettono una maggiore flessibilità nella modalità di comunicazione tra utenti, fornendo supporto allo scambio di file in maniera asincrona e con più possibili riceventi. In questi sistemi le entità che desiderano partecipare alla comunicazione assumono il ruolo di clienti di un servitore che espone delle operazioni di Upload e Download, che corrispondono rispettivamente a operazioni di scrittura e lettura di un file su un dispositivo di memorizzazione permanente. La qualità dei sistemi di file hosting è legata in gran parte alle loro proprietà di availability (la garanzia che il servizio sia sempre disponibile per eseguire upload e download) e di correctness (la certezza che il contenuto dei file letti dal sistema sia sempre lo stesso memorizzato all’atto della scrittura); questo progetto nasce con l’idea di fornire un supporto per la realizzazione di sistemi di file hosting fault-tolerant e scalabili che siano dotati di queste caratteristiche. 2. Architettura del sistema La tecnica comunemente adottata per ottenere garanzie di correttezza in un servizio di File Hosting è l’uso di risorse replicate, che significa mantenere più copie dello stesso file su diversi servitori, e verificarne all’occorrenza la consistenza confrontandole tra loro. La replicazione dei file permette inoltre di fornire il servizio anche in caso di caduta di uno o più dei nodi, purchè sia attivo almeno uno dei nodi in grado di ricevere ed eseguire le operazioni di upload e download. Un problema con cui si scontrano spesso i servizi di File Hosting è costituito dalle situazioni di congestione in cui si vengono a trovare i nodi servitori nel caso in cui debbano servire un numero di operazioni superiore a quanto è possibile secondo le loro capacità computazionali, oppure una volta esaurito lo spazio disponibile per la memorizzazione dei file. Per queste ragioni il sistema è organizzato in gruppi di replicazione tra loro indipendenti: tutti i nodi che appartengono ad uno stesso gruppo replicano ciascuno lo stesso insieme di file; un nodo speciale, detto Proxy, si occupa di ricevere ciascuna richiesta proveniente da un cliente e delegarla ad uno dei nodi del gruppo di replicazione a cui il file richiesto è univocamente assegnato. La redirezione delle richieste da parte del Proxy verso un nodo delegato ad eseguire l’operazione, scarica il Proxy da ogni responsabilità sull’effettivo trasferimento (il quale rischierebbe altrimenti di congestionarsi facilmente e fare da “collo di bottiglia” per il sistema), e permette di implementare politiche di Load Balancing per suddividere tra i nodi di ogni gruppo di replicazione le risorse computazionali e la banda, e, allo stesso tempo, partizionare sui diversi gruppi la capacità di memoria richiesta. Il Proxy ha a sua disposizione ad ogni istante le informazioni su quali nodi di ciascun gruppo sono attivi; se almeno un nodo per ogni gruppo è attivo, il sistema è complessivamente in grado di erogare il servizio, altrimenti il Proxy nega al client la possibilità di eseguire operazioni di upload o download. Il progetto, sviluppato in Java, fornisce un supporto allo sviluppo di sistemi di File Hosting. La comunicazione tra il Proxy e i nodi di replicazione è implementata con Socket TCP, mentre il protocollo e i metodi di comunicazione tra il client e i diversi nodi del sistema, che sono variabili strettamente legate al contesto applicativo, non sono specificati. Ad esempio, nel caso di servizio di Web File Hosting, queste comunicazioni dovrebbero avvenire tramite HTTP, e i Proxy e i nodi di replicazione comunicherebbero con i clienti tramite Web Server. Sono quindi fornite le interfacce da implementare per definire protocolli di comunicazione, politiche di scelta dei nodi per servire le richieste, codifiche da applicare sui messaggi di delega che il Proxy indirizza ai nodi di replicazione tramite la redirezione dei client, e altri parametri che regolano il funzionamento del sistema. 3. Gruppo di replicazione e inizializzazione Per avere informazioni in tempo reale sullo stato di attività di ciascun nodo di replicazione, il Proxy configura ogni gruppo di replicazione in maniera che ogni nodo abbia assegnato un nodo controllore, il quale ha il compito di interrogarlo periodicamente e notificare il Proxy in caso di mancata risposta dal nodo controllato. Caduta di nodo singolo Durante il funzionamento a regime ogni nodo ha, oltre all’indirizzo del nodo da controllare, anche l’indirizzo del successore di questo; nel caso in cui il nodo non risponda ad una interrogazione IS_ALIVE, il controllore passa ad interrogare il nodo successivo. Per fare in modo che ogni nodo conosca il successore del nodo controllato, ogni messaggio di risposta IS_ALIVE_OK deve riportare, nel caso in cui il nodo controllato sia cambiato dalla precedente interrogazione subita, l’indirizzo del nuovo successore. Nell’ipotesi in cui il tempo che trascorre tra la caduta del nodo e lo scadere del timeout dell’interrogazione sia inferiore al time-between-failures minimo, questo accorgimento è sufficiente a garantire il funzionamento corretto di ciascun gruppo di replicazione. Se invece un nodo riscontra una situazione di fallimento multiplo, ovvero, sia il nodo controllato, sia il suo successore, non rispondono, comunica la situazione di errore al Proxy con una richiesta di inizializzazione. Durante la fase di inizializzazione (illustrata in seguito) il gruppo di replicazione in cui si è verificato l’errore viene riconfigurato, assegnando nuovamente a ciascun nodo il rispettivo nodo da controllare tra quelli attivi. Falsa caduta di un nodo La mancata ricezione di una risposta al messaggio IS_ALIVE entro il timeout non garantisce che un nodo sia effettivamente caduto; il nodo in questione potrebbe avere ritardato la risposta per altre ragioni ed essere ancora attivo. In una situazione di questo tipo il sistema deve essere in grado di accorgersi della anomalia ed eseguire una inizializzazione del gruppo, considerando anche il nodo che era apparentemente caduto. Per questo motivo ogni nodo memorizza un identificativo del nodo che è responsabile del suo controllo; questo identificativo viene aggiornato ogni volta che si riceve un messaggio IS_ALIVE_NEW_ID, inviato dal nodo che, riscontrata la caduta del suo successore, passa a controllare il nodo successivo. Quando un nodo riceve un messaggio IS_ALIVE da un mittente che ha un identificativo diverso da quello memorizzato, risponde con un IS_ALIVE_WRONG_ID, col quale notifica il nodo che l’ha interrogato della sua uscita dal gruppo di replicazione. Il nodo che riceve come risposta IS_ALIVE_WRONG_ID può quindi richiedere al Proxy una nuova inizializzazione. Inizializzazione Il Proxy ha il compito di avviare una fase di inizializzazione (durante la quale si riorganizza un gruppo di replicazione riassegnando le responsabilità di controllo di ciascuno dei nodi attivi) nelle seguenti occasioni: All’avvio del Proxy, per verificare in ogni gruppo di replicazione quali nodi sono attivi e inizializzarli (quindi anche in caso di caduta e riavvio del Proxy) In seguito alla ricezione di una richiesta di inizializzazione da parte di un nodo del gruppo (che può avvenire sia all’avvio/riavvio di un nodo, sia in caso di ricezione di falsa caduta) In entrambi i casi il Proxy notifica tutti i nodi del gruppo inviando un messaggio INIT a ciascuno, e attendendo in risposta un messaggio INIT_OK entro un tempo di timeout, con il quale i nodi manifestano la loro partecipazione all’inizializzazione. Ogni nodo che risponde con INIT_OK notifica il Proxy di avere cessato l’interrogazione di un eventuale nodo controllato con messaggi IS_ALIVE, e di essere in attesa di un messaggio WATCH con l’indirizzo del nuovo nodo da controllare. Considerando attivi i soli nodi che rispondono al messaggio INIT entro il timeout, il Proxy organizza l’anello inviando a ciascun nodo il messaggio WATCH e attendendo risposta; se almeno uno dei nodi partecipanti non risponde con un messaggio WATCH_OK, l’inizializzazione viene considerata fallita e ripetuta. I nodi che ricevono il messaggio WATCH estraggono l’indirizzo inviato dal Proxy e ricominciano l’interrogazione tramite IS_ALIVE, fino alla successiva ricezione di un messaggio INIT. 4. Il coordinamento delle copie Ciascun nodo di un gruppo di replicazione è in grado di servire richieste di download e upload indipendentemente dagli altri nodi; ciascuna operazione quindi agisce sui file memorizzati localmente sul nodo, senza alcun tipo di comunicazione con gli altri. Questa scelta è dovuta al fatto che in un sistema di file hosting la prontezza del servizio è uno dei requisiti principali, ed eseguire un coordinamento con tutti i nodi del gruppo ad ogni richiesta di un cliente porterebbe a tempi di attesa troppo elevati. Le fasi di coordinamento delle copie in un gruppo hanno pertanto un duplice scopo: Propagare a tutti i nodi i file memorizzati solo sul nodo che ne ha gestito l’upload. Garantire che le copie di ciascun file siano identiche su tutti i nodi del gruppo. Il modello di replicazione dei file è quindi passivo; File Contenuto PRIMA del coordinamento un servizio che esegue in background si occupa di NodoA NodoB NodoC svolgere periodicamente il coordinamento (ad text.txt 98 A9 1B… istanti di checkpoint) senza incidere sui tempi di video.wmv 80 11 FC… 40 11 FC… 80 11 FC… risposta alle richieste di upload e download. archive.zip 12 2D D6 Per queste ragioni il sistema non è in grado di garantire la consistenza delle copie ad ogni trasferimento, ma un opportuno dimensionamento del periodo che intercorre tra un coordinamento e l’altro permette (scegliendo un compromesso tra correttezza e tempi di risposta) di garantire un livello di consistenza adeguato alle esigenze applicative e alle risorse disponibili. File Contenuto DOPO il coordinamento text.txt NodoA 98 A9 1B… NodoB 98 A9 1B… NodoC 98 A9 1B… video.wmv archive.zip 80 11 FC… 12 2D D6 80 11 FC… 12 2D D6 80 11 FC… 12 2D D6 Protocollo di coordinamento – il ruolo del Proxy Durante il funzionamento del sistema, il Proxy si occupa di verificare lo stato delle operazioni di coordinamento in corso e di comandarne l’esecuzione in caso in cui sia passato un intervallo di tempo sufficiente dall’ultimo coordinamento eseguito con successo (il periodo di coordinamento è un parametro di configurazione del sistema). Il Proxy inoltre verifica se, nel gruppo che si vuole coordinare, ci sono sufficienti nodi attivi; il numero di nodi minimo richiesto per il coordinamento è definito a livello applicativo: un valore elevato riduce le possibilità che gli errori vengano propagati (ad esempio un coordinamento di due soli nodi non da alcuna garanzia di integrità), viceversa un valore più ridotto permette di mantenere la coordinazione anche in caso di caduta di un numero consistente di nodi. Quando si verificano le condizioni richieste per iniziare una fase di coordinamento il Proxy seleziona uno dei nodi del gruppo da coordinare come coordinatore, inviandogli un messaggio COORD_START e passando gli indirizzi di tutti i nodi del gruppo che dovrà coordinare. La scelta di quale nodo tra quelli attivi eleggere coordinatore in ciascuna occasione spetta all’applicazione, dato che può essere un fattore critico e possono quindi essere utilizzate politiche volte a bilanciare il carico dei nodi (ad esempio scegliere come coordinatore il nodo che sta servendo meno richieste, oppure sempre uno stesso nodo dotato di risorse specializzate per l’operazione). Ad intervalli regolari il Proxy controlla poi lo stato delle operazioni di coordinamento in corso inviando a ciascun coordinatore un messaggio COORD_STATUS; se il coordinatore non risponde, oppure risponde con un messaggio COORD_ERROR, il Proxy considera il coordinamento fallito e ne inizia uno nuovo sui nodi che in quel momento sono attivi. Se viceversa riceve in risposta COORD_WAIT, il coordinamento è ancora in corso e quindi non viene iniziato nessun nuovo coordinamento nel gruppo. Un messaggio di risposta COORD_SUCCESS significa invece che è stato raggiunto l’accordo sul contenuto corretto di ciascun file, e tutti i nodi del gruppo contengono copie identiche dello stesso insieme di file. Il sistema è quindi tollerante alla caduta del nodo coordinatore, che viene rilevata quando COORD_STATUS non ottiene risposta, e alla caduta di uno o più nodi partecipanti al coordinamento, indicata da un messaggio COORD_ERROR da parte del coordinatore. Nel caso di caduta del Proxy durante il coordinamento, il coordinatore continua ad eseguire correttamente, e solo al momento del suo riavvio risponde alla interrogazione sullo stato del coordinamento. Protocollo di coordinamento – il ruolo del coordinatore Un nodo che riceve il messaggio COORD_START dal Proxy esegue il coordinamento che consiste nei seguenti passi: 1. Richiesta della lista dei file e del contenuto dei file da ciascun partecipante al coordinamento. 2. Scelta, attraverso votazione, del contenuto corretto di ogni file. 3. Richiesta e ricezione di ciascun file del quale il coordinatore abbia una copia corrotta (cioè con un contenuto diverso da quello considerato valido) da uno dei nodi che ne possiede una copia integra. 4. Invio delle versioni valide dei file a ciascun nodo partecipante che abbia un contenuto diverso da quello stabilito. Solo se tutti questi passi vengono completati correttamente il coordinatore considera l’operazione completata con successo. Il primo passo prevede l’invio di un messaggio COORD_GET_LIST a ciascun partecipante; un servizio in background per le risposte dei messaggi di coordinamento si occupa di ricevere questo messaggio, recuperare la lista dei file memorizzati e di rispondere con COORD_LIST. La lista inviata contiene per ciascun file, oltre all’identificativo univoco, una stringa che ne riassume il contenuto (l’estrazione del riassunto da un file è una delle specifiche di livello applicativo; ad esempio potrebbe essere implementata con una funzione hash sicura). Se ciascun partecipante fornisce la sua lista il coordinamento continua; viceversa se almeno uno non risponde, il coordinamento fallisce non essendo disponibili tutte le informazioni necessarie per la votazione. Durante il secondo passo il coordinatore conta, per ogni diversa versione del contenuto riassunto di ciascun file, quanti partecipanti la posseggono eleggendo il più diffuso come copia integra. Se la copia locale è valida, il coordinatore passa alla quarta fase; viceversa se il contenuto locale del file differisce dalla versione più diffusa, richiede con un messaggio FILE_TX_REQUEST l’upload del file ad uno dei nodi che dispongono di una copia valida. Al termine del trasferimento, estrapolando dal file ricevuto la stringa riassuntiva e confrontandola con quella maggiormente votata, verifica se è possibile passare alla fase di propagazione. Infine, con un messaggio FILE_TX_REQUEST (in questo caso con un attributo che indica “upload”) richiede al nodo l’upload del file, che andrà a sovrascrivere un’eventuale copia già presente e gli trasmette anche la stringa riassuntiva. Al termine di questo trasferimento il coordinatore attende un messaggio di risposta FILE_TX_SUCCESS, per avere la garanzia che il file ricevuto dal partecipante ha un contenuto conforme alla stringa riassuntiva inviatagli. Protocollo di coordinamento – il partecipante passivo Ciascun nodo dispone di un servizio di trasferimento file in background che, secondo il protocollo di coordinamento, riceve le richieste di upload o download provenienti dal coordinatore. Questo servizio è in grado di soddisfare più richieste contemporanee, e garantisce che non vi siano interferenze nelle operazioni di scrittura. Inoltre può ricevere messaggi di tipo COORD_START (provenienti dal Proxy) e COORD_GET_LIST (provenienti dal coordinatore). E’ importante che ad ogni istante sia attivo al più un coordinatore per ogni gruppo, per evitare problemi di consistenza nel caso in cui le decisioni prese dai diversi coordinatori riguardo le versioni corrette dei file fossero in contraddizione. Questa situazione può verificarsi se il Proxy, una volta avviato un coordinatore, cade e, una volta riavviato, non sapendo che è già in funzione un coordinamento, elegge un nuovo coordinatore. Lo stesso può capitare anche nel caso di “falsa caduta” del nodo coordinatore, ovvero se l’interrogazione COORD_START non riceve risposta entro il tempo di timeout nonostante il coordinatore sia in funzione. Per questa ragione se un nodo coordinatore riceve COORD_GET_LIST (da un altro “aspirante” coordinatore) risponde con un messaggio di errore, in maniera da costringere questo a terminare con un fallimento. 5. L’interazione con i clienti Come già illustrato nella panoramica sull’architettura del sistema, l’interazione dei clienti con il sistema avviene in due momenti: Nel contattare il Proxy che fa da front-end del sistema, ricevendo le informazioni che permettono di contattare il nodo servitore scelto Nell’invocazione dell’operazione sul nodo servitore Le due comunicazioni avvengono senza alcun coordinamento tra Proxy e nodo scelto; questo permette di evitare un notevole overhead di comunicazione, che inciderebbe sui tempi di risposta agli occhi del cliente, ma, allo stesso tempo, richiede alcuni accorgimenti per garantire un servizio affidabile. Scelta del nodo servitore Il Proxy, una volta ricevuta una richiesta di upload o download, è in grado di selezionare il gruppo di replicazione corrispondente al file richiesto, a seconda delle politiche di partizionamento della capacità di memoria. All’interno del gruppo, però, la scelta dello specifico nodo servitore per le operazioni di download non è del tutto libera: come visto nel capitolo sul coordinamento, è infatti possibile che un file sia memorizzato solo sul nodo che ne ha gestito l’upload non essendo ancora stato propagato agli altri membri del gruppo. Questo significa che il Proxy deve sapere, per ogni upload eseguito in passato, quale nodo del gruppo ha ricevuto il file, e deve mantenere lo stato dei coordinamenti eseguiti su quel gruppo (per sapere quali file sono stati propagati a tutti i membri e quali invece sono memorizzati solo localmente al nodo che li ha ricevuti). Per permettere questo il Proxy marca ciascuna operazione di upload (quindi ciascun file ricevuto) con un timestamp, ovvero una stringa che codifica l’istante di tempo della ricezione della richiesta. Inoltre, anche ogni coordinamento comandato dal Proxy ha come parametro un timestamp, che viene passato al nodo coordinatore tramite COORD_START e successivamente restituito tramite il messaggio COORD_SUCCESS di risposta all’interrogazione del Proxy. Il coordinatore si occupa di eseguire il coordinamento dei soli file che abbiano un timestamp di upload che indichi un istante precedente a quello del timestamp di coordinamento. Il Proxy, alla ricezione di un messaggio COORD_SUCCESS indicante un certo timestamp, considera già propagati ai membri del gruppo tutti i file che hanno un timestamp di upload precedente a quello del coordinamento. Per potere smistare correttamente le richieste di download il Proxy deve solo memorizzare una lista dei file temporaneamente “non ancora propagati” e, per ciascuno, il nodo che lo ha memorizzato localmente; ad ogni coordinamento terminato con successo scarta da questa lista tutti i file con un timestamp di upload precedente a quello del coordinamento eseguito. Questo meccanismo non da l’assoluta certezza che i file considerati propagati siano effettivamente presenti su tutti i nodi del gruppo. Ad esempio, se un upload con un timestamp X viene effettivamente terminato dopo un coordinamento eseguito con timestamp Y con X < Y, allora questo file non verrà propagato agli altri membri del gruppo fino al successivo coordinamento. Del resto il sistema non garantisce il servizio di tutte le richieste provenienti dai clienti; questa ipotesi non è particolarmente stringente dato che nel tipico scenario applicativo di un sistema di File Hosting, il fallimento di una richiesta è un disservizio tollerabile. La semantica riguardo al servizio delle richieste si potrebbe pertanto definire “at most once”. Passaggio dei parametri di invocazione Al momento della redirezione del cliente al nodo servitore incaricato di eseguire la sua richiesta, il Proxy gli fornisce, oltre all’indirizzo che gli permetterà di mettersi in comunicazione con questo, anche i parametri di invocazione. Questi parametri contengono l’identificativo unico del file, un’indicazione sul tipo di trasferimento (download/upload), e, solo in caso di upload, il timestamp assegnato a quel file. La codifica di questa tupla sotto forma di stringa spetta al livello applicativo; ad esempio potrebbe essere richiesta una codifica che la renda opaca al cliente, oppure una qualche forma di autenticazione del Proxy che possa essere verificata dal nodo ricevente. 6. Utilizzo del supporto In questo capitolo vengono illustrate le interfacce attraverso cui il progettista di un sistema di File Hosting può specificare il comportamento, le politiche e i protocolli personalizzati in base alle esigenze applicative. Implementazione di un Proxy La classe Proxy rappresenta il generico Proxy; per definire una istanza di questa classe devono essere forniti, oltre ai parametri di configurazione (tra cui i tempi di timeout, la struttura dei gruppi di replicazione, gli indirizzi e le porte da utilizzare per le comunicazioni interne) i seguenti oggetti: Un oggetto di tipo FileHostingService che definisce la comunicazione con i clienti e la redirezione delle richieste verso i nodi servitori. Il metodo principale che deve essere implementato per questa classe astratta è FileRequestConnection acceptConnection() che deve ascoltare e ricevere una connessione da un cliente sulla quale verrà eseguita la comunicazione per ricevere la richiesta e reindirizzare il cliente. L’oggetto restituito (di tipo FileRequestConnection) deve fornire, a seconda del protocollo utilizzato per comunicare con il client un’implementazione ai metodi: FileOperation receiveRequest() //Legge e interpreta i parametri della richiesta void sendFileLink(Node selectedNode, String encodedRequest) //Invia un indirizzo per la redirezione e i parametri di invocazione void sendErrorNotification(Exception exception) //Notifica di un errore avvenuto sul proxy Oltre a questi il FileHostingService deve fornire implementazione ai metodi per la scelta del gruppo di replicazione associato ad un certo file, e la scelta del nodo di servizio tra quelli attivi (quest’ultimo metodo viene invocato solo nel caso in cui il file sia già stato propagato a tutto il gruppo). Un oggetto che implementi l’interfaccia FileNamer, che espone metodi per la scelta degli ID univoci dei file, per la lettura e il confronto di timestamp, e per la codifica/decodifica dei parametri di invocazione. Un CoordinationManager. Questa classe astratta richiede l’implementazione del metodo (invocato ogni volta che si verificano le condizioni per avviare un coordinamento) che sceglie, tra i nodi attivi di un gruppo, il coordinatore. Implementazione di un nodo di replicazione La costruzione di un GroupNode (che gestisce un nodo di replicazione) richiede, oltre ai parametri di configurazione del nodo: Un FileTransferService che, in maniera simile a FileHostingService apre una connessione con il cliente per servire le richieste. La connessione creata è in questo caso di tipo FileTransferConnection e deve fornire, una volta aperta, gli stream di input e di output per leggere o scrivere il file da trasferire, e i parametri di invocazione ricevuti (codificati dal Proxy). Un oggetto che implementi FileManager. Questa interfaccia definisce le modalità di memorizzazione locale dei file (anche questo dipende dalle esigenze applicative: potrebbe essere usato un database ad esempio); ha quindi metodi per l’apertura in lettura o in scrittura di file, per il salvataggio delle modifiche e per l’annullamento delle modifiche fatte. Inoltre espone i metodi per il calcolo della stringa riassuntiva del contenuto dei file (ad esempio tramite funzione hash), per ottenere l’elenco dei file memorizzati e i timestamp. Un oggetto di tipo FileNamer come quello usato dal Proxy (usato per decodificare i parametri di invocazione ricevuti). Applicazione di prova E’ stata sviluppata una applicazione di test che è stata utilizzata per provare il sistema in diverse possibili configurazioni e per il debugging. Questa applicazione fornisce un’implementazione molto semplificata alle interfacce sopra elencate; realizza la comunicazione tra i client e i nodi del sistema tramite socket TCP e realizza un bilanciamento del carico smistando in maniera omogenea i file sui gruppi di replicazione e le richieste sui membri di ciascun gruppo. La memorizzazione dei file è eseguita con una scrittura e lettura sul file system locale (il meccanismo di annullamento delle modifiche viene gestito usando dei file temporanei), le stringhe riassuntive sono calcolate con SHA, e i parametri di invocazione vengono passati ai clienti in chiaro. 7. Possibili sviluppi futuri Questo progetto, che nasce con l’idea di facilitare la costruzione di sistemi di File Hosting, ha messo in evidenza alcuni settori su cui si potrebbe lavorare per migliorare il supporto al progettista. Risaltano soprattutto i problemi cui questo sistema andrebbe incontro se usato in ambienti al limite delle capacità computazionali o di memoria. Per migliorarne il funzionamento si potrebbe pensare di introdurre una serie di meccanismi per la Quality of Service, a partire dai quali il progettista potrebbe realizzare delle politiche di gestione del sistema che mirino a differenziare la quantità di risorse stanziate per la gestione di ciascuna richiesta. In questo senso potrebbe tornare utile un sistema di monitoraggio della capacità residua su ciascun nodo, che permetta di inserire politiche di reazione o di azione preventiva allo scopo di evitare il riempimento della memoria. Scartando alcuni file (ad esempio quelli che non sono richiesti da molto tempo, oppure quelli meno importanti) in condizioni critiche, si potrebbe liberare dello spazio, ma si perderebbe la garanzia di persistenza. Un’altra dimensione della qualità di servizio è quella della gestione del traffico e del problema di come suddividere la banda disponibile tra le diverse operazioni di trasferimento in corso. Molti servizi di Web File Hosting, soprattutto quelli disponibili gratuitamente, prevedono code presso cui i clienti vengono messi in attesa del loro turno per eseguire il trsferimento; a volte si adottano politiche personalizzate di gestione delle code, che danno la precedenza a determinate richieste (ad esempio quelle provenienti da clienti paganti, oppure quelle per file di dimensioni ridotte). BIBLIOGRAFIA Lucidi del corso di Reti di Calcolatori L-S del Prof. A.Corradi A.S. Tanenbaum, M.van Steen, Distributed Systems: Principles and Paradigms, Prentice-Hall 2002.