PROGETTO DI RETI DI CALCOLATORI

 

Marco Manservigi

 


 

INDICE:

1) Introduzione

2) Descrizione del progetto

2.1) Client

2.2) Server

2.3) Server Bancario

3) Uso del progetto

3.1) Client

3.2) Server

3.3) Server Bancario

4) Prova del progetto in laboratorio

4.1) Prestazioni


 

1) INTRODUZIONE

Si vuole realizzare un sistema di prenotazione tramite Java.

Dal lato client viene fornito l’elenco dei giorni disponibili e l’utente deve specificare i giorni di inizio e fine prenotazione, il nome ed un codice bancario. Viene poi fornita risposta affermativa o negativa.

Per avere affidabilità del server si utilizza la replicazione: sono presenti due programmi server su due nodi diversi che si devono coordinare (per tenere aggiornata la tabella delle prenotazioni). Ciascun server, ricevuta la richiesta da un client si deve accordare con l’altro server per effettuare la prenotazione e successivamente interrogare un altro server di una banca. Solo dopo il successo di quest’ultima operazione si da risposta affermativa al client.

Il client conosce entrambi i server di prenotazione e sceglie in modo casuale a quale effettuare la richiesta (per suddividere meglio il traffico sui due server).

Le ipotesi fatte sono:

  1. Ipotesi di guasto singolo per i server di prenotazione, cioè nel caso in cui uno dei due cada l’altro funziona correttamente finchè non viene ripristinato il primo server,
  2. Ipotesi di affidabilità del server bancario, cioè si assume che tale nodo non cada mai,
  3. Ipotesi di traffico delle richieste non elevato, in modo che non ci sia congestione dei nodi e che sia conveniente che ogni richiesta ricevuta venga comunicata singolarmente all’altro server,
  4. Si ipotizza che solo raramente una richiesta venga rifiutata perché annullata dal server della banca.

 

2) DESCRIZIONE DEL PROGETTO

 

2.1) CLIENT

Il client conosce entrambi i server e si rivolge ad uno di questi a caso, se però il server interpellato non risponde si rivolge all’altro.

Se il server risponde, il client riceve e visualizza la tabella delle prenotazioni. Per semplicità si possono prenotare solo 7 giorni (numerati da 0 a 6) e c’è un solo posto disponibile al giorno. Nei giorni prenotati viene visualizzato a fianco il nome di chi lo ha prenotato (che può essere seguito da "(non confermato)" nel caso in cui non si ha ancora avuto la conferma dalla banca). A questo punto l’utente inserisce i giorni di inizio e fine soggiorno, il nome ed un codice bancario. Se tutto funziona senza errori si riceve la risposta affermativa o negativa.

Nel caso in cui il client cada dopo avere inviato la richiesta ma prima di avere ricevuto la risposta: la prenotazione viene comunque effettuata (se possibile), l’utente sa di non avere ricevuto risposta e quando si collega ad un server controlla nella tabella se la prenotazione è avvenuta. Se invece è il server a cui ci si è rivolti a cadere durante una richiesta: il client si rivolge automaticamente all’altro e visualizza la tabella per vedere se la prenotazione è avvenuta. Quando l’utente vede sulla tabella il proprio nome in corrispondenza dei giorni in cui voleva prenotare, l’operazione ha avuto successo e può annullare la ripetizione della richiesta. Se però il nome è seguito da "(non confermato)" significa che la banca non ha ancora dato la risposta, in questo caso si deve annullare e riprovare dopo un po’ di tempo. Se invece nella tabella non c’è il nome si continua con la attuale richiesta inserendo i dati per ripetere la prenotazione.

 

2.2) SERVER

Ogni server apre due ServerSocket:

  1. una per accettare richieste da un client,
  2. una per accettare richieste dall’altro server.

All’avvio del programma parte una fase di inizializzazione che consiste nel verificare se l’altro server è già attivo:

Terminata l’inizializzazione vengono aperte le ServerSocket a e b e si rimane in attesa di richieste (partono due thread che fanno le rispettive accept. Per ogni richiesta che arriva viene fatto partire un thread corrispondente: gestisceRichiestaClient e gestisceRichiestaServer.

La tabella delle prenotazioni è contenuta nella classe Tabella, che attraverso il costrutto synchronized sequenzializza le operazioni di modifica della tabella stessa. Quindi se più thread contemporaneamente devono accedere alla tabella ne è garantita la mutua esclusione.

Le richieste che provengono dall’altro server possono essere di due tipi:

Ai due server è assegnata una priorità (che è fissa): uno è master e l’altro è slave. La differenza sta nel come vengono gestite le richieste dei client ed è stata introdotta per gestire il caso particolare in cui due richieste di prenotazione, incompatibili tra loro ma singolarmente accettabili, vengano gestite contemporaneamente ciascuna da uno dei due server.

La richiesta che il master manda allo slave è in realtà un "ordine": il master modifica prima localmente la tabella (se la richiesta viene accettata localmente) e poi impone la modifica allo slave.

La richiesta che lo slave manda al master può invece essere rifiutata: lo slave controlla localmente se la richiesta può essere accettata ed invia la richiesta al master, solo se questa è stata accettata lo slave aggiorna la propria tabella.

Notare che il caso in cui la richiesta inviata dal master venga rifiutata dallo slave può capitare solo per incongruenza delle tabelle dei due server. Questa situazione di errore non è tollerata e compare un messaggio di errore che consiglia di arrestare il sistema.

In entrambi i casi, se un server manda una richiesta all’altro e capisce che l’altro server è caduto, prosegue da solo e non manda più richieste all’altro finchè non riceve da questo la richiesta Start che indica che è stato ripristinato. Notare che se invece riceve prima Change significa che l’altro server era attivo ma si era interrotta la comunicazione, in questo caso ciascuno dei due server può avere accettato richieste singolarmente e le due tabelle possono essere differenti. Anche questa situazione di errore non è tollerata e provoca la comparsa di un messaggio d’errore.

Vediamo cosa succede nei vari casi in cui uno dei due server può cadere (facendo l’ipotesi 1) di guasto singolo):

