Répartition dynamique de charge dans un SGBD parallèle hiérarchique *



Documents pareils
Julien MATHEVET Alexandre BOISSY GSID 4. Rapport RE09. Load Balancing et migration

TP Bases de données réparties

Métriques de performance pour les algorithmes et programmes parallèles

Gestion de mémoire secondaire F. Boyer, Laboratoire Sardes

Chapitre 10. Architectures des systèmes de gestion de bases de données

Initiation au HPC - Généralités

Partie 7 : Gestion de la mémoire

PROBLEMES D'ORDONNANCEMENT AVEC RESSOURCES

Tests de performance du matériel

Informatique industrielle A Systèmes temps-réel J.F.Peyre. Partie I : Introduction

WEA Un Gérant d'objets Persistants pour des environnements distribués

INF6500 : Structures des ordinateurs. Sylvain Martel - INF6500 1

LES OUTILS D ALIMENTATION DU REFERENTIEL DE DB-MAIN

ÉTUDE DE L EFFICACITÉ DE GÉOGRILLES POUR PRÉVENIR L EFFONDREMENT LOCAL D UNE CHAUSSÉE

Chapitre V : La gestion de la mémoire. Hiérarchie de mémoires Objectifs Méthodes d'allocation Simulation de mémoire virtuelle Le mapping

Évaluation et optimisation de requêtes

BD réparties. Bases de Données Réparties. SGBD réparti. Paramètres à considérer

Module BDR Master d Informatique (SAR)

<Insert Picture Here> Solaris pour la base de donnés Oracle

Principe de symétrisation pour la construction d un test adaptatif

REALISATION d'un. ORDONNANCEUR à ECHEANCES

Runtime. Gestion de la réactivité des communications réseau. François Trahay Runtime, LaBRI sous la direction d'alexandre Denis Université Bordeaux I

Etude d Algorithmes Parallèles de Data Mining

Audit activité base Oracle / SAP

Implémentation des SGBD

Projet d informatique M1BI : Compression et décompression de texte. 1 Généralités sur la compression/décompression de texte

Ordonnancement temps réel

Conception des systèmes répartis

Cours Bases de données

4. Utilisation d un SGBD : le langage SQL. 5. Normalisation

Prototype de canal caché dans le DNS

Structure fonctionnelle d un SGBD

LE PROBLEME DU PLUS COURT CHEMIN

PROGRAMME DU CONCOURS DE RÉDACTEUR INFORMATICIEN

Présentation du module Base de données spatio-temporelles

Techniques de stockage. Techniques de stockage, P. Rigaux p.1/43

