Slides del seminario P2P (15 dicembre 2005)

Peer-to-Peer
Un approccio pratico
Topologie, protocolli, sicurezza
Orlando Selenu
Partiamo dalle origini
“Il problema fondamentale della
comunicazione è quello di riprodurre in un
punto, esattamente o meno, un messaggio
proveniente da un altro punto.“
Claude Elwood Shannon
Un problema vecchio quanto
l’informatica
Turing, Shannon, e Dijkstra, i padri dell’informatica,
hanno sempre cercato nuove risposte al bisogno
crescente di comunicazione.
Abbiamo la maggior parte degli strumenti informatici
che ci servono per realizzare una rete paritaria sin
dagli anni ’70, ma solo negli ultimi anni si è
registrata un’effettiva e diffusa tendenza
all’aggregazione delle risorse (Napster ha avuto un
picco di traffico di 7 TB in un giorno).
Tendenza classica
Storicamente si registra una tendenza
all'aggregazione delle potenze di calcolo
I motivi sono da ricercarsi essenzialmente
nella riduzione dei costi
E’ passata l’era dei mainframe, o del glorioso
CEP
E poi? Cosa sarà oltre Internet? (interrogativo
sempre aperto)
Un approccio pratico al
problema
Perché?
un approccio pratico per una mia personale
visione dell'informatica
un'analisi ergonomica dell'informatica
Ovvero:
Quale impatto nella società può avere una
scoperta/invenzione informatica?
La moglie di Nobel
Quanto approfondire il
discorso
La resistenza di una catena è data dall'anello
più debole
Pertanto:
E’ necessario capire tutti i passaggi di un
applicazione o tecnologia (P2P in questo
caso) per comprendere i punti deboli del
sistema
Un po’ di terminologia
Peer (o Nodo) = qualcuno o qualcosa che è
allo stesso livello
Da qui:
Rete paritaria = rete formata da calcolatori
gerarchicamente uguali
Lo strato fisico
Per una trasmissione da un nodo a un altro
nodo ho bisogno di:
un'infrastruttura sottostante (toh! Internet!)
[metà anni '60, quindi precedente a Metcalfe]
una lingua comune, un protocollo, per
scambiare informazioni [sempre dalla fine
degli anni '60 in poi i primi sviluppi]
Le tipologie di P2P (1/2)
Prima ancora di interrogarsi sui dettagli, è
intuitivo pensare che esistano due grandi
macroaree:
Distribuzione di potenza di calcolo (cpu)
Distribuzione di spazio (dati)
(esisterebbe una terza via, il caching, ma la
comprendo nella distribuzione di dati)
Le tipologie di P2P (2/2)
A dirla tutta esiste anche un’altra distinzione tra le reti
paritarie:
Reti strutturate e non strutturate (reti che hanno un
server centrale, o meno)
Un primo problema, comune ad ogni rete:
Indicizzazione, hashing (impronta digitale del file)
Algoritmi usati solitamente [md5, sha-1, merkle’s
tree]
Comprimere una quantità di dati n in uno spazio
arbitrario n‘ (limiti ragionevoli dell’hashing)
Il P2P più semplice possibile
Due nodi
Ogni nodo è alternativamente client e server
Almeno uno dei due deve ottenere dei dati
dall’altro nodo [interrogazione, ack, replica]
Nessuna policy di saturazione di banda
(flooding) [“vince il più forte”]
Per fortuna non è tutto qui
Pertanto:
Il primo problema nell’utilizzo di un sistema
peer-to-peer è localizzare in modo efficiente
il nodo che mantiene l’informazione o la
risorsa che si sta cercando.
Il secondo problema è bilanciare tutto il carico.
Bene.. E adesso?
E adesso viene il bello!
Le 4 fasi di una rete P2P
Boot (è un limite)
Lookup (vero nodo cruciale)
Join (dipendente da anonimità e sicurezza)
Leave (non sempre presente)
Boot
Si tratta di ottenere un elenco, perlomeno parziale,
degli altri nodi della rete
Non è detto che esista, ad esempio si potrebbe fare un
ip scanning, sperando di trovare un altro nodo, con
lo stesso protocollo.
(un tentativo molto poco ragionevole)
Praticamente tutti i protocolli hanno la fase di boot
implementata come un elenco degli ultimi
nodi/server attivi
Lookup
Si tratta di cercare il gestore di un dato sulla rete
Lookup centralizzato (Napster)
Flooded queries (Gnutella)
Architettura ibrida: più server centrali risolvono le ricerche
Peer to Peer puro non strutturato: Multicast della richiesta:
i vicini inviano ricorsivamente la richiesta ai loro vicini.
Routed Queries
Architettura pura strutturata: Ogni peer attua politiche di
routing per instradare la richiesta
Join
Per ora non ce ne occupiamo, ogni rete è
estremamente singolare
Leave
Non è banale, perché è bene che i protocolli
siano tolleranti verso i nodi che si scollegano
inaspettatamente
Le buone topologie, infatti, devono bilanciarsi
automaticamente
Richieste di una buona rete (1)
Il lavoro richiesto a un determinato nodo nel sistema
non deve crescere troppo in funzione del numero di
nodi nel sistema
La scalabilità di un protocollo dipende:
dalla topologia della rete
dall’algoritmo di routing
Obiettivi:
Minimizzare il numero di messaggi necessari per fare
lookup (minimizzare il flooding)
Minimizzare, per ogni nodo, le informazioni relative agli altri
nodi (minimizzare la tabella di routing)
Richieste di una buona rete (2)
“Conoscere i luoghi, vicini o lontani non vale
la pena, non è che teoria; saper dove meglio
si spini la birra è pratica vera, è geografia”
Goethe
P2P di prima generazione (1/2)
Reti strutturate:
ed2k,
Fasttrack,
Gnutella e Gnutella2 (“piccola” diatriba sul
nome con la GNU project)
trovare tutti i nodi che hanno un dato
trovarne almeno uno nel minor tempo possibile
P2P di prima generazione (2/2)
Sistemi proprietari o meno (distinzione e
primo approccio alla sicurezza)
Topologia tipica:
alcuni server centrali, molti client
Problemi tipici:
http://katapekkia.altervista.org/?q=aumentano_i_
server_spia_sulla_rete_ed2k.htm
Rapida comparativa
DirectConnect (DC++)
Usa una serie di hub (server) che mantengono le
informazioni relative a un gruppo di utenti
Una volta connessi ad un hub si condivide file solo
con i nodi connessi a tale hub
E’ possibile connettersi a più hub nello stesso tempo
Gli hub sono connessi tra loro ma non si scambiano
informazioni relative alla ricerca di una determinata
chiave (tanti piccoli Napster)
La lista degli hub attivi viene mantenuta da tutti gli
hub e aggiornata periodicamente dagli altri hub
mediante messaggi del tipo “I am here”
WinMX
Basato su una rete di server (circa 50) chiamata
OpenNap nata subito dopo che è stato chiuso il
server di Napster
Viene usata anche da NapMx
In WinMx viene fatta una distinzione fra nodi di
connessione primaria:
direttamente connessi ai server
sono usati anche per il Routing
e nodi di connessione secondaria:
connessi solo ai nodi di connessione primaria
non si occupano di Routing
KaZaA
Viene usata una rete proprietaria
In KaZaA viene fatta una distinzione fra nodo
e Supernodo(server):
Ogni nodo semplice collabora con il proprio
Supernodo
I Supernodi collaborano tra loro e con i propri
sottonodi
Come sono connessi i Supernodi?
Gnutella
La ricerca usa il flooding
Il messaggio di ricerca viene inoltrato a tutti i nodi
della rete Gnutella, ogni volta
La ricerca risulta inefficiente e non scalabile
Il peso dei messaggi è rilevante rispetto al traffico
Gnutella2 (1/2)
Struttura simile a KaZaA
In Gnutella2 il numero massimo di nodi affidati a un hub è
basso(150)
Il costo di comunicazione fra nodi e hub è basso (ed è giusto che
sia così)
Il problema principale è rappresentato dalla comunicazione fra gli
hub:
Gli hub sono raggruppati in cluster
Quando un nodo richiede la ricerca di un proprio elemento al
proprio hub:
Viene ricercato l’elemento nel proprio cluster
Viene ricercato l’elemento nei cluster vicini(a distanza 1) più qualche
cluster lontano scelto a caso
Viene ricercato l’elemento nei cluster vicini dei vicini (a distanza 2)
più qualche cluster lontano scelto a caso
Gnutella2 (2/2)
La lista degli hub a distanza i+1 è ottenuta in
risposta alla ricerca effettuata sugli hub a distanza i
Ogni hub mantiene la lista degli hub vicini più una
cache di hub lontani aggiornata di tanto in tanto
Viene mantenuta una done list
Le ricerche all’interno del cluster sono fatte usando
TCP
Le ricerche fra cluster sono fatte usando UDP
Gli strumenti software
Sun, con grande lungimiranza, ha realizzato una
piattaforma open source JXTA (sta per juxtapose)
per creare in modo facile applicazioni P2P
JXTA non è una libreria di codice; piuttosto, è un
insieme di protocolli che può essere implementato in
ogni linguaggio e su ogni rete per costruire
applicazioni P2P
JXTA fornisce tutte le funzionalità di base richieste
in una applicazione P2P fra queste:
peer discovery;
peer communication;
JXTA è 100% OPEN SOURCE (http://www.jxta.org)
Ancora su JXTA, InstantP2P
InstantP2P è un esempio opensource di
applicazione JXTA.
E’ progettato per fornire un mezzo semplice
per capire come un’applicazione può usare la
tecnologia JXTA. Implementa alcune
applicazioni classiche:
peer-to-peer messaging (crittografato e in chiaro)
peer group chat
condivisione file
Assistiamo ad un gap
generazionale
Reti non strutturate:
Kademlia (varie implementazioni)
Chord
Tapestry
Gnunet
BitTorrent
Quasi tutte non sono proprietarie!
Topologia tipica:
ogni client può anche fungere da server centrale
Problemi tipici:
lentezza e scarsa esaustività della ricerca
Distributed Hash Tables (1/2)
Le tabelle di hash distribuite (DHT) sono una classe
di metodi distribuiti decentrallizzati che partizionano
la proprietà di un insieme di chiavi tra i nodi
partecipanti, e possono efficentemente indirizzare i
messaggi all’unico proprietario di una data chiave.
Le DHT sono pensate per scalare su grandi numeri
di nodi e per gestire un continuo va e vieni di nodi
(eventuali problemi potrebbero mandare in crash
una macchina).
Primo sviluppo: MIT
Distributed Hash Tables (2/4)
A ogni file e ad ogni nodo è associata una chiave
La chiave viene di solito creata facendo l’hash
(tipicamente 128 o 160 bit) del nome del file o dell’IP
del nodo
Ogni nodo del sistema è responsabile di un insieme
di file/chiavi, e tutti insieme realizzano una DHT
L’unica operazione che un sistema DHT deve fornire
è lookup(key), la quale restituisce l’identità del
responsabile di una determinata chiave
Distributed Hash Tables (3/4)
Tutti i nodi del sistema condividono una
tabella hash
Conoscono la struttura della tabella
Ma non conoscono il responsabile di una
determinata entry
Distributed Hash Tables (4/4)
Se una chiave è richiesta più spesso, il
responsabile della chiave e anche i suoi vicini
potrebbero sovraccaricarsi
Per ovviare al problema si possono usare
meccanismi di caching e di duplicazione
Diverso è il problema relativo ai nodi che si
sovraccaricano per il traffico generato dalle
lookup
Questo tipo di traffico è abbastanza difficile da
individuare e da gestire
P2P di seconda generazione
(1/3)
Problema: i protocolli usati da Napster e
Gnutella non sono scalabili
Per migliorare la scalabilità sono nati i
cosiddetti protocolli P2P di seconda
generazione che utilizzano le DHT
(Distributed Hash Table)
Alcuni esempi di questi protocolli sono:
Tapestry, Pastry, Chord, Can, Viceroy,
Butterfly
P2P di seconda generazione
(2/3)
A ogni file e ad ogni nodo è associata una chiave;
La chiave viene di solito creata facendo l’hash del
nome del file;
Ogni nodo del sistema è responsabile di un insieme
di file(o chiavi) e tutti realizzano una DHT;
L’unica operazione che un sistema DHT deve fornire
è lookup(key), la quale restituisce l’identità del
responsabile di una determinata chiave.
P2P di seconda generazione
(3/3)
La scalabilità di un protocollo è direttamente
legata all’efficienza dell’algoritmo usato per il
routing
I vari DHT conosciuti differiscono proprio nel
routing
Ricordo che per ora stiamo parlando di
protocolli pensati per reti fisiche wired
Kademlia (1/2)
Ogni nodo è rappresentato da un identificatore di 160 bit
Dati due identificatori x e y la distanza fra x e y (d(x,y)) è definita
come x ⊕(xor) y
XOR è una metrica:
d(x,x)=0
d(x,y)>0 se x≠y
d(x,y)=d(y,x) (simmetrico)
d(x,y)+d(y,z)≥d(x,z)
fissato x e una distanza d esiste un solo y tale che d(x,y)=d
Per ogni 0 ≤ i ≤ 160, ogni nodo mantiene una lista di k (costante)
nodi (detta k-bucket) a distanza compresa fra 2i e 2i+1 da se
stesso
Kademlia (2/2)
I k-bucket vengono aggiornati e ordinati ad ogni operazione
con una politica detta least-recently seen node
Ovviamente a ogni passo l’algoritmo di routing dimezza la
distanza fra il nodo che fa la richiesta e la destinazione
(O(log n) passi)
La dimensione delle tabelle di routing è klog n
Poiché è simmetrico il sistema si stabilizza da solo. In
pratica durante le lookup le tabelle di routing vengono
aggiornate
Tapestry
Realizzazione dinamica dell’algoritmo di Plaxton
(che non si adattava a sistemi dinamici)
Supponendo che le chiave sia costituita da un
intero positivo l’algoritmo di routing corregge a ogni
passo un singolo digit alla volta
Per fare ciò un nodo deve avere informazioni sui
nodi responsabili dei prefissi della sua chiave;
(O(log N) nodi)
Il numero di messaggi necessari per fare lookup è
O(log N)
L’algoritmo in pratica simula un Ipercubo
Chord
Le chiavi sono mappate su un array circolare (ring, o anello)
Il nodo responsabile di una determinata chiave è il primo nodo che la succede in
senso orario
Ogni nodo x di Chord mantiene due insiemi di vicini:
I log N successori del nodo x più il predecessore. Questo insieme viene usato per
dimostrare la correttezza del Routing
Un insieme log N nodi distanziati esponenzialmente dal nodo x, vale a dire l’insieme
dei nodi che si trovano a distanza 2i da x per i che va da 0 a log N – 1. Questo insieme
viene usato per dimostrare l’efficienza del Routing
Le informazioni che il nodo deve mantenere sugli altri nodi sono log N + log N +
1 = O(log N)
Il numero di messaggi necessari per fare lookup è O(log N)
Il costo che si paga quando un nodo lascia o si connette alla rete è di O(log2N)
messaggi
L’algoritmo in pratica simula un Ipercubo, inoltre si comporta molto bene in un
sistema dinamico
Svantaggi:
una sola dimensione
una sola strada
CAN
I nodi sono mappati su un toro a d dimensioni
A ogni nodo è associato un sottoinsieme di
questo spazio d-dimensionale
Ogni nodo mantiene la lista dei nodi
responsabili dei sottospazi che confinano
con il proprio sottospazio
Ogni nodo ha O(d) vicini (due per ogni
dimensione)
Sicurezza nelle DHT
E’ possibile realizzare un protocollo P2P che resista
ad attacchi di tipo denial of service
E’ necessario replicare i dati
E’ importante usare funzioni hash “One Way” (per i
dati e per i nodi)
E’ importante osservare che tutte le dimostrazioni
relative alla sicurezza dei vari algoritmi incontrati
finora si basano sul fatto che le chiavi vengono
associate ai files in modo casuale (quasi tutti gli
algoritmi usano SHA)
P2P di terza generazione
Freenet
Mute
Netsukuku (progetto italiano!)
ANtsP2P (progetto italiano!)
Devono offrire piena anonimità, e alcune
accortezze per resistere agli attacchi di denial
of service
(l’ipotesi dei generali bizantini, ad esempio)
Freenet
Ogni nodo mette a disposizione un po’ di spazio
Le operazioni possibili sono get e put di un file
Per aggiugere un nuovo file si invia un send
message nella rete e un identificatore GUID (Global
Unique Identifier) in base al quale il file viene
memorizzato in un insieme di nodi (Data Partition)
Per recuperare un file basta inviare un messaggio di
richiesta contenente il GUID del file
Servizi aggiuntivi:
Persistenza
Anonimato
Purtroppo è tutt’altro che efficiente…
Idee per reti atipiche
Small world network (6 gradi di separazione)
Bloom filters (una tipica funzione hash a
senso unico)
Bloom Filters
Sono una soluzione probabilistica al problema
dell’appartenenza da parte di un membro
“Ovunque sia usata una lista o un insieme, e lo spazio
sia una variabile da tenere in considerazione, un
filtro di Bloom dovrebb’essere considerato
anch’esso. Quando si usa un filtro simile è bene
mettere in conto i falsi positivi”
B. Bloom [1970]
Come testare una rete P2P
ns2, molto avanzato
p2psim, estremamente specializzato, anche
se in fase di beta
Simulatore di reti: p2psim (1/3)
p2psim fa parte del progetto IRIS (MIT):
Il progetto IRIS si propone come fine lo sviluppo di una nuova
infrastruttura decentralizzata, basata su DHT
Il progetto IRIS comprende tra l’altro:
Chord
CFS (Cooperativa File System):
è un sistema di memorizzazione basato su Chord
permette la pubblicazione dei propri file e la possibilità di
accedere ai file pubblicati da altri (solo lettura)
permette di distribuire il carico fra i nodi
permette di creare repliche dei dati, onde evitare la perdita
degli stessi a seguito di fallimento dei nodi del sistema
Simulatore di reti: p2psim (2/3)
L’applicazione prende in input 3 file di testo, per
rappresentare rispettivamente:
La topologia della rete
Il protocollo da utilizzare
Gli eventi da generare
C’è di che sbizzarrirsi, ma non esiste uno standard per la
visualizzazione dei risultati di una simulazione
In realtà i risultati vengono generati dal distruttore della classe
che rappresenta il protocollo testato
Nella versione attuale di p2psim ogni protocollo si basa su
parametri diversi, e questo complica la comparazione dei
protocolli
Simulatore di reti: p2psim (3/3)
Simulare un protocollo con p2psim è abbastanza semplice
perchè i file sillyprotocol.h e silliprotocol.C
contengono una bozza di protocollo non implementato
E’ sufficiente implementare le operazioni di join e lookup
E’ possibile farsi un’idea del codice da scrivere analizzando
il codice sviluppato per gli altri protocolli
Infine bisogna editare i 3 file di testo (protocollo, topologia,
generatore di eventi) da passare all’applicazione
E’ possibile inoltre creare il proprio generatore di eventi
utilizzando tra l’altro SillyEventGenerator
Prove di concetto
Tutto è iniziato da:
tinyp2p, 15 righe di Python
Seguito da:
molester, 6 righe di Perl
E da:
uP2P, 6 righe di bash script
uP2P, il codice
Altri usi del P2P
Ambienti virtuali distribuiti:
Grid Network e distribuzione della potenza di
calcolo
Update di un file, replicazione sugli slave, e
consistenza
Concludiamo in bellezza
“Possiamo vedere poco di ciò che c’è
all’orizzonte, ma ciò che vediamo ci fa capire
che c’è molto da fare.“
Alan Turing