Alla ripartenza il server riprende con la procedura di inizializzazione. Si suppone che durante l’inizializzazione non si possano verificare guasti.

 

2.3) SERVER BANCARIO

Dopo che un server ha l’ok dell’altro e quindi dopo che sono state aggiornate entrambe le tabelle, manda una richiesta al server bancario (viene fatto dopo per l’ipotesi 4: solo raramente la banca rifiuta una richiesta e quindi in tale caso si accetta il costo di annullare l’operazione nelle tabelle dei due server).

La banca controlla nella propria tabella se l’operazione si può effettuare e scala l’importo dal conto. In caso di risposta affermativa al server, la prenotazione è terminata e viene data conferma al client. Invece in caso di risposta negativa il server annulla la richiesta localmente ed invia all’atro server una richiesta di tipo Undo. In particolare:

cioè in pratica si ribalta l’ordine che c’è nella prenotazione (per avere sempre la tabella del master "più restrittiva" di quella dello slave). Se non si facesse così potrebbe succedere che in un certo istante il master abbia, per un certo giorno, un posto libero mentre per lo slave quel posto risulta occupato, quindi potenzialmente una richiesta accettata dal master può essere rifiutata dallo slave. Questo viene riconosciuto come incongruenza tra le tabelle dei due server e quindi non deve accadere.

Facciamo l’ipotesi che le richieste rifiutate dalla banca siano poche, cioè che sia difficile che chi prenota non sappia di non avere abbastanza soldi. Può capitare che una richiesta che verrà poi rifiutata dalla banca, occupi temporaneamente dei posti che facciano fallire altre prenotazioni. Questo può essere tollerato per l’ipotesi precedente.

Il server bancario avrà una ServerSocket su cui accetterà le richieste ed ogni accesso alla tabella avverrà in modo esclusivo.

Se cade il server che ha la richiesta dal client:

In questi casi per il client avviene quanto già descritto.

 

3) USO DEL PROGETTO

Prima di iniziare, in ogni programma si devono specificare i parametri per la comunicazione. Questo consente di configurare velocemente il sistema per testarlo su diverse macchine.

 

3.1) CLIENT

Si può usare quando sono già presenti e attivi gli altri server. Si può scegliere a quale dei 2 server connettersi, in generale usare l’opzione random.

Con il pulsante OK si invia la richiesta, verrà visualizzata la tabella delle prenotazioni. Premendo Cancel si annulla l’operazione, altrimenti inserire i dati (inizio e fine prenotazione, nome e codice bancario) e ripremere OK. Verrà data conferma o meno.

 

3.2) SERVER

Si devono usare 2 esecuzioni di questo programma su due macchine diverse, uno deve essere settato come slave e l’altro come master.

Occorre specificare 2 porte locali per la ricezione delle richieste: una per quelle dei client e una per quelle dell’altro server.

I 2 server devono partire uno alla volta: il primo si accorgerà che l’altro non è presente, il secondo riconoscerà la presenza dell’altro.

 

3.3) SERVER BANCARIO

Basta inserire la porta locale per la ricezione delle richieste e premere OK per l’inizializzazione locale.

 

4) PROVA DEL PROGETTO IN LABORATORIO (LAB2)

Il progetto è stato provato in laboratorio senza che siano stati riscontrati malfunzionamenti.

Per testare correttamente i vari casi di concorrenza sono stati introdotti temporaneamente dei ritardi per consentire di simulare la caduta di un nodo in particolari punti del programma.

 

4.1) PRESTAZIONI

Sia il server che il server bancario risultano un po' lenti nell'inizializzazione (circa 1 minuto), questo sembra dovuto al fatto che la creazione di una ServerSocket risulta particolarmente lenta sui computer del lab2.

A regime le prestazioni del sistema sono buone:

  • caso migliore (funzionamento normale): la risposta al client arriva quasi istantaneamente
  • caso di peggiore ritardo (se il client si rivolge prima ad un server caduto, poi all'altro che non si era ancora accorto di essere rimasto l'unico server): al massimo 1 o 2 secondi
  • Nel caso di guasto di un server che stava gestendo la richesta che era già stata comunicata all'altro server, il client si rivolge all'altro. In tutte le prove effettuate in cui la prenotazione era possibile il client ha ottenuto la tabella con la dicitura (non confermato) e cioè si collega con l'altro server prima che questo abbia una conferma dalla banca.

    La presenza alcuni client che effettuano richieste contemporanee non sembra rallentare sensibilmente il sistema, risulta però difficile effettuare volutamente più richieste contemporanee data la velocità del servizio.