• Aucun résultat trouvé

2.2 Systèmes de gestion de données distribués

2.2.2 Catégories de réseaux P2P

Les quatre catégories de réseaux sont maintenant introduites.

Réseaux P2P avec topologie non-structurée

Les réseaux avec topologie non-structurée représentent l’ensemble des solu- tions P2P où le voisinage de chaque nœud, ou pair, d’une part, et le placement des données, d’autre part, ne souffrent que de peu de restrictions [43]. De cette manière, chaque pair connaît un sous-ensemble des pairs disponibles sur le réseau, son voisinage (i.e. neighbors), généralement choisis aléatoirement sur un serveur de bootstrap – lorsqu’un pair rejoint le réseau, il contacte ce serveur. Chaque pair partage ses propres données qu’il stocke localement et le placement des autres données lui est inconnu.

Plusieurs méthodes ont été mises en place pour le traitement des requêtes [165] comme l’inondation (i.e. BFS) présentée plus bas. L’objectif de chacune de ces méthodes est de limiter le coût de la requête, tout en maximisant le rappel (i.e.

recall). Ce coût représente le nombre de sauts qu’elle doit faire sur le réseau – et

donc, le nombre de pairs impliqués. Le rappel représente la fraction des objets pertinents qu’il a été possible de récupérer lorsque la requête a été soumise :

recall(q) = |R

q∩ Relq|

|Relq| (2.16)

Où Rq représente l’ensemble des objets récupérés lors du traitement de la re- quête q et Relq représente tous les objets pertinents présents dans le système. Un certain nombre de contributions se focalisant sur le traitement des requêtes sont présentées ici :

u v4 v6 v2 v5 v1 v3 v2 q q q q q q q

(a) Propagation de la requête q.

u v4 v6 v2 v5 v1 v3 v2 R R R R R R R

(b) Renvoi des résultats par le

même chemin que la requête q.

Figure 2.6: Traitement des requêtes dans les réseaux P2P avec topologie non

structurée.

BFS (i.e. Breath-First Search) [78] : lorsqu’un utilisateur u soumet une

requête q, celle-ci est propagée au voisinage de u récursivement (cf. Figure 2.6a). Le nombre maximum de sauts, ou récursions, que peut faire la requête est défini par le système : TTL (i.e. Time To Live). Chaque pair ayant reçu la requête calcule localement les résultats de celle-ci, QueryHit, et les transmet par le même chemin qu’a suivi la requête (cf. Figure 2.6b).

Iterative Deepening [175] : cette méthode est une adaptation de BFS où la

requête était directement propagée sur le réseau avec une grande valeur de TTL.

Iterative Deepening est un BFS progressif. Pour cela, plusieurs exécutions de BFS

sont nécessaires, chacune ayant une valeur plus grande de TTL (e.g. 1, 2, 3 puis 4). L’exécution de la requête s’arrête lorsque des résultats pertinents sont trouvés ou qu’un TTL maximum est atteint.

Random walks [100] : les marches aléatoires sont ici exploitées. Les nœuds

sont structurés de manière à ce que le degré de connexion (i.e. nombre de voisins) de chacun dépende du nombre de requêtes qu’ils sont capable de traiter, étant donné un espace de temps prédéfini. Les marches aléatoires sont également fixées par une valeur TTL. Finalement, étant donné un pair u, chaque autre pair p dans le voisinage de u est associé à une valeur définissant le nombre maximum de fois que u peut le contacter dans un espace de temps donné (i.e. valeur prédéfinie). Les pairs maximisant cette probabilité reçoivent la requête.

Autre : à cela s’ajoutent de nombreux autres algorithmes, tels que APS (Adap- tive Probabilist Search) [165], Local indices [45, 174], basés sur les filtres de

Réseaux P2P avec topologie structurée

Les réseaux avec topologie structurée font très souvent référence aux DHTs (i.e. Tables de Hachage Distribuées). À l’inverse des réseaux avec topologie non- structurée, ici, les données et les utilisateurs sont positionnés de manière prédé- finie. Ce genre de structures propose principalement une fonction de lookup (i.e. recherche), qui, à partir d’une clé key retourne le nœud responsable de celle-ci. Plus généralement, dans le cadre de la gestion de données, l’opération se décom- pose en deux étapes. Dans l’optique de stockage d’une valeur, celle-ci est d’abord transformée en clé :

key= hash(value) (2.17)

Puis, la DHT, via son mécanisme de lookup, permet de retrouver le nœud qui est responsable de ce couple (key,value) :

node= lookup(key) (2.18)

Pour cela, chaque nœud est représenté par un identifiant unique et chaque ap- proche structure les nœuds entre eux en fonction de cet identifiant. Contrairement aux réseaux avec topologie non-structurée, l’objectif n’est pas de maximiser le re-

call qui est systématiquement de 1 (les algorithmes étant déterministes dans leur

localisation), mais uniquement d’optimiser le coût de traitement de la requête. Un nombre varié d’approches a été proposé [63] :

Anneau (i.e. ring) [47, 156] : un représentant de cette approche est Chord.

