Conclusioni

 

Sono state fatte delle prove sul servizio in questo modo: un cliente genera un numero finito di thread in parallelo, ognuno dei quali fa una richiesta di un servizio al sistema replicato tramite uno stesso UA (il cliente è locale all'UA). Lo stesso cliente crea prima e dopo l'esecuzione dei thread un oggetto Date (java.util), e calcola il tempo "di esecuzione" facendo la differenza (in millisecondi).

Occorre ricordare che queste prove non costituiscono un risultato generale per vedere le prestazioni, perché i risultati possono variare di molto in base a parametri come per esempio il numero di utenti sulla workstation , il traffico di rete sulla LAN, ecc.

 

    Prove

Il cliente di prova è realizzato nel file Clienteparallelo.java. Per confrontare i risultati sono stati fatti eseguire tre servizi per ogni replica presente, su un anello composto da quattro, tre, due e una replica (i servizi richiesti sono solo quelli per cui non c'è bisogno del token). Inoltre il cliente, per fornire valori più "realistici" ripete questa sequenza di 12 servizi per trenta volte e alla fine stampa il valore medio. Poi, per vedere se ci fosse una sequenza particolare di creazione dei "thread di richiesta", il cliente è stato dotato della possibilità di eseguire lo start() dei thread ad intervalli di tempo specifici. Se non si inseriscono ritardi, le richieste hanno il "sopravvento" sulla messa in esecuzione per cui il meccanismo di load sharing non fa il suo dovere (le richieste vengono accolte tutte o quasi tutte da una sola replica). Il valore di ritardo da inserire per cui si è riscontrata una buona distribuzione dei servizi (è un riscontro molto "soggettivo", ma è dovuto al fatto che i tempi di esecuzione sono i minori) si aggira tra i 10 e i 30 millisecondi.

Il server, allo scopo di poter eseguire prove di questo tipo, è stato dotato delle possibilità di inserire un ritardo nel tempo di esecuzione dei servizi, e i ritardi inseriti variano da 0 a 500 millisecondi.

 

 

Il tempo medio di un servizio è stato calcolato eseguendo le richieste tutte localmente (Cliente, UA e Replica sono locali). La differenza che è pressoché costante fra ritardo inserito e tempo "rilevato" è imputabile al tempo impiegato dalla JVM per creare i thread "coinvolti" nell'esecuzione del singolo servizio (più o meno 50 millisecondi).

0 50 100 150 200 250 300 350 400 450 500
Tempo medio di un servizio 56.66667 98.33333 148.3333 197.3333 248.6667 295.3333 337 393 438 491.3333 531.3333

 

 

 

Il tempo di esecuzione è relativo all'esecuzione di tre servizi per ogni replica presente nell'anello (si è pensato ad una "densità di servizi per workstation" costante, visto che le workstation usate sono tutte uguali).

0 50 100 150 200 250 300 350 400 450 500
4 repliche 649 789 804 1135 1278 1377 1497 1805 1809 2028 1895
3 repliche 530 627 750 975 1096 1181 1447 1509 1618 1729 2114
2 repliche 455 544 744 907 1013 1083 1248 1413 1433 1676 1779
1 replica 170 295 445 592 746 886 1011 1179 1314 1474 1594

 

 

L'overhead è stato calcolato facendo riferimento al tempo medio di un servizio su un anello con una replica, quindi non è un overhead "canonico", per il quale si dovrebbe calcolare la durata del servizio realizzandolo come un unico thread nella JVM. La formula usata è:

Overhead%=((Tempo di esecuzione - Tempo di un servizio)*100)/(Tempo di un servizio)

NOTA: ho provato a realizzare un thread che esegue un servizio in questo modo, ed è risultato che il tempo impiegato è di 40 millisecondi in più del ritardo introdotto, invece dei 50 risultanti usando la replica.

0 50 100 150 200 250 300 350 400 450 500
4 repliche 281.7647 167.4576 80.67416 91.72297 71.31367 55.41761 48.07122 53.09584 37.67123 37.5848 18.88331
3 repliche 211.7647 112.5424 68.53933 64.69595 46.91689 33.29571 43.12562 27.98982 23.13546 17.29986 32.62233
2 repliche 167.6471 84.40678 67.19101 53.20946 35.79088 22.23476 23.44214 19.84733 9.056317 13.70421 11.60602

 

 

    Problemi affrontati durante lo svolgimento del progetto

Il primo "ostacolo" incontrato è stato dover imparare il linguaggio Java da zero, poi riuscire a realizzare i meccanismi di sincronizzazione che servono:  realizzare ricezioni con timeout (tutte realizzate tramite thread perché occorre gestire una eccezione), dover distinguere se un thread si sblocca in seguito al timeout o in seguito ad una notifica, realizzare meccanismi di sincronizzazione diversi dentro un unico oggetto da condividere.

Un altro ostacolo è stato riuscire a realizzare il protocollo di recovery e di gestione dell'anello (che interagiscono molto tra loro), e riuscire a trovare una politica di priorità tra i vari thread e sottothread generati dai vari gestori.

Posso affermare che è stato "vitale" per me avere un collegamento con il sito della Sun dedicato a Java (il Tutorial e il Forum) dove ho trovato spiegazioni, problemi risolti e non, che riguardano la gestione e la sincronizzazione dei thread, anche se non sono riuscito a trovare spiegazioni esaurienti o esempi sul funzionamento della wait con timeout (cfr. java.lang.Object.wait()). Ho dovuto fare tante prove per capire come funzione e come usarla.

 

 


<< Previous page