Equilibrage de charge (Load

Les simulations dans l enseignement des sondages Avec le logiciel GENESIS sous SAS et la bibliothèque Sondages sous R

Cours de Génie Logiciel

Contributions à l expérimentation sur les systèmes distribués de grande taille

Technologie de déduplication de Barracuda Backup. Livre blanc

Équilibrage Dynamique de Charge pour des Calculs Parallèles sur Cluster Linux - Une Évaluation de l Environnement AMPI.

UNE EXPERIENCE, EN COURS PREPARATOIRE, POUR FAIRE ORGANISER DE L INFORMATION EN TABLEAU

Aspects théoriques et algorithmiques du calcul réparti L agglomération

Chapitre 1 : Introduction aux bases de données

INF 1250 INTRODUCTION AUX BASES DE DONNÉES. Guide d étude

Bases de données réparties: Fragmentation et allocation

MEAD : temps réel et tolérance aux pannes pour CORBA

Solution A La Gestion Des Objets Java Pour Des Systèmes Embarqués

Introduction à la Programmation Parallèle: MPI

Projet Active Object

ORDONNANCEMENT CONJOINT DE TÂCHES ET DE MESSAGES DANS LES RÉSEAUX TEMPS RÉELS 4. QUELQUES EXEMPLES DU DYNAMISME ACTUEL DU TEMPS RÉEL

Évaluation et implémentation des langages

Résumé CONCEPTEUR, INTEGRATEUR, OPERATEUR DE SYSTEMES CRITIQUES

INTERSYSTEMS CACHÉ COMME ALTERNATIVE AUX BASES DE DONNÉES RÉSIDENTES EN MÉMOIRE

Sauvegarde collaborative entre pairs Ludovic Courtès LAAS-CNRS

Temps Réel. Jérôme Pouiller Septembre 2011

Vers une approche Adaptative pour la Découverte et la Composition Dynamique des Services

Détection d'intrusions en environnement haute performance

SYSTÈME DE GESTION DE FICHIERS

Communications collectives et ordonnancement en régime permanent pour plates-formes hétérogènes

Eléments de spécification des systèmes temps réel Pierre-Yves Duval (cppm)

Programmation parallèle et distribuée

Qualité du service et VoiP:

Big Data et Graphes : Quelques pistes de recherche

High Performance by Exploiting Information Locality through Reverse Computing. Mouad Bahi

SYSTÈME DE GESTION DE FICHIERS SGF - DISQUE

Cours Base de données relationnelles. M. Boughanem, IUP STRI

Processus! programme. DIMA, Systèmes Centralisés (Ph. Mauran) " Processus = suite d'actions = suite d'états obtenus = trace

Exclusion Mutuelle. Arnaud Labourel Courriel : arnaud.labourel@lif.univ-mrs.fr. Université de Provence. 9 février 2011

CONFIGURATION DE BASE. 6, Rue de l'industrie BP130 SOULTZ GUEBWILLER Cedex. Fax.: Tel.:

Définitions. Numéro à préciser. (Durée : )

Equilibrage de charge pour les grilles de calcul : classe des tâches dépendantes et indépendantes.

Bases de données Cours 1 : Généralités sur les bases de données

L unique SAN industriel proposant un stockage multiniveau automatisé (Automated Tiered Storage)

Rapport d activité. Mathieu Souchaud Juin 2007

Les transactions 1/46. I même en cas de panne logicielle ou matérielle. I Concept de transaction. I Gestion de la concurrence : les solutions

Système de stockage IBM XIV Storage System Description technique

La nouvelle planification de l échantillonnage

Techniques d interaction dans la visualisation de l information Séminaire DIVA

INEX. Informatique en Nuage : Expérimentations et Vérification. Livrable n M1 PARALLÉLISME ET ÉVALUATION

Optimisations des SGBDR. Étude de cas : MySQL

Encryptions, compression et partitionnement des données

M2-Images. Rendu Temps Réel - OpenGL 4 et compute shaders. J.C. Iehl. December 18, 2013

ORACLE TUNING PACK 11G

SafeKit. Sommaire. Un livre blanc de Bull Evidian

!-.!#- $'( 1&) &) (,' &*- %,!

Bases de données. Chapitre 1. Introduction

Windows Internet Name Service (WINS)

WHITE PAPER. Quels avantages la déduplication offre-t-elle aux entreprises? Livre blanc Acronis

Modélisation de bases de données : Le modèle relationnel

Differential Synchronization

Optimisation multi-critère pour l allocation de ressources sur Clouds distribués avec prise en compte de l énergie

Créer le schéma relationnel d une base de données ACCESS

physicien diplômé EPFZ originaire de France présentée acceptée sur proposition Thèse no. 7178

Définition et diffusion de signatures sémantiques dans les systèmes pair-à-pair

Introduction aux algorithmes répartis

Systèmes d informations nouvelles générations. Répartition, Parallèlisation, hétérogénéité dans les SGBD. Exemple d application d un futur proche

Cours n 12. Technologies WAN 2nd partie

Transcription:

Répartition dynamique de charge dans un SGBD parallèle hiérarchique * Luc Bouganim, Daniela Florescu, Patrick Valduriez Projet Rodin - INRIA Rocquencourt 78153 Le Chesnay Cedex * Travail effectué dans le GIE Dyade (Bull Inria) et partiellement financé par le projet IDEA de la CE RÉSUMÉ :Nous considérons l'exécution de requêtes multi-jointures dans une architecture parallèle hiérarchique, consistant d'un ensemble de noeuds multiprocesseurs à mémoire partagée, reliés par un réseau rapide. Dans ce contexte, l'équilibrage de charge doit être effectué à deux niveaux, localement entre les processeurs de chaque noeud à mémoire partagée puis globalement entre les différents noeuds. Nous proposons un modèle d'exécution dynamique qui maximise l'équilibrage local de charge et minimise ainsi le besoin de redistribution du travail entre les noeuds. Cela est obtenu en permettant à chaque processeur d'un noeud d'exécuter n'importe quel opérateur pouvant être traitée localement, tirant ainsi parti du parallélisme inter et intra-opérateur présent dans les requêtes complexes. Nous effectuons une évaluation de performances en utilisant un prototype de notre modèle sur une machine KSR1 comprenant 72 processeurs. Les mesures effectuées sur un ensemble de requêtes mettant en jeu de grandes relations montrent de bonnes performances, même dans le cas de mauvaises répartitions des données. Nous montrons que notre modèle se comporte, sur un noeud à mémoire partagée, aussi bien que des modèles dédiés et prend en compte efficacement plusieurs noeuds. ABSTRACT : We consider the execution of multi-join queries in a hierarchical parallel system,i.e., a shared-nothing system whose nodes are shared-memory multiprocessors. In this context, load balancing must be addressed at two levels, locally among the processors of each shared-memory node and globally among all nodes. In this paper, we propose a dynamic execution model that maximizes local load balancing within shared-memory nodes and minimizes the need for load sharing across nodes. This is obtained by allowing each processor to execute any operator that can be processed locally, thereby taking full advantage of interand intra-operator parallelism. We conducted a performance evaluation using an implementation on a 72-processor KSR1 computer. The experiments with many queries and large relations show very good speedup results, even with highly skewed data. We show that, in shared-memory, our execution model performs as well as a dedicated model and can scale up very well to deal with several nodes. MOTS-CLÉS : bases de données, parallélisme, machines hiérarchiques KEYWORD : databases, parallelism, hierarchical architecture

1. Introduction Les concepteurs de bases de données parallèles ont longtemps opposés les architectures à mémoires partagées (shared-memory) et distribuées (shared-nothing). La mémoire partagée permet d obtenir de bonnes performances pour un nombre limité de processeurs. A l inverse, les architectures distribuées autorisent des configurations avec un grand nombre de processeurs [DeW92b][Val93]. L architecture hiérarchique consiste en un ensemble de noeuds multiprocesseurs à mémoire partagée, reliés par un réseau rapide. Elle permet de combiner les avantages des deux approches précédentes [Gra93]. Ainsi, les multiprocesseurs symétriques (SMP), e.g., Sequent, évoluent vers des architectures extensibles alors que les machines massivement parallèles (MPP), e.g., NCR s Teradata, se tournent vers la mémoire partagée. La PowerCluster de Bull est un autre exemple d architecture hiérarchique composée d un ensemble de multiprocesseurs symétriques Power-PC. Nous nous intéressons à l'exécution de requêtes multi-jointures dans une architecture parallèle hiérarchique. Ces requêtes sont de plus en plus fréquentes dû à l utilisation de vues, notamment dans les nouvelles applications décisionnelles, e.g. entrepôts de données. L objectif d une exécution parallèle est de réduire le temps de réponse en distribuant la charge d une requête sur plusieurs processeurs. Le principal obstacle à cet objectif est la mauvaise distribution de la charge, lorsque des processeurs sont surchargés alors que d autres sont inactifs. Les performances d une exécution parallèle peuvent alors se dégrader fortement puisque le temps de réponse correspond à celui du processeur le plus chargé. La parallélisation d une requête peut être effectuée selon deux axes: horizontalement (parallélisme intra-opérateur), en distribuant chaque opérateur sur un ensemble de processeurs, et verticalement (parallélisme inter-opérateur indépendant ou pipeline) en distribuant tous les opérateurs de la requête sur différents processeurs. Les solutions proposées pour la répartition de charge sont généralement spécifiques à un type de parallélisation et à une architecture. Sur une architecture shared-nothing, le parallélisme intra-opérateur est obtenu grâce à la fragmentation des données [Bor90], [DeW90], [Ape92]. Les mauvaises distributions de données (skew), fréquente en pratique, [Wal91], peuvent entraîner une mauvaise répartition de la charge. Ce problème a été traité en développant des algorithmes de jointure spécifiques supportant différents types de skew [Kit90], [DeW92a], [Sha93], [Ber92] et qui sont basés sur une redistribution dynamique. Avec le parallélisme inter-opérateur, la distribution des opérateurs sur les processeurs peut aussi entraîner une mauvaise répartition de la charge. Plusieurs études sont dédiées à ce problème [Meh95], [Rah95], [Gar96]. La répartition de charge est faite statiquement pendant la phase d optimisation ou juste avant l exécution. Les raisons potentielles d une mauvaise répartition de charge sur une architecture shared-nothing sont étudiées dans [Wil95]. Premièrement, le degré de parallélisme et l allocation des processeurs aux opérateurs, décidé statiquement pendant la phase

d optimisation, sont basés sur un modèle de coût souvent imprécis. Deuxièmement, le choix du degré de parallélisme est sujet à des erreurs de partie entière car les processeurs et les opérateurs sont des entités discrètes. Enfin, les processeurs associés aux opérateurs en haut de la chaîne pipeline peuvent rester inactifs un certain temps, à cause des délais dans une chaîne pipeline. Ces problèmes sont dus à une association rigide entre processeurs et opérateurs, inhérente à l architecture shared-nothing. En mémoire partagée, il y a plus de flexibilité puisque tous les processeurs ont un accès uniforme à la mémoire et aux disques. Les techniques de répartition de charge peuvent alors être plus dynamique (i.e., pendant l exécution) puisque la redistribution de la charge peut être faite à faible coût. Une stratégie d exécution très efficace en mémoire partagée est le pipeline synchrone (SP) [Pir90], [Hon92], [She93]. Chaque processeur lit des tuples dans des buffers d I/O et exécute les jointures le long de la chaîne pipeline en utilisant des appels de procédure. DBS3 [Cas95] utilise un modèle d exécution destinés à une architecture shared-nothing sur une machine à mémoire partagée. Ce modèle, présenté dans [Bou96] permet de réduire les interférences et d effectuer une bonne répartition de charge au niveau intra-opérateur. Cependant la répartition inter-opérateur n a pas été abordée. A notre connaissance, le problème de la répartition de charge sur une architecture hiérarchique n a jamais été traité. Dans ce contexte, la répartition de charge est plus complexe puisqu elle doit être effectuée à deux niveaux, localement, entre les processeurs de chaque noeud mémoire partagée, et globalement entre les noeuds. Les approches présentées ci-dessus ne peuvent être facilement adaptées à une architecture hiérarchique. Les approches dédiées à une architecture shared-nothing ne profiteraient pas de la flexibilité de l'architecture à mémoire partagée, et leurs problèmes inhérents ne feraient que s'aggraver (complexité et inexactitude du modèle de coût). Pour les approches destinées à la mémoire partagée, l aspect distribué de l architecture hiérarchique entraînerait des surcoûts de communications prohibitifs. Dans cet article, nous proposons un modèle d exécution pour une architecture hiérarchique qui réalise dynamiquement la répartition de la charge au niveau inter et intra-opérateur. L idée de base est de décomposer la requête en unités séquentielles de travail autonomes pouvant être exécutées par n importe quel processeur. De manière intuitive, un processeur peut ainsi se déplacer horizontalement et verticalement le long de la requête. L avantage principal de cette méthode, dans une architecture hiérarchique, est qu elle permet de minimiser les coûts de communications en maximisant la répartition de charge inter et intra-opérateur au niveau de chaque noeud. Pour valider ce modèle d exécution, nous avons développé un prototype du modèle sur la machine KSR1 et étudié ses performances sur un ensemble de requêtes complexes. Cet article est organisé comme suit. La section 2 présente la problèmatique abordée en fixant de manière plus précise le contexte. La section 3 présente les concepts de base de notre modèle ainsi que la stratégie de répartition de charge. La section 4 complète la description du modèle par des détails de réalisation. La section 5 compare les performances de notre modèle à deux autres modèles d exécution, sur la machine KSR1. La section 6 conclut.

2. Problématique Le fait de considérer une architecture hiérarchique change les décisions prises par l optimiseur pour la génération des plans d exécution parallèle. Dans cette section, nous définissons plus précisément le système d exécution (architecture sous jacente, modèle de parallélisation, etc.) et les plans d exécution parallèle, paramètre d entrée de notre modèle. 2.1. Système d exécution Nous considérons un système de bases de données distribué comportant un ensemble de noeuds à mémoire partagée, appelés par la suite noeud-smp et composés de plusieurs processeurs, plusieurs disques et une mémoire partagée. Les communications inter-noeuds se font par envoi de messages alors que dans chaque noeud, la mémoire partagée est utilisée pour réaliser efficacement la communication inter-processeurs. Les relations sont fragmentées horizontalement sur chaque noeud, et dans chaque noeud, sur les disques. A cet effet, une fonction de hachage est appliquée à un ou plusieurs attributs. Le home d une relation représente simplement l ensemble des noeuds SMP stockant ses fragments. Nous considérons ici les algorithmes de jointure parallèle par hachage puisqu ils offrent généralement des performances supérieures [Val84][Sch89]. La jointure par hachage permet deux types de parallélismes: (i) plusieurs jointures peuvent être exécutées en mode pipeline (parallélisme inter-opérateur); et (ii) chaque jointure peut être effectuée en parallèle sur des fragments de relations (parallélisme intraopérateur). Les deux relations mises en jeu sont fragmentées (dynamiquement) en un même nombre de fragments avec la même fonction de hachage appliquée à l'attribut de jointure. La jointure parallèle par hachage s effectue alors en deux phases séquentielles. Dans la première phase, une table de hachage est construite, en parallèle, pour chaque fragment de la relation interne. Dans la deuxième phase, les fragments de la relation externe sont lus en parallèle et leurs tuples sont joints par hachage avec la table de hachage du fragment correspondant de la relation interne. 2.2. Plan d exécution parallèle Le résultat de la phase d optimisation parallèle est un plan d exécution parallèle consistant d un arbre d opérateur, de l ordonnancement de ces opérateurs et de l allocation des ressources aux opérateurs. Plusieurs formes d arbres peuvent être considérées: gauches, droits ou bushy. Les arbres bushy sont les plus intéressants car ils offrent plus d opportunités pour minimiser la taille des résultats intermédiaires [She93] et pour exploiter différents types de parallélisme [Lan93]. Aussi, dans cet article, nous nous concentrons sur l'exécution d arbres bushy. L arbre d opérateur provient de la macro-expansion de l arbre de jointure [Has94]. Les noeuds représentent les opérateurs atomiques de l'algèbre relationnelle et les arcs représentent les flots de données. Ces arcs peuvent être de deux types:

bloquants ou pipelines. Un arc bloquant indique que les données doivent être entièrement produites avant de pouvoir commencer l opérateur consommateur. Ainsi, un opérateur ayant une entrée bloquante doit attendre la matérialisation complète de l'opérande avant de commencer. Un arc pipeline indique que les données peuvent être consommées au fur et à mesure. Ainsi, le consommateur peut débuter dès que le premier tuple à consommer a été produit. Considérons un arbre d'opérateur utilisant la jointure par hachage. Trois opérateurs sont nécessaires: scan pour lire chaque relation de base, build et probe. L'opérateur de build produit la table de hachage de manière bloquante. Le probe produit, en pipeline, les tuples résultats. Ainsi, pour une jointure par hachage, il y a toujours un arc bloquant entre le build et le probe. L arbre d'opérateur n'entraîne pas de contraintes entre deux opérateurs indépendants et permet donc leur exécution parallèle. Toutefois, afin d optimiser le partage des ressources disponibles (mémoire, disques, processeurs), l optimiseur peut ajouter de nouvelles contraintes afin de rendre leur exécution séquentielle. Ainsi, l ordonnancement des opérateurs, décidé par l optimiseur reflète les contraintes d optimisation ainsi que les contraintes inhérentes à l utilisation de la jointure par hachage. Il est exprimé par un ordre partiel sur l ensemble des opérateurs. O1 < O2 indique que l'opérateur O2 ne peut commencer avant la fin de O1 Un arbre d'opérateur peut être décomposé en un ensemble de chaînes pipeline maximum, i.e., avec le plus grand nombre d opérateurs pipeline, appelées aussi fragments [She93] ou tasks [Hon92]. Pour des raisons de simplicité, nous supposons que chaque chaîne pipeline peut être entièrement exécutée en mémoire. Dans le cas contraire, l optimiseur devrait ajouter de nouveaux arcs bloquants entre les opérateurs d une chaîne pipeline, afin de forcer la matérialisation de relations intermédiaires. Classiquement, l optimiseur parallèle choisi l ensemble des processeurs qui seront alloués pour l'exécution de chaque opérateur. En mémoire partagée, cette décision se réduit au nombre optimal de processeurs, puisque chaque processeur a un même coût d'accès à la mémoire et aux disques. En shared-nothing, l allocation des processeurs dépend fortement de la localisation des données. Chaque processeur est généralement assigné à l exécution d un et un seul opérateur. L architecture hiérarchique introduit une nouvelle dimension à ce problème. Dans ce cas, il semble plus important de décider du sous ensemble de noeuds-smp où sera exécuté un opérateur, que nous appellerons le home de l opérateur, plutôt que le sous ensemble des processeurs. Ainsi, le plan d exécution parallèle contiendra le home de chaque opérateur, celui-ci devant respecter deux contraintes évidentes: (i) le home d un opérateur scan est égal au home de la relation lue; et (ii) deux opérateurs build et probe consécutifs ont forcément le même home. 1 1. Il est relativement aisé de fournir un tel plan d exécution parallèle en utilisant un optimiseur sharednothing. Chaque noeud-smp sera considéré par l optimiseur comme un puissant processeur.

La figure 1 montre un arbre bushy mettant en jeu 4 relations, ainsi que le plan d exécution parallèle associé. Celui-ci consiste en un arbre d opérateur étiqueté avec l ordonnancement des opérateurs et les informations de localisation (home). Outre les contraintes temporelles impliquées par l utilisation de la jointure par hachage, l ordonnancement présenté contient d autres contraintes, correspondant à deux heuristiques possibles: (i) une chaîne pipeline ne débute que lorsque toutes les tables de hachage sont construites; et (ii) les chaînes pipelines sont exécutées une par une. Un tel plan d exécution parallèle est l entrée de notre modèle d exécution. Les décisions d optimisations et d ordonnancement des opérateurs, supposées bonnes, sont strictement suivies. Build 3 R S T U Arbre de jointure Probe 3 Probe 2 Arc piquant Arc pipeline Chaîne pipeline Ordonnancement des opérateurs Contraintes (hachage) : Build1<Probe1, Build2<Probe2, Build3<Probe3 Heuristique 1: Build1<Scan2, Build2<Scan4, Build3<Scan4 Heuristique 2: Build3<Scan3 Probe 1 Build 2 Build 1 Scan 2 Scan 3 Scan 1 Arbre d opérateur Scan 4 Localisation des opérateurs home(scan1) = Neud A home(build1, Probe1, Scan2, Scan3) = Noeud B home(scan 4) = Node C home (Build3, Build2, Probe2, Probe3) = Noeud B,C Figure 1. Un arbre de jointure et le plan d exécution parallèle associé. 2.3. Définition du problème Avec les définitions et hypothèses précédemment énoncées, nous pouvons maintenant poser le problème. Etant donné un plan d exécution parallèle composé d un arbre d opérateur, de son ordonnancement et du home des opérateurs, le problème est de produire une exécution sur une architecture hiérarchique minimisant le temps de réponse. Pour cela, il est nécessaire d éviter l'inactivité des processeurs en effectuant une distribution dynamique de la charge de travail. Celle-ci doit se faire à deux niveaux: (i) sur chaque noeud-smp, la répartition de charge peut être réalisée efficacement grâce à la mémoire partagée; (ii) entre les noeuds-smp, un mécanisme, plus coûteux, basé sur des envois de messages doit être mis en place. Nous voulons donc proposer un modèle d'exécution qui permet une répartition dynamique de la charge à deux niveaux dans lequel l utilisation du mécanisme local est maximisé alors que l utilisation du mécanisme global, plus coûteux, est minimisé. 3. Le modèle d exécution parallèle DP Conceptuellement, la parallélisation d une requête revient à découper le travail

total suivant deux axes. D une part, chaque opérateur est horizontalement fragmentée afin d obtenir du parallélisme intra-opérateur. D autres part, la requête est verticalement fragmenté en opérateurs dépendants ou indépendants afin d obtenir du parallélisme inter-opérateur. Nous appelons activation un travail élémentaire séquentiel, i.e., ne pouvant plus être fragmenté. La principale propriété de notre modèle est de permettre à tous les threads d exécuter n'importe quelle activation localisée sur son noeud-smp. Ainsi, il n y a pas d association statique entre les threads et les opérateurs. Ceci doit nous permettre d obtenir une répartition de charge au niveau intra-opérateur comme inter-opérateur sur chaque noeud-smp. De cette manière, le besoin d une répartition de charge globale est réduit au minimum. Elle est uniquement mise en oeuvre lorsqu il n y a plus de travail sur un noeud-smp. Dans cette section, nous présentons les concepts de base de notre modèle et la stratégie de répartition de charge que nous illustrons par un exemple. 3.1. Concepts Notre modèle d'exécution est basé sur quelques concepts: activations, files d activations, fragmentation, et threads. Activations. Une activation représente un travail élémentaire séquentiel. Comme les activations peuvent être traitées par n importe quel thread, elles doivent référencer l ensemble des informations nécessaires à leur traitement: le code à exécuter et les données accédées. Les activations de déclenchement ou trigger activation sont utilisées pour déclencher l'exécution d un opérateur feuille, i.e., un scan. Elle est constituée par un doublet (Opérateur, Fragment) référençant l opérateur de scan ainsi que le fragment de la relation de base à lire. Les activations de données ou data activation sont relatives aux tuples produits en mode pipeline et sont constituées d un triplet (Opérateur, Tuple, Fragment) référençant l opérateur à exécuter (build ou probe), le tuple traité et le fragment correspondant. Pour un build, l'exécution d une data activation revient à insérer le tuple dans la table de hachage associée au fragment. Pour un probe, elle consiste à tester le tuple avec la table de hachage associée au fragment. La qualité de l'équilibrage de charge obtenue dépend du grain de parallélisme [Bou96]. Avec un grain très fin, (data activations) nous obtenons une très bonne répartition de la charge mais avec un haut surcoût. A l inverse, l'utilisation d un grain plus grossier, (trigger activation) a un surcoût limité mais peut entraîner des mauvaises répartitions de charge. Afin d'obtenir une bonne répartition de la charge à un coût limité, nous diminuons le grain des activations de déclenchement en remplaçant un fragment par une ou plusieurs pages du fragment, et augmentons le grain des activations de données par l utilisation de caches. Files d activations. La transmission des activations de données le long des pipelines est effectuée grâce à des files d activations associées aux opérateurs. Ces envois sont effectués à travers la mémoire partagée quand le producteur et le consommateur sont sur le même noeud et à travers le réseau dans le cas contraire. Afin d unifier le

modèle, nous utilisons des files d activations pour les activations de données ( build et probe) et pour les activations de déclenchement (scan) Chaque opérateur utilise une file pour recevoir des activations. Comme chaque thread peut accéder à l ensemble des files localisées sur son noeud-smp, l utilisation d un nombre restreint de files (par exemple, une par opérateur) entraînerait des contentions. Afin de réduire ces contentions, nous associons pour chaque opérateur une file par thread. L ensemble des files d activations allouées à un thread constitue l ensemble des files primaires de ce thread. Afin de réduire encore plus les contentions, un thread consomme d abord des activations de ses files primaires avant de chercher dans les autres files accessibles sur le noeud-smp. Pendant l'exécution, l ordonnancement des opérateurs induit le blocage de certains opérateurs dans l attente de la fin des opérateurs précédents. Dans ce cas, les files des opérateurs bloqués sont aussi bloquées, i.e., leurs activations ne peuvent être consommées. Elles peuvent toutefois être produites. Lorsque tous les opérateurs bloquant sont terminés, la file bloquée devient consommable, i.e., les threads peuvent consommer ses activations. Ceci est illustré dans la figure 2 qui présente un cliché de l exécution pour l arbre d opérateur de la figure 1. n1 d1 n2 e1 d3 Sca Buil Sca Prob Buil T T T T Noeud A Noeud B Noeud C Figure 2. Cliché d une exécution Les threads peuvent librement consommer des activations de n importe quelle file non bloquée. Sans aucune restriction sur la façon dont les activations sont sélectionnées, la consommation mémoire peut considérablement augmenter. Considérons par exemple, l exécution pipeline de deux opérateurs. Si la stratégie de sélection favorise le producteur, la relation intermédiaire peut être entièrement matérialisé (plus de pipeline!), risquant alors de saturer la mémoire. Afin d éviter cette situation, nous avons choisi de limiter la taille des files d activations et utilisons un mécanisme de contrôle de flux [Gra93][Pir90], pour synchroniser les producteurs et les consommateurs dans les chaînes pipeline. Fragmentation. Appelons degré de fragmentation, le nombre de paquets des relations mises en jeu. Dans [Bou96], nous avons montré que l utilisation d un haut degré de fragmentation permet de réduire les effets négatifs des répartitions biaisées (data skew) mais peut entraîner des surcoûts non négligeables, dus à un grand nombre de fragments à gérer. Comme nos activations sont autonomes, et référencent T T T T Files primaires Files terminées Files bloquées Files actives Thread

le fragment considéré, nous pouvons mélanger des activations correspondantes à différents fragments dans la même file, réduisant alors les surcoûts de gestion de files. D une façon plus générale, dans notre modèle d exécution, l usage d un haut degré de fragmentation facilite l équilibrage de charge. Threads. Afin d'équilibrer la charge de travail, sur un noeud-smp, une stratégie simple consiste à allouer un nombre de threads bien plus grand que le nombre de processeurs, et de laisser le système d exploitation réaliser l ordonnancement des threads. Le problème d une telle stratégie est qu elle entraîne beaucoup d appels au système d exploitation dus à l ordonnancement des threads, aux interférences entre les threads et aux effets de convoi [Bla79] [Pir90] [Hon92]. Au lieu de compter sur le système d exploitation pour réaliser l équilibrage de charge, nous avons choisi d allouer un seul thread par processeur et par requête. Ceci est possible dans notre modèle, puisqu un thread peut exécuter n importe quel opérateur localisé sur son noeud-smp. L avantage de cette stratégie un-thread-parprocesseur est de réduire, de façon significative les surcoûts d interférences et de synchronisation. Sur chaque noeud-smp, nous créons alors une file par thread et par opérateur, donnant alors le même degré de parallélisme potentiel à chaque opérateur. De plus, comme il n y a qu un thread par processeur pour l ensemble de la requête, nous réduisons fortement les surcoûts d initialisation. Cette stratégie un-thread-par-processeur peut réaliser une bonne répartition de la charge de travail si les threads ne se bloquent jamais. En effet, le blocage d un thread, en l attente d un événement, entraînerait une inactivité du processeur. Pendant le traitement d une activation, un thread peut être bloqué dans les situations suivantes: le thread ne peut insérer une activation dans une file car celle-ci est pleine (contrôle de flux); l utilisation d I/O asynchrones, permettant de réaliser les accès disques et les traitements en parallèle, peuvent créer des situations bloquantes, notamment en début d exécution; avec plusieurs transactions, le traitement d une activation référençant une donnée partagée peut entraîner le blocage d un thread sur une demande de verrou transactionnel. Les problèmes de blocages sont généralement résolus à l aide de primitives de synchronisation du système d exploitation (e.g., signaux). Cette solution n est pas optimale car elle entraîne des surcoûts de synchronisation et de changement de contexte. Elle est cependant acceptable lorsque plus de threads que de processeurs ont été alloués, puisque le système exécute les threads non bloqués afin de maximiser l utilisation des processeurs. Dans notre modèle, ces situations d attentes entraîneraient l inactivité du processeur. Nous avons résolu ce problème comme suit: un thread, dans une situation bloquante, suspend son exécution, en faisant un appel de procédure, afin de trouver d autres activations à traiter durant l attente. L avantage est que la sauvegarde du contexte d exécution est fait par l appel de procédure, bien moins coûteux que des primitives systèmes. Ce mécanisme est détaillé plus loin.

3.2. Répartition de la charge La répartition de la charge, dans chaque noeud-smp, est obtenue en allouant les files d activations dans un segment de mémoire partagée et en permettant à tous les threads de consommer des activations dans n importe quelle file. Afin de limiter les interférences entre les threads, chaque thread consommera, autant que possible, dans ses files primaires avant de considérer d autres files sur le même noeud-smp. Ainsi, un thread ne devient inactif que lorsqu il n y à plus aucune activation d aucun opérateur, c est à dire qu il n y a plus rien à faire sur ce noeud (situation dite de famine). Lorsqu un noeud est en famine, i.e., il n y a plus d activations dans les files non bloquées, nous appliquons une technique de load sharing ou partage du travail, en transférant une partie de la charge d un autre noeud-smp, i.e., des activations distantes. Cependant, le transfert d activations (en utilisant des envois de messages) entraîne des surcoûts de communications. De plus, il faut aussi transférer les données associées (tables de hachage). Il est donc nécessaire d estimer dynamiquement le gain obtenu par cette opération. Appelons demandeur le noeud-smp en famine et fournisseur le noeud- SMP fournissant une partie de son travail au demandeur. Il nous faut choisir le nombre (combien?) et le type d activations à transférer (quels opérateurs, quelles files?). Il y a un compromis entre le gain potentiel apporté par la redistribution de la charge et le surcoût occasionné. Ce compromis peut s exprimer par les conditions suivantes: (i) le demandeur doit disposer de suffisamment de mémoire pour stocker les activations et les données associées; (ii) suffisamment de travail doit être transféré afin d amortir le surcoût d'acquisition; (iii) il ne faut pas transférer trop de travail, au risque de surcharger le demandeur; (iv) seules les activations de probe peuvent être transférées puisque les activations de scan nécessitent des accès aux disques et que les activations de build entraînent la construction de tables de hachage locales; (v) il n y a pas d intérêt à transférer des activations d une file bloquée puisqu elles ne pourront pas être traitées immédiatement. Enfin, (vi) pour respecter les décisions de l optimiseur, un noeud-smp n exécutera pas d activations d un opérateur qu il ne possède pas, i.e., le noeud-smp n est pas dans le home de l opérateur. Plus de détails sur la stratégie de répartition de charge globale sont donnés dans la section 4. La qualité de la répartition de charge obtenue dépend du nombre d opérateurs exécutés concurremment puisqu ils fournissent des opportunités de trouver du travail en cas d inactivité. Il est possible d augmenter le nombre d opérateurs concurrents en exécutant concurremment plusieurs chaînes pipelines ou en utilisant des algorithmes de jointures par hachage non bloquant [Wil95]. La stratégie full parallel décrite dans [Wil95] est basée sur cet algorithme, et permet d exécuter tous les opérateurs de l arbre bushy concurremment. Cependant, l exécution concurrente de plusieurs opérateurs peut entraîner une augmentation de la consommation mémoire. L ordonnancement statique des opérateurs, effectué par l optimiseur doit éviter le dépassement de capacité mémoire et résoudre ce compromis.

3.3. Exemple Nous allons maintenant illustrer ces concepts sur un exemple simple. Bien que le modèle d exécution soit conçu pour des requêtes multi-jointures, un exemple sur de telles requêtes serait incompréhensible. Nous considérons donc simplement la jointure de deux relations R et S exécuté sur deux noeuds-smp A et B, chacun possédant deux processeurs et donc deux threads d exécution. La relation R est stockée sur le noeud A, et S sur le noeud B. La figure 3 présente le plan d exécution parallèle ainsi qu un cliché de l exécution à son début. Node B Probe Scan R Build R Scan S Probe R S Build R Scan S c 1 c 2 Arbre de jointure Scan R Build R < Probe Node A Plan d exécution parallèle T A1 T A2 T B1 T B2 Node A Node B Cliché de l exécution Figure 3. Exemple simple d exécution Sur le noeud A, les threads T A1 et T A2 consomment des activations déclenchantes de l opérateur de scan R dans les files associées. Pour chaque activation, ils exécutent l opérateur de scan sur un fragment de R, lisant les tuples du disque et envoyant les tuples sélectionnés en pipeline à l opérateur build sur le noeud B. Si T A1 et T A2 se bloquent, car une des files de l opérateur de build est pleine, comme il n y a pas d autre opérateur à traiter sur le noeud A, ils devront attendre que les files du build se vident. Si un thread, T A1 par exemple, termine le traitement de toutes les activations de sa file, il consommera des activations de la file de T A2 afin d équilibrer la charge de travail. L opérateur scan R se termine lorsqu il n y a plus d activations à traiter. Sur le noeud B, les threads T B1 et T B2 consomment des activations déclenchantes de l opérateur de scan S dans les files associées. Pour chaque activation, ils exécutent l opérateur de scan S sur un fragment de S, lisant les tuples du disque et envoyant les tuples sélectionnés en pipeline à l opérateur de probe. Afin d illustrer le changement de contexte d exécution par les threads, nous supposerons que le traitement des activations C 1 et C 2 produisent plus de tuples sélectionnés que les files du probe ne peuvent stocker. Ainsi, lors du traitement de C 1, T B1 remplit les files du probe. Afin d éviter d attendre, T B1 suspend le traitement de C 1 en appelant une procédure qui cherchera d autres activations à traiter. Ainsi, le contexte d exécution de C 1 est sauvegardé dans la pile d appel de procédure. Comme le traitement d autres activations du scan R résulterait en un nouveau blocage de T B1, et comme l opérateur de probe est bloqué (puisque le build n est pas terminé), T B1 sélectionnera des activations du build produites par T A1 et T A2. T B2 fera de même lors du traitement de C 2. T B1 et T B2 traitent donc les activations du build jusqu à la fin de l opérateur de

build (i.e., les tables de hachage sont entièrement construites), débloquant ainsi l opérateur de probe. Ils peuvent alors consommer les activations du probe, vidant ainsi les files du probe et permettant la reprise du traitement de C 1 et C 2. Le traitement d autres activations du scan S peut, de nouveau, saturer les files du probe, entraînant un changement de contexte par appel de procédure et le traitement d activations du probe, et ainsi de suite jusqu à la fin de l opérateur scan S. Cet exemple simple montre l intérêt des activations et du mécanisme de changement de contexte par appel de procédure. Les threads T B1 et T B2 sont toujours actifs pendant le traitement de la requête, et la charge du noeud B est parfaitement équilibrée. Les threads T A1 et T A2 ont pu rester inactif (si les files du build restent saturées). Cela est dû aux décisions de l optimiseur qui restreint le champ d action des threads T A1 et T A2 au seul opérateur de scan R. Dans le cas de requêtes multijointures, d autres opérateurs pourraient être exécutés durant cette attente. 4. Mise en oeuvre Dans cette section, nous présentons les techniques de bases utilisées pour mettre en oeuvre notre modèle d exécution. Cette présentation se fait en suivant les différentes étapes de l exécution d une requête sur une architecture hiérarchique. Initialisation. Soit s le nombre de noeuds-smp, ayant chacun p processeurs. L exécution est initialisée en créant, sur chaque noeud-smp participant à la requête, p threads d exécution, et, pour chaque opérateur non bloqué, localisé sur ce noeud, p files d activations. De plus, un thread additionnel, appelé scheduler est créé sur chaque noeud-smp afin de recevoir et transmettre les messages entre les noeuds. Pendant l exécution, le scheduler reçoit les messages (activations) des noeuds distants et les redirige vers les files destinataires sur le noeud-smp. Le scheduler traite aussi les messages de synchronisation globale nécessaires pour la répartition de charge globale et la détection de la fin des opérateurs. Localement, le scheduler communique avec les autres threads en utilisant la mémoire partagée (pour l envoi d activations) ou par envoi de signaux pour la synchronisation. Exécution de la requête. Elle débute par l envoi d activations de déclenchement à tous les opérateurs de scan non bloqués. Chaque thread traite alors des activations les consommant par priorité dans ses files primaires. Si toutes les files primaires d un thread sont vides, il cherchera des activations dans les files primaires des autres threads localisés sur le même noeud. S il n y a plus d activations disponibles sur le noeud, les threads consommeront des activations d autres noeuds (voir plus loin). Conceptuellement, chaque thread effectue une simple boucle qui se finit lorsque le dernier opérateur de la requête termine. A chaque itération, une activation est traitée. Si aucune activation, locale ou distante ne peut être consommée, le thread est endormi. Lorsque de nouvelles activations arrivent, ou lorsqu un opérateur est débloqué, le scheduler réveille le thread qui reprend son exécution. Sélection locale d activations. Afin de maximiser la répartition de charge locale, la sélection des activations doit permettre l'accès à l ensemble des files, en respectant

les priorités, minimiser les interférences entre les threads lors des accès aux files et éviter de chercher dans des files associées à des opérateurs terminés ou bloqués. Notre solution repose sur une liste circulaire référençant l ensemble des files actives, i.e., ni terminées ni bloquées (voir figure 4). Cette liste est accédée par tous les threads pendant la sélection des activations. Q j i indique la file prioritaire de l opérateur i pour le thread Thread 3 Thread 4 Q 3 Q 4 Q 3 3 1 2 Q 4 2 Q 1 3 Q 4 3 Q 2 3 Q 1 Q 2 2 Q 2 Q 1 Q 1 1 2 1 3 Thread 1 Sélection d activations Thread 2 Figure 4. Liste circulaire de files d activations Afin d éviter les interférences, chaque thread accède la liste circulaire à une position différente correspondant à sa première file primaire. Cette liste est créée au début de la requête, et mise à jour à la terminaison de chaque opérateur afin de supprimer les files associées de la liste. De plus, si la fin de cet opérateur entraîne le déblocage d autres opérateurs, les files débloquées sont insérées dans la liste circulaire. Si aucune activation n est trouvée dans les files de la liste circulaire, cela signifie qu il n y a plus de travail à effectuer sur ce noeud. Des activations distantes doivent être alors sélectionnées. Sélection d activations distantes. La sélection d activations distantes permet de réaliser la répartition globale de la charge. Lorsqu un thread ne trouve pas d activations à traiter localement, il envoie un signal à son scheduler local, qui, à son tour envoie un message de famine aux autres noeuds. Ce message indique la mémoire disponible du noeud demandeur. Sur réception de ce message, le scheduler de chaque noeud va évaluer les files candidates. La section 3.2. énumère les conditions nécessaires pour qu une queue soit candidate, i.e., les conditions qui assurent que le transfert des activations de cette queue est possible et apportent un gain. Sur chaque noeud, le scheduler choisit la queue candidate présentant le meilleur rapport gain/surcoût. Le gain obtenu par le transfert d une queue est proportionnel au nombre d activations dans la file. Le surcoût est proportionnel à la taille des données transmises (tables de hachage et activations). Le scheduler renvoi alors au demandeur des informations sur la file sélectionnée (s il y en a une) ainsi qu une estimation de sa charge. Après avoir reçu des réponses de tous les noeuds, le demandeur sélectionne le noeud le plus chargé et demande alors le transfert des activations et des données associées, i.e., les tables de hachage. Sur réception des données, le scheduler du noeud demandeur réveil les threads afin de traiter les activations transmises. Afin d optimiser l exécution dans le cas de famine répétitive sur le même noeud, une liste de files transmises est maintenue sur le noeud demandeur. Lors de la situation de famine suivante, le noeud en famine cherchera à transférer des

activations des files dont il possède déjà les données associées. Traitement des activations. Une activation référence le code devant être exécuté (scan, build ou probe). Ainsi, le traitement d une activation est simplement effectué en faisant un appel au code associé. Cependant, lors de l exécution de ce code, un thread peut effectuer une action bloquante, par exemple en effectuant une entrée/ sortie sur le disque ou en écrivant dans une file pleine. Pour éviter ce genre de situation, le code de chaque action potentiellement bloquante est modifié de la manière suivante. Si (je ne peux effectuer (Action bloquante)) alors tantque (je ne peux effectuer (Action bloquante)) faire TraiterUneAutreActivation fin tantque // effectuer l action bloquerais le thread // cherche une autre activation finsi La procédure TraiterUneAutreActivation ne recherchera pas d activations venant du même opérateur afin d éviter de nouveaux blocages. Cette technique permet d éviter les blocages et maximise l utilisation des processeurs sans nécessiter d appels au système. 5. Etude de performances L évaluation des performances d un modèle d exécution parallèle pour des requêtes multi-jointures est rendue difficile par la nécessité d utiliser un grand ensemble de requêtes de test mettant en jeu de grosses relations. Une solution classique est d utiliser une simulation qui facilite la génération de requêtes et des relations, et permet de tester diverses configurations. Cependant, une simulation ne nous permettrait pas de prendre en compte des paramètres importants comme les surcoûts d interférences entre les threads. D un autre côté, l utilisation d un prototype complet et de jeu de tests réels restreindrait le nombre de requêtes testées et rendrait la génération des données difficile. Nous avons donc choisi de réaliser complètement notre modèle d exécution sur une machine multiprocesseur et de simuler l exécution des opérateurs, ignorant ainsi le contenu des relations. L exécution des requêtes ne dépend alors plus du contenu des relations mais de paramètres affectés à chaque relation (cardinalité, sélectivité, distribution, etc...). Dans la suite de cette section, nous décrivons la plate-forme d expérimentation et présentons des mesures de performances en deux étapes: localement sur un seul noeud-smp puis sur plusieurs noeuds. 5.1. Plate-forme d expérimentation Dans cette section, nous présentons la configuration de la machine multiprocesseur utilisée dans les expérimentations et la façon dont nous avons généré les plans d exécution parallèles et les relations. Nous présentons aussi la méthodologie utilisée pour la présentation des résultats.

5.1.1 Configuration de la plate-forme Nous avons mis en oeuvre notre modèle d exécution sur la machine KSR1, munie de 72 processeurs [Fran93] car sa composante mémoire partagée et le grand nombre de processeurs disponible permettent une organisation de type hiérarchique. Afin de simuler une architecture hiérarchique, nous avons divisé l ensemble des processeurs en groupes. Chaque groupe représente un noeud-smp 1, entre ces groupes, nous avons simulé des communications inter-noeuds en utilisant des paramètres classiques des réseaux d interconnexion. Paramètres réseau Bande passante (basé sur [Meh95]) Délai de transmission point à point Coût CPU pour l envoi d un message de 8 Ko Coût CPU pour la réception d un message de 8 Ko Valeur Infinie 0,5 ms 10000 instructions 10000 instructions Enfin, pour pouvoir exécuter des requêtes mettant en jeu plusieurs disques, nous avons simulé les accès aux disques avec les paramètres suivants: Paramètre Valeur Commentaires Nb Disques 1/processeur Nombre de disques simulés Latence 17 ms Temps de rotation Seek 5 ms Temps de placement du bras Débit 6 Mo/s Taux de transfert Coût I/O async. 5000 instr. Coût CPU pour initialiser une I/O asynchrone Cache d I/O 8 pages Buffer de cache pour les lectures séquentielles 5.1.2 Plans d exécution parallèle L entrée de notre modèle d exécution est un plan d exécution parallèle obtenu après compilation et optimisation de la requête. Pour générer les requêtes, nous avons utilisé l algorithme proposé par [She93] avec trois types de relations: petite (10K- 20K tuples), moyenne (100K-200K tuples) et grande (1M-2M tuples). Tous d abord, nous générons aléatoirement le graphe de connexion des prédicats. Comme, en pratique, la plupart des requêtes multi-jointures ont des prédicats de jointure simple, nous n avons considéré que des graphes acycliques. La cardinalité de chaque relation mise en jeu dans la requête est alors choisi aléatoirement dans les intervalles des petites, moyennes ou grandes relations. Enfin, la sélectivité de chaque arc entre deux relations du graphe de connexion des prédicats est choisie aléatoirement dans l intervalle [ 0,5 min( R, S ) R S, 1,5 max( R, S ) R S ] 1. Afin de simuler une architecture à mémoire partagée et d éviter l influence de l architecture NUMA de la KSR1, nous avons rendu locales toutes les lectures et écriture de tuples, i.e., dans le cache local de chaque processeur.

Le résultat de la génération des requêtes est un graphe acyclique étiqueté avec les cardinalités des relations et la sélectivité des arcs. Nous avons produit 20 requêtes, portant chacune sur 12 relations. Nous avons alors optimisé chaque requête grâce à l optimiseur de DBS3 [Lan93]. Le fait que cet optimiseur ait été développé dans notre équipe nous permet de contrôler de façon très fine cette étape. Pour chaque requête, les deux meilleurs arbres bushy sont retenus. Pour produire automatiquement des plans d'exécution parallèles à partir d arbres d opérateurs, nous avons fait un certain nombre d'hypothèses. Premièrement, les relations sont fragmentées sur tous les noeuds-smp. Deuxièmement, tous les opérateurs du plan s exécutent sur tous les noeuds-smp. Troisièmement, les chaînes pipelines sont exécutées une par une. Bien que ces hypothèses ne produisent pas un plan d'exécution optimal, elles nous semblent raisonnables. De plus, notre objectif est d obtenir la meilleure exécution pour un plan parallèle donné. Sans aucune contrainte sur la génération des requêtes, nous obtiendrions des exécutions très différentes et nous aurions alors bien du mal à en tirer des conclusions pertinentes. C est pourquoi nous avons contraint la génération des arbres d opérateurs de telle sorte que le temps de réponse séquentiel soit compris entre 30mn et une heure. Ainsi, nous avons produit 40 plans d'exécution parallèle portant en moyenne sur 1.3 Go de relations de base et générant environ 40 Go de résultats intermédiaires. Puisque nous ne tenons pas compte du contenu des relations, nous avons pu générer automatiquement de ces relations avec des cardinalités données. 5.1.3 Méthodologie Dans les mesures suivantes, chaque point d une courbe est obtenu à partir d un calcul effectué sur le temps de réponse de 40 plans d exécution parallèle. Comme les plans d exécution parallèle correspondent à 20 requêtes différentes, la moyenne des temps de réponse n a pas de sens. Les résultats seront donc toujours présentés en termes de raports de temps de réponse. Par exemple, dans une mesure du gain (rapport du temps de réponse avec p processeurs et du temps de réponse avec un processeur), chaque point sera calculé comme la moyenne des gains (speed-up) de chaque plan. Plus généralement, chaque point d un graphe obtenu avec n mesures, chacune sur un plan d exécution différent, sera calculé grâce à la formule suivante: n TempsRep ( P ) 1 Mesure i -- n ------------------------------------------------------------------ TempsRep ( P ) Reference i Le temps de réponse de référence sera indiqué pour chaque expérimentation. Chaque mesure correspond à la moyenne de 5 mesures successives. 5.2. Répartition locale de la charge i = 1 Afin d étudier les performances de notre modèle d exécution sur un seul noeud- SMP, nous le comparons avec deux autres modèles d exécution puis étudions son

comportement face à des mauvaises distributions de données (data skew). 5.2.1 Comparaison des performances Nous avons donc choisi et réalisé sur la KSR1 deux modèles d exécution bien connus. Le pipeline parallèle synchrone (Synchronous Pipeline ou SP) [She93], est conçue pour une architecture à mémoire partagée. Chaque processeur est multiplexé en deux threads, un pour les entrées/sorties (thread I/O) et un pour les traitements (thread CPU). Chaque thread CPU participe à tous les opérateurs de la chaîne pipeline. Les threads I/O sont utilisés pour lire les relations de bases et placer les tuples dans des buffers. Chaque thread CPU lit alors les tuples de ces buffers et les teste successivement avec les tables de hachage le long de la chaîne pipeline en utilisant des appels de procédures. A moins d une distribution de données très irrégulière (qui pourrait entraîner de grandes variations dans le temps de traitement d un tuple d une relation de base), ce modèle d exécution obtiendra une répartition de charge parfaite. Cependant, SP ne peut être raisonnablement mis en oeuvre sur une architecture distribuée car la redistribution des données entre deux opérateurs successifs entraînerait de haut surcoûts de synchronisation. La deuxième stratégie à été conçue pour des architectures shared-nothing [DeW90][Bor90]. Pour chaque chaîne pipeline, les processeurs sont statiquement alloués aux opérateurs. Le nombre de processeurs pour chaque opérateur est déterminé par le rapport de la complexité estimé de chaque opérateur (coût CPU et I/O) sur la complexité de l intégralité de la chaîne pipeline. Cette stratégie permet d obtenir une assez bonne répartition de charge dans la mesure où le modèle de coût est fiable. Nous avons adapté cette stratégie, dans le cas d une architecture à mémoire partagée, en permettant une redistribution dynamique de la charge de travail au niveau intra-opérateur et l avons appelé Fixed Processing (FP) puisque chaque processeur est assigné à un et un seul opérateur. Cette stratégie à été mise en oeuvre à partir de notre modèle d exécution en restreignant chaque thread au traitement d activations associés à un seul opérateur. Afin de nous comparer à SP et FP, nous avons appelé notre modèle Dynamic Processing (DP) pour refléter le fait que les processeurs sont alloués dynamiquement aux opérateurs de la chaîne pipeline. La Figure 5 compare les performances relatives des trois stratégies en faisant varier le nombre de processeurs et en utilisant une distribution uniforme des données. Le temps de réponse de référence est celui de SP qui est toujours meilleur. Les performances de notre modèle d exécution sont très proches de celles de SP entre 8 et 32 processeurs et un peu moins bonnes avec un plus grand nombre de processeurs. La différence vient des surcoûts d interférences et de gestion des files avec DP. FP est toujours le moins bon à cause des erreurs de partie entière (voir [Wil95]) qui s aggravent lorsque le nombre de processeurs décroît. Les performances de FP dépendent fortement de la précision du modèle de coût utilisé et nous voulions connaître l'impact des erreurs du modèle de coût sur ses performances. La figure 6 montre la dégradation relative des performances lorsque le taux d erreur varie avec différents degrés de parallélisme. Le temps de réponse de référence est ici celui de FP avec un taux d erreurs de 0.

Pour obtenir une mesure avec un taux r% d erreur, la cardinalité des relations de base et intermédiaires ont été modifié par une valeur choisie aléatoirement entre [- r%,+r%], propageant ainsi l erreur dans l estimation du coût des opérateurs et donc du nombre de processeurs alloués. Les mesures ont été effectuées avec un taux d erreurs réaliste entre 0 et 30%. Etant donné le caractère aléatoire de ces mesures, nous avons choisi de restreindre le nombre de plans d exécution testés. Par contre, pour chaque plan, trois taux d erreur ont été choisis aléatoirement. Performances relatives 1.5 1.4 1.3 1.2 1.1 1 0.9 0.8 0.7 0.6 SP DP FP Dégradation relative des performances 2 1.8 1.6 1.4 1.2 1 0.8 0.6 0.4 8 procs 16 procs 32 procs 64 procs 16 32 64 Nb de processeurs 0 5 10 20 30 Taux d erreurs du modèle de coût (%) Les mesures montrent que le temps de réponse se dégrade de manière significative dès que le taux d erreur augmente. Avec peu de processeurs (e.g., 8), la dégradation est petite avec un faible taux d erreurs mais augmente drastiquement avec le taux d erreur. L inexactitude du modèle de coût entraîne l allocation de processeurs en trop pour certains opérateurs. L influence de ces processeurs mal alloués est d autant plus significative qu il y a peu de processeurs (e.g., 1/8 est pire que 1/64). Ainsi, avec un grand nombre de processeurs, un petit taux d erreur modifie le processus d allocation des processeurs mais n a que peu d influence sur les performances. Evidemment, les plus mauvaises performances sont obtenues lorsque peu de processeurs sont alloués aux opérateurs complexe, les autres processeurs étant alloués aux opérateurs plus simples. Cette situation arrive avec un plus ou moins grand taux d erreur suivant le degré de parallélisme. Par exemple, avec 5 opérateurs et 8 processeurs, la plus mauvaise allocation est obtenue lorsque seuls 3 processeurs sont mal alloués, alors qu avec 64 processeurs, il en faut 59!!. Ceci explique la chute de performance vers les 20% d erreurs avec 8 processeurs ainsi que la lente dégradation avec plus de processeurs. Ces mesures confirment les limites de la répartition de charge statique et motivent le besoin d un mécanisme dynamique. Finalement, la figure 7 montre les gains moyens de tous les plans d exécution pour chaque stratégie, avec un taux d erreur nul pour FP. De nouveau, SP est toujours légèrement meilleur que DP, et FP est toujours le moins bon. Jusqu à 32 processeurs, SP et DP obtiennent un gain presque linéaire. La stratégie DP semble donc bien adapté à une architecture hiérarchique qui est typiquement composée de noeud-smp avec moins de 32 processeurs.

5.2.2 Impact des mauvaises distributions de données (data skew). Dans notre modèle, tous les threads ont accès à toutes les files d activations, sources potentielles d interférences. Les surcoûts dus aux interférences augmentent en cas de mauvaises distributions des activations dans les files pouvant provenir de plusieurs formes de data skew [Wal91]. Le skew de valeur d attribut (AVS) et le skew de placement des tuples (TPS) entraînent des variations dans la taille des fragments de relations, menant à une mauvaise distribution des activations dans les files pipeline. Les mesures suivantes ont pour but d étudier les surcoûts dus aux interférences dans notre modèle en cas de data skew. Nous avons introduit du skew de redistribution (RS) dans la production des activations trigger et dans tous les opérateurs produisant en pipeline. Toutefois, le skew d un opérateur producteur n a pas d influence sur le degré de skew du consommateur. Ainsi, la complexité de la requête est indépendante du degré de skew. Tous les opérateurs ont le même degré de skew, modélisé par une fonction de Zipf [Zip49] variant entre 0 (distribution uniforme) et 1 (très fort skew). Speedup 56 48 40 32 24 16 8 1 SP DP FP Dégradation relative des performances 1.3 1.2 1.1 1 DP 1 8 16 32 48 64 Nb de processeurs 0 0.2 0.4 0.6 0.8 1 Degré de skew de redistribution (Zipf) La figure 8 montre la dégradation des performances de DP en fonction du skew avec 64 processeurs. Le temps de réponse de référence est mesuré avec une distribution uniforme. Comme le montre la figure 8, l impact du skew sur notre modèle d exécution est insignifiant. Ceci est dû à plusieurs décisions de conception. Premièrement, notre modèle permet un haut degré de fragmentation qui permet de réduire les effets du skew [Kit90]. Deuxièmement, la priorité donnée à un sous ensemble de files distinctes pour chaque thread (files primaires) permet de réduire les interférences entre les threads. Finalement, les interférences sont encore réduites en bufferisant les lectures et écritures d activations. Nous n avons pu, dans ces mesures considérer toutes les formes de skew. Les mauvaises distributions de données peuvent, par exemple entraîner des temps de traitement variables pour le même type d activations. Cela arrive en cas de skew de valeur des attributs (AVS), de skew de sélectivité (SS) et du skew de produit de

jointure (JPS). Les différences de temps de traitement des activations entraînent aussi la surcharge de files d activations, nous ramenant alors au cas précédent. 5.3. Répartition globale de la charge Notre modèle permet de minimiser l utilisation de la répartition globale de la charge (entraînant des surcoûts de communication) et de favoriser la répartition locale, plus efficace, permettant une répartition inter- et intra-opérateurs. Afin d'évaluer les gains d une telle stratégie dans une architecture hiérarchique, nous l avons comparé à FP, qui donne de bons résultats en shared-nothing. Pour nos mesures, nous avons adapté FP de la manière suivante. Comme chaque opérateur est présent sur tous les noeuds-smp, la répartition des processeurs sur les opérateurs est réalisée indépendamment sur chaque noeud, de la même manière que dans la section 5.2.1 Afin de créer artificiellement des mauvaises répartitions de charge entre les noeuds-smp, nous avons introduit du data skew comme précédemment. Nous avons, tout d abord, comparé le comportement de FP et DP lors de l'exécution d une chaîne pipeline de 5 opérateurs, chacun ayant un degré de skew de redistribution de 0.8. Le système hiérarchique comporte 4 noeuds-smp de 8 processeurs chacun. Nous avons mesuré la quantité de données échangées entre les noeuds avec FP et DP. Pour ces mesures, FP a nécessité l'échange de 9 Mo de données contre 2.5 Mo pour DP. En effet, avec FP, chaque processeur peut être inactif, indépendamment les uns des autres. Comme il n y a pas de répartition de charge dynamique inter-opérateur, un processeur alloué à un opérateur peut être inactif alors qu un autre, sur le même noeud, est surchargé. Le processeur inactif entraîne alors la mise en route de la répartition globale de charge pour prendre du travail à un processeur d un autre noeud alloué au même opérateur. Ainsi, plusieurs situations de famine peuvent se produire sur le même noeud-smp. De plus, il peut y avoir des vols mutuels entre deux noeuds (pour deux opérateurs différents). Avec DP, ces problèmes sont évités puisque lorsqu un processeur est inactif, c est l ensemble du noeud qui est en famine. Comme la répartition de charge se fait au niveau du noeud, et non du processeur, il ne peut y avoir de famines multiples ou mutuelles. Comme dans les expériences précédentes, nous avons aussi effectué des mesures sur 40 plans d'exécution (arbres bushy mettant en jeu 12 relations), avec trois configurations et un degré de skew de 0.6. La figure 9 montre les gains de performances de DP sur FP avec 4 noeuds de 8, 12 et respectivement 16 processeurs. Sur l ensemble de ces exécutions, nous avons observé des gains de performance entre 14 et 39% dus à une utilisation moindre de la répartition globale de charge avec DP ainsi qu aux meilleures performances de DP sur chaque noeud-smp. Les surcoûts de communications dus à la répartition globale de charge sont entre 2 et 4 fois moindres avec DP. De plus les temps d'inactivités des processeurs, quasiment nuls avec DP sont conséquents avec FP. Il faut remarquer que ces mesures ne nous ont pas permis d observer une relation entre le nombre de