Les nœuds sont positionnés les uns après les autres, par identifiant croissant ; le nœud ayant l’identifiant le plus grand est quant à lui connecté avec celui qui a l’identifiant le plus petit. Un nœud est responsable de l’ensemble des clés dont la valeur est inférieure ou égale à son identifiant mais supérieure à celui du nœud précédent. Afin d’accélérer l’opération de lookup, chacun d’entre eux est associé à une table de routage (e.g. finger table) composée de k lignes associant toutes une clé au nœud qui en est responsable. La valeur de ces clés suit l’équation suivante :

key= nodeId + 2i (2.19)

0 ≤ i < k étant le numéro de la ligne. Finalement, l’opération de lookup consiste à envoyer une requête q = key de manière récursive au nœud ayant le plus grand identifiant inférieur à la clé. L’opération s’arrête lorsque le nœud situé après le nœud courant a un identifiant supérieur à la clé.

Comme pour la plupart des implémentations de DHT, la structure en anneau permet un lookup avec une complexité de O(log(n)).

Autres : plusieurs autres topologies de DHTs ont été proposées comme l’arbre

(i.e. tree) [63], l’hypercube [134], en forme de fleur [53], de papillon [106] ou en- core, sous forme de structures hybrides [139]. Avec l’arrivée du NoSQL, les DHTs

sont revenues à l’ordre du jour avec des implémentations modifiées comme Dy-

namo de Amazon [47]. Kademlia [111] (i.e. XOR) est aujourd’hui utilisée pour

la diffusion de données sur le réseau Bittorrent. Chaque utilisateur effectue pé- riodiquement l’opération put(key, ip), signifiant qu’à son adresse IP, l’objet avec la clé key est disponible. À l’inverse, un utilisateur voulant télécharger un objet effectuera un get(key) pour récupérer la liste des utilisateurs le partageant.

Deux remarques peuvent être formulées à propos des réseaux structurés. Tout d’abord, bien que les DHTs offrent une opération de lookup efficace de complexité O(log(n)), satisfaisante pour la recherche exacte (i.e. exact-match queries), celles- ci ont plutôt du mal à s’adapter aux requêtes plus complexes (e.g. à base de mots clés) où le positionnement des données n’est plus évident. En second lieu, l’autonomie de chaque nœud se réduit, puisqu’il ne choisit pas son recouvrement et se conforme à une règle (i.e. topologie).

Réseaux P2P avec topologie dynamique

Les réseaux P2P avec topologie dynamique exploitent des protocoles de bavar- dage (i.e. gossip). En se calquant sur la propagation de rumeurs et les bavardages dans la vie réelle, ces protocoles sont caractérisés par des échanges réguliers – la régularité est définie par le système – entre pairs.

En plus de leur capacité de passage à l’échelle, ils sont faciles à implémenter, robustes, résistants aux pannes et permettent de s’adapter à la dynamicité du réseau. Les protocoles de gossip sont principalement utilisés pour (1) la dissémi- nation d’information sur le réseau, (2) le calcul d’agrégations et (3) la détection d’erreurs. Cette caractéristique de dissémination de l’information fait que les pro- tocoles de bavardage sont parfois appelés protocoles épidémiques. Par la suite, nous nous focalisons sur les protocoles de gossip pour les réseaux dynamiques, et seule la dissémination d’information nous intéresse donc : il s’agit de maintenir une vue dynamique du réseau et donc, de permettre à chaque pair u de découvrir d’autres pairs v présents sur le réseau.

Les protocoles de gossip utilisent une vue aléatoire du réseau – dont la taille est définie par le système – associée à chaque pair [75, 83]. Deux threads sont exécutés en parallèle : le premier, ou bavardage actif, exécuté par un pair u, initiera pério- diquement des bavardages avec des pairs v choisis dans la vue aléatoirement de u ; le second, ou bavardage passif, exécuté par v, consistera à recevoir ces demandes de bavardage, émanant de u. Chaque pair se retrouve donc successivement actif et passif dans le protocole de gossip.

Un bavardage s’effectue en trois étapes, telles que décrites dans la Figure 2.7 : 1. sélection du contact : un pair p sélectionne aléatoirement un autre pair

p2 p6 p3 p1 p4 p5 p6 p5 p1 p4 p2 p3 Select contact

(a) Sélection du contact.

p2 p6 p3 p1 p4 p5 p6 p5 p1 p4 p2 p3 Exchange info p6 p5 p4 p3 (b) Échange. p1 p4 p3 p2 p6 p5 p2 p6 p3 p1 p4 p5 Update view (c) Mise à jour.

Figure 2.7: Échange entre deux pairs exécutant un protocole de gossip.

2. échange : p envoie un sous-ensemble aléatoire de cette vue à p2, qui, en retour, envoie un sous-ensemble aléatoire de sa propre vue ;

3. mise à jour : enfin, p et p2mettent à jour leur vue respective en remplaçant aléatoirement des pairs qu’ils connaissaient par ceux qu’ils viennent de voir. À terme, l’ensemble des utilisateurs (e.g. leur profil ou identifiant) sera diffusé sur le réseau – généralement en O(log(n)).