Università degli Studi di Bari Laurea Magistrale in Informatica Esame di Sistemi Distribuiti Implementazione e simulazione di un algoritmo epidemico Prof. S. Pizzutilo Studenti: Annamaria Cozzolongo Fabio Pomes Michele Tarantini Anno Accademico 2013/2014 1 Introduzione Un elemento importante della comunicazione nei sistemi distribuiti è il supporto per l'invio di dati a molteplici destinatari, conosciuto anche come comunicazione multicast. La comunicazione multicast può essere realizzata sia creando communication path espliciti sia affidandosi a tecniche applicative che simulano i comportamenti epidemici. Esistono due approcci fondamentali per l'implementazione del multicast applicativo: il primo utilizza l’organizzazione dei nodi “ad albero”, il che significa che c'è un unico percorso tra una coppia di nodi; l’altro, invece, vede i nodi organizzati in una rete a maglia in cui ogni nodo ha molti altri vicini, creando cosi molti percorsi diversi per ogni coppia di nodi. La differenza principale tra i due approcci è che, di solito, il secondo si presenta più solido. Infatti, se cadesse una connessione (dovuta ad esempio alla disfunzione di un nodo), ci sarebbe ancora la possibilità di distribuire le informazioni senza la necessità di riorganizzare immediatamente l'intera rete. Algoritmi epidemici Si parla di algoritmi epidemici in virtù della somiglianza con i processi di diffusione di una malattia infettiva: proprio grazie a queste analogie è possibile sfruttare i risultati ottenuti nelle ricerche mediche. L’algoritmo epidemico consente, infatti, di poter determinare la politica di contagio in quanto tali tecniche di comunicazione garantiscono la propagazione di tutte le operazioni a tutti i nodi, anche quando la topologia della rete è sconosciuta e variabile. Questi algoritmi offrono una maggiore scalabilità del sistema in presenza di un grande numero di punti proprio perché è molto minore il livello di sincronizzazione. L'obiettivo principale di questi protocolli epidemici è la rapida propagazione delle informazioni in un grande insieme di nodi usando solo informazioni locali; in altre parole, non esiste un componente centrale che coordina la distribuzione delle informazioni. Volendo usare la terminologia delle epidemie, un nodo che fa parte di un sistema distribuito è detto “infetto” se possiede dati che si desidera diffondere su altri nodi; un nodo che non ha ancora visto questi dati si dice “suscettibile”; infine un nodo aggiornato che non vuole o non può più diffondere i propri dati è detto “rimosso”. Più precisamente, i protocolli di gossip godono delle seguenti proprietà: 2 • scalabilità: le loro performance non degradano rapidamente al crescere del numero dei processi. Generalmente ogni processo invia un numero di messaggi indipendente dal numero di processi e predeterminato. In queste condizioni, se la stabilità della rete fisica non degrada con il numero dei processi, il protocollo di gossip è scalabile. • adattabilità: non è difficile aggiungere o rimuovere processi nella rete. Il problema risiede nella configurazione dei parametri utilizzati dai protocolli che spesso sono configurati in modo statico in base alle dimensioni previste della rete. Un aumento imprevisto e consistente del numero di processi di un gruppo può portare, in questi casi, ad una degradazione delle prestazioni. Modello di diffusione: Gossiping o "Diffusione del rumore" In questo modello di diffusione, il nodo P nel momento in cui viene aggiornato con un determinato dato prova a contattare un casuale nodo Q e prova ad inviargli l'aggiornamento. Tuttavia, è possibile che Q sia già stato aggiornato da un altro nodo e in questo caso P potrà perdere l'interesse a diffondere ulteriormente l'aggiornamento entrando a far parte dei nodi “rimossi”. Anche qui risulta evidente l'analogia con la vita reale, in quanto il nodo sembra simulare il comportamento umano in caso di “pettegolezzo”, raggiungendo ottime prestazioni soprattutto nella velocità di diffusione. Nonostante tale tecnica sia molto efficiente nella propagazione del dato, va detto però che la diffusione non garantisce che tutti i nodi siano raggiunti dall'aggiornamento. In tale algoritmo, i nodi sono all'inizio ignoranti rispetto all’informazione, ma una volta ricevuta, questa è considerata “HOT” e perciò da condividere; viene scelto, quindi, periodicamente un altro nodo a caso e si verifica che anche l'altro ne sia a conoscenza. Quando un host ha contattato troppi altri nodi che già conoscevano l'aggiornamento, l’host ne cambia la connotazione HOT, mantenendolo senza più cercare di propagarlo. Questo meccanismo viene utilizzato ogni qual volta che un nodo ottiene un nuovo dato o da un pari o da un utente: tale dato può essere, infatti, lanciato frequentemente non necessitando di tante risorse. Nella nostra implementazione, un nodo che tenta di diffondere l’informazione ad un altro nodo, già in possesso dell’informazione, viene rimosso. 3 Simulazione dell’algoritmo Per il nostro caso si è voluto simulare la diffusione dell’informazione attraverso una rete composta da 100 nodi (come si può vedere in figura). Creazione matrice della rete (diversa ad ogni lancio dell’algoritmo) : m_punti=zeros(100,5); %%popolamento %1 colonna= id nodo %2 colonna= coordinata x %3 colonna= coordinata y %4 colonna= infetto %5 colonna= rimosso for k=1:Rete m_punti(k,1)=k; % 1 colonna m_punti(k,2)=M(k); % 2 colonna m_punti(k,3)=M1(k); % 3 colonna end 4 Dichiariamo una nuova matrice (100 righe x 100 colonne) per salvare le distanze spaziali dei nodi: RankDistanze100 = zeros(100,100); Distanza100 = zeros(100,100); for i=1:100 [RankDistanze100(i,:),Distanza100(i,:)] = knnsearch(m_punti(:,2:3),m_punti(i,2:3),'k',100); end Ultimiamo la matrice aggiungendo 99 colonne (100 colonne-1) che rappresentano la precedente matrice privata della prima posizione (posizione occupata rispettivamente dal nodo dal quale si calcolano le distanze): %ultimiamo la matrice %1 colonna = id nodo %2 colonna = coordinata x %3 colonna = coordinata y %4 colonna = infetto %5 colonna = rimosso %6 a 104 colonne = rank di distanza dal 2° al 100° ( poiche' il 1° e' il nodo stesso ) matriceRete = [m_punti,RankDistanze100(:,2:100)]; disp(matriceRete); Identifichiamo il paziente 0 attraverso una funzione casuale che sceglie un nodo tra i 100 presenti nella rete, dopodiché settiamo il flag (booleano 0/1) nella matrice del paziente 0 a infetto (val = 1) : %scelta casuale del paziente zero disp('Paziente0 ='); paziente0=randi(100,1); disp(paziente0); %set del flag nella colonna infetto matriceRete(paziente0,4)=1; Avviamo l'algoritmo e settiamo il tempo massimo a 2000 cicli (tempo nel quale l'epidemia e' attiva). A ogni ciclo un solo nodo infetto può contagiare un suo vicino: in questo caso è quindi chiamata una seconda funzione denominata "EpidemicSpread", che riceve in input la matrice della rete e il nodo infettante nell'attuale ciclo; questa funzione restituisce come output la matrice aggiornata e ad ogni ciclo salva le statistiche sui nodi infetti e rimossi: while ( contatore ~= tempoMax ) i=randi(100,1); if ( (matriceRete(i,4)==1)&&(matriceRete(i,5)~=1) ) 5 nodo=i; [ matriceRete] = EpidemicSpread(nodo,matriceRete); %pause(2); end switch contatore case fix(tempoMax/3) infetti=sum(matriceRete, 1); IPrimoTerzo=infetti(4); RPrimoTerzo=infetti(5); case fix(tempoMax/3)*2 infetti=sum(matriceRete, 1); ISecondoTerzo=infetti(4); RSecondoTerzo=infetti(5); case tempoMax-1 infetti=sum(matriceRete, 1); ITerzoTerzo=infetti(4); RTerzoTerzo=infetti(5); end contatore = contatore+1; end Nel dettaglio, la funzione "EpidemicSpread” si comporta in questo modo: il primo controllo serve a verificare che non si vada oltre i limiti della matrice e che non sia stata effettuata nessuna infezione/rimozione nella corrente chiamata di funzione (quest'ultima condizione viene verificata attraverso la variabile flagEseguito). Il secondo controllo (primo if) verifica che il nodo infettante non tenti di infettare nuovamente un nodo che ha già preso in considerazione nel rank, cioè che ha già infettato; quindi, in caso positivo, si effettua un ulteriore controllo per stabilire se il nodo preso in considerazione sia infetto o rimosso. Se tutte le precedenti condizioni danno esito positivo, il nodo corrente viene infettato dal nodo dato in input alla funzione “EpidemicSpread”: a questo punto viene cancellato dal rank del nodo infettato l’identificativo del nodo infettante per evitare che nei successivi cicli si prendano in considerazione coppie di nodi vicini tra loro. while (i~=105) && (flagEseguito==0) %identifico il nodo piu' vicino nel rank if(matriceRete(nodo,i)~=0) %controllo che il nodo da infettare non sia infetto o rimosso if (matriceRete(matriceRete(nodo,i),4)~=1) && (matriceRete(matriceRete(nodo,i),5)~=1) % cambio infettato matriceRete(matriceRete(nodo,i),4)=1; flagEseguito=1; X = fprintf('(msg) Il nodo[%d] infetta il nodo[%d] ! \n', matriceRete(nodo,1),matriceRete(nodo,i)); infettatoIdNodo = matriceRete(nodo,i); k=1; for k=6:104 if(matriceRete(infettatoIdNodo,k)==nodo) matriceRete(matriceRete(nodo,i),k)=0; end k=k+1; 6 end matriceRete(nodo,i)=0; Se le condizioni di non infezione e non rimozione danno esito negativo si ricade nel seguente caso : rimozione del nodo infettante con annesso messaggio di output. %altrimenti viene rimosso il nodo infettante else X = fprintf('(msg) Il nodo[%d] tenta di infettare il nodo[%d](precedentemente infettato), quindi il nodo[%d] viene rimosso! \n', matriceRete(nodo,1), matriceRete(nodo,i), matriceRete(nodo,1)); matriceRete(nodo,5)=1; %assegna 0 ai nodi rimossi for j=1:100 for k=6:104 if( matriceRete(j,k)== matriceRete(nodo,1)) matriceRete(j,k)=0; end end end flagEseguito=1; end end i=i+1; end end Terminata l'esecuzione della funzione "EpidemicSpread" la funzione chiamante (principale) continua con i suoi cicli fino al termine del tempo dato in input (come detto nel nostro caso 2000 cicli). Disp(‘Contatore = ‘); disp(contatore); %Stampa a video delle percentuali di rimossi e infettati X = fprintf(‘(msg) Infetti(1° Sezione) = %d Rimossi(1° Sezione)= %d \n(msg) Infetti(2° Sezione) = %d Rimossi(2° Sezione)= %d \n(msg) Infetti(3° Sezione) = %d Rimossi(3° Sezione)= %d \n’, IprimoTerzo,RprimoTerzo,IsecondoTerzo,RsecondoTerzo,IterzoTerzo,RterzoTerzo); out = [IprimoTerzo,IsecondoTerzo,IterzoTerzo,RprimoTerzo,RsecondoTerzo,RterzoTerzo]; end Insieme alle due funzioni precedentemente descritte, ve ne è una terza chiamata “Run100”, la quale richiama la funzione principale "RandomRandomNodes100" e salva gli output su un foglio elettronico nel quale i dati vengono elaborati per ricavare: 7 Media Infetti (nelle 3 trance che vanno a formare il tempo massimo) Media Rimossi (nelle 3 trance che vanno a formare il tempo massimo) Picchi (min/MAX) di infezione (nelle 3 trance che vanno a formare il tempo massimo) Picchi (min/MAX) di rimozione (nelle 3 trance che vanno a formare il tempo massimo) function [ output ] = Run100( ) output= zeros(100,6); for i=1:100 output(i,:)=RandomRandomNodes100; end xlswrite('OutputEpidemici.xls', output, 'OutputFabio', 'A2'); end Ecco un esempio: Una seconda versione del sistema è stata successivamente creata per simulare graficamente la diffusione epidemica. 8 Guida alla simulazione attraverso l'ambiente MATLAB Aprendo l'ambiente andremo in primo luogo a caricare il file RandomRandomNodes100.m presente nella directory “Algoritmi Epidemici ParteGrafica” il quale oltre a simulare l’algoritmo precedentemente descritto, produrrà un output grafico grazie al quale sarà possibile seguire ad ogni passo la diffusione dell’informazione nella rete composta dai 100 nodi. Per rendere visibile l’avanzamento dell’epidemia si è deciso di interrompere per una frazione di secondo l’esecuzione del programma ogni qual volta si verifica un’infezione. I nodi in verde rappresentano nodi non ancora raggiunti dall’informazione (sani); i nodi gialli rappresentano i nodi infettati e infine i nodi rossi rappresentano i nodi rimossi. 9 10 Sarà inoltre possibile consultare tutti i passi dell’epidemia grazie alla creazione di un output visibile in MATLAB: Paziente0 = 75 (msg) Il nodo[75] infetta il nodo[77] ! (msg) Il nodo[77] infetta il nodo[88] ! (msg) Il nodo[88] infetta il nodo[16] ! (msg) Il nodo[16] infetta il nodo[87] ! (msg) Il nodo[88] tenta di infettare il nodo[87](precedentemente infettato), quindi il nodo[88] viene rimosso! (msg) Il nodo[87] tenta di infettare il nodo[75](precedentemente infettato), quindi il nodo[87] viene rimosso! (msg) Il nodo[16] infetta il nodo[100] ! (msg) Il nodo[16] tenta di infettare il nodo[77](precedentemente infettato), quindi il nodo[16] viene rimosso! (msg) Il nodo[77] infetta il nodo[81] ! (msg) Il nodo[81] infetta il nodo[94] ! : : : Contatore = 2000 (msg) Infetti(1a Sezione) = 15 Rimossi(1a Sezione)= 10 (msg) Infetti(2a Sezione) = 40 Rimossi(2a Sezione)= 33 (msg) Infetti(3a Sezione) = 85 Rimossi(3a Sezione)= 74 11 Riferimenti -“ Simple, Fast and Deterministic Gossip and Rumor Spreading “ - B.Haeupler -“ Progetto di sistemi distribuiti multiagente – Analisi di algoritmi epidemici ” – Nunzio Gianfelice -“ Randomized Gossip Algorithms “ - S. Boyd, A.Ghosh, B.Prabhakar, and D.Shah -A. Tanenbaum e M. van Steen, Sistemi Distribuiti ed. Pearson-Prentice Hall, seconda edizione 2007. 12