Précédent : Présentation générale et
objectifs Remonter : Projet SOLIDOR, Construction de systèmes
Suivant : Grands domaines
d'application
Résumé : Les travaux de recherche du projet Solidor s'articulent autour de la construction de systèmes d'exploitation distribués. Un système d'exploitation distribué, ou plus simplement système distribué, peut être succinctement défini comme un logiciel complexe permettant de coordonner l'exécution d'applications au-dessus d'une architecture distribuée donnée. Les principes sur lesquels s'appuie la construction d'un tel système sont par conséquent de deux ordres :
- les principes nécessaires à la maîtrise de la complexité du système et en particulier pour pouvoir raisonner sur son comportement. Dans ce cadre, nous nous appuyons plus spécifiquement sur la notion d'architecture logicielle qui permet de décrire de manière abstraite l'organisation d'un système logiciel et ainsi d'exploiter des méthodes formelles pour spécifier le comportement des différents éléments du système.
- les principes relatifs à la construction du système lui-même, c'est-à-dire, son organisation particulière eu égard aux contraintes des applications visées et de l'architecture distribuée sous-jacente. L'objectif est ici de proposer une solution à la réalisation de fonctions de gestion de la distribution permettant de respecter des contraintes de nature temporelle ou encore de sûreté de fonctionnement.
Le domaine des architectures logicielles est apparu au début des années 90 et consiste à promouvoir le développement de systèmes logiciels à partir de la définition de leur architecture. Une architecture logicielle décrit abstraitement l'organisation d'un système en terme d'interconnexion de composants caractérisant des unités de calcul ou de stockage, via des connecteurs caractérisant les protocoles d'interaction entre composants. Un avantage de cette approche est qu'en faisant abstraction des détails de mise en oeuvre du système, elle permet d'appréhender plus simplement le comportement du système. En particulier, elle rend viable l'utilisation de méthodes formelles pour la spécification du comportement de systèmes complexes, et des outils associés pour la vérification automatique de propriétés sur les architectures.
De nombreux travaux complémentaires sont actuellement en cours sur la spécification formelle du comportement d'une architecture. Nous pouvons les distinguer suivant les propriétés de l'architecture qui sont privilégiées : (i) les propriétés invariantes de l'architecture en fonction de son organisation, (ii) les propriétés fonctionnelles qui relèvent du comportement des composants, (iii) les propriétés d'interaction qui relèvent du comportement des protocoles de communication (ou connecteurs), et (iv) les propriétés non-fonctionnelles qui ont trait aux fonctions de gestion de ressources, mises en oeuvre de manière transparente par le système d'exécution sous-jacent (e.g. disponibilité, performance, sécurité).
Dans le cadre de la spécification des propriétés invariantes d'une architecture, l'objectif est ici d'une part, de faciliter l'implantation correcte d'une architecture par raffinement et, d'autre part, de promouvoir la ré-utilisation de conceptions de systèmes en caractérisant une famille d'architectures (ou style) qui peut ensuite être exploitée pour développer une architecture particulière exhibant les mêmes caractéristiques. Différentes méthodes de spécification sont utilisées dans ce contexte, citons la logique du premier ordre, le formalisme Z, le modèle CHAM ou encore les grammaires de graphe.
La spécification des propriétés fonctionnelles d'une architecture permet de vérifier la correction d'une interaction entre deux composants au regard du comportement de l'action découlant de cette interaction. Elle permet en outre de spécifier le comportement global (du point de vue des propriétés fonctionnelles) de l'architecture en fonction de celui de chacun de ses composants et de leurs interconnexions. Un autre avantage de la spécification de propriétés fonctionnelles est qu'elle peut être exploitée pour la recherche automatique de composants à partir de leur spécification, et promeut ainsi la ré-utilisation de logiciels. La méthode de spécification formelle utilisée dans ce cadre s'appuie sur la logique de Hoare. Remarquons ici que les propriétés spécifiées sont utilisées pour vérifier la validité de l'interconnexion de composants et non la correction d'une mise en oeuvre pour une spécification donnée. Ceci rend ainsi praticable l'emploi d'outils pour une automatisation des processus de vérification ou de recherche.
La spécification des propriétés d'interaction d'une architecture vise les vérifications de correction de l'architecture compte tenu des protocoles de communication attendus par les composants et de ceux effectivement implantés par le système de communication utilisé. Elle permet ainsi de vérifier la validité des interconnexions de composants via les connecteurs ou encore la satisfaction de propriétés globales comme l'absence d'interblocage. La méthode de spécification retenue est une algèbre de processus fondée sur CSP, ce qui permet d'utiliser l'outil FDR pour l'automatisation des vérifications.
La spécification de propriétés non-fonctionnelles a fait l'objet de très peu d'attention dans la communauté des architectures logicielles. Les quelques travaux qui abordent ce type de propriétés traitent soit les performances à l'exécution, soit la sécurité du système logiciel. Toutefois, la prise en compte des propriétés non-fonctionnelles est cruciale lorque l'on considère la construction de systèmes (d'exploitation) distribués puisqu'il s'agit de propriétés inhérentes à ces systèmes. Aussi, les travaux de recherche du projet Solidor dans ce cadre se concentrent sur la spécification de propriétés non-fonctionnelles de différente nature. La méthode de spécification proposée s'appuie sur la logique du premier ordre. Cette solution nous permet d'appréhender le raffinement d'architectures logicielles du point de vue de la réalisation de propriétés non-fonctionnelles. Par ailleurs, du fait de la forme particulière des propriétés non-fonctionnelles, nous sommes à même de fournir des outils d'aide au raffinement d'architectures et de recherche de composants implantant des fonctions de gestion de ressources pour effectivement réaliser une propriété non-fonctionnelle.
Suivant la définition d'un système distribué, la construction d'un tel système se fait en fonction du (ou des) domaine(s) d'application(s) et de l'architecture distribuée sous-jacente, ceci afin de respecter les contraintes non-fonctionnelles de l'application et de fournir des performances à l'exécution optimales. Si la construction d'un système distribué propriétaire ne partant d'aucune base existante était envisageable par le passé, ceci n'est aujourd'hui plus concevable en raison du coût financier en résultant, de la nécessité de supporter des logiciels du commerce, ou encore de l'hétérogénéité du matériel. Dans ce cadre, l'adéquation du système avec les applications visées ne peut être obtenue que par adaptation, ou spécialisation, d'une base système existante comprenant les noyaux de systèmes d'exploitation des machines de l'architecture et les protocoles de communications standards (e.g. TCP/IP).
La spécialisation apportée par un système distribué peut être plus ou moins fine suivant le type du noyau de système d'exploitation considéré. Celui-ci détermine jusqu'à quel degré les politiques de gestion de ressources de base peuvent être modifiées. Le type de noyau le moins flexible est le noyau monolythique comme par exemple UNIX. Dans ce cas, la gestion de ressources est totalement figée et la spécialisation du système se fait suivant la technologie middleware qui consiste à implanter un ensemble de composants logiciels (ou services) entre l'application et le noyau. Une flexibilité accrue est fournie par la technologie micro-noyau (e.g. CHORUS, MACH). Dans ce cas, chaque gestionnaire de ressources est encapsulé dans un serveur caractérisé par une interface. La modification d'une politique de gestion de ressources se fait alors par la réécriture du corps du serveur. Enfin, le type de noyau le plus souple est le nano-noyau, comme SPIN ou EXOKERNEL, qui permet de revoir l'ensemble des politiques de gestion de ressources. Toutefois, les nano-noyaux, proposés au milieu des années 90, relèvent encore principalement du domaine de la recherche et ne sont que très peu utilisés. Il est évident que plus le noyau est flexible, plus la spécialisation du système distribué peut-être affinée. Toutefois, le choix du noyau ne relève que rarement du concepteur de système distribué, celui-ci est imposé par les applications et le possible accès au code source du noyau. Par exemple, les applications grand public obligent une spécialisation suivant la technologie middleware. En revanche, les applications embarquées permettent voire obligent une spécialisation à partir d'un micro ou nano-noyau.
Les travaux de recherche du projet Solidor dans ce domaine se concentrent sur la spécialisation de systèmes distribués à partir de noyaux de systèmes d'exploitation du commerce c'est-à-dire de noyaux monolythiques (UNIX et WINDOWS-NT) ou de micro-noyaux (CHORUS). Dans ce contexte, nous examinons des solutions à la réalisation de la gestion des interactions ainsi qu'au respect des contraintes non-fonctionnelles fortes des applications. La gestion des interactions repose principalement sur la mise en oeuvre d'un protocole de communication distribué par mémoire partagée ou par échange de messages. Les contraintes non-fonctionnelles d'une application se subdivisent en contraintes de :
Notons que nous avons omis une contrainte, souvent forte des applications, qui est la sécurité-confidentialité du système. En effet, nos travaux dans ce domaine s'appuient sur l'utilisation de solutions existantes.
Le respect de contraintes de disponibilité, fiabilité ou de sécurité-inocuité s'appuie principalement sur l'emploi de techniques de tolérance aux fautes. Dans le cas des contraintes de disponibilité, il s'appuie également sur l'emploi de techniques utilisées pour l'optimisation de performance. Nous donnons un aperçu des techniques de tolérance aux fautes dans le paragraphe suivant. Nous présentons ensuite les principes de construction de système, utilisés pour fournir des garanties de temps-réel aux applications, puis pour optimiser les performances à l'exécution des applications.
Pour tolérer la défaillance d'une action (ou processus) tout en assurant la continuité de service, le seul moyen est de la répliquer en n, n>=2, exemplaires sur n machines distinctes. Deux stratégies de réplication sont applicables :
Enfin, ces deux stratégies de réplication s'accompagnent obligatoirement d'un mécanisme d'échange atomique d'information entre les processus, propriété indispensable à la construction d'un système tolérant aux fautes.
Nous identifions deux grandes classes de contraintes temporelles pour les applications : (i) les contraintes temps-réel dur où le système doit impérativement garantir le respect des échéances pour l'exécution des actions et (ii) les contraintes temps-réel mou où le système doit garantir le respect d'échéances pour l'exécution des actions mais ces échéances peuvent éventuellement être modifiées lorsqu'un fonctionnement dégradé est toléré pour l'application. Les contraintes temps-réel dur sont typiquement les contraintes inhérentes aux applications à sûreté critique. Le système doit ici satisfaire une exigence de promptitude en raison des temps de réponse typiques exigés : de 1 ms à 100 ms suivant le type d'application considéré. Un exemple typique d'applications ayant des contraintes temps-réel mou est les applications multimédias à flux de données continus. Le système doit assurer le respect de contraintes temporelles dans la délivrance des flux de données afin de garantir la qualité des images et du son. Toutefois, les contraintes imposées peuvent être adaptées puisque la qualité des données tolère une dégradation qui ne sera que faiblement perçue par l'utilisateur. Les paragraphes suivants indiquent les principes système, employés pour satisfaire respectivement les contraintes temps-réel dur et mou.
La satisfaction de contraintes temps-réel dur s'appuie conjointement sur une technique de compilation particulière des applications et l'utilisation d'un noyau de système d'exploitation, dit temps-réel. Un système temps-réel a la responsabilité de produire des résultats corrects tout en respectant des échéances dans la production de ces résultats. La correction temporelle, c'est-à-dire l'aptitude à respecter des échéances, dépend de deux facteurs : (i) la connaissance des exigences en termes de ressources et la durée d'exécution de l'application, (ii) la disponibilité des ressources de la plate-forme d'exécution au moment de l'exécution, où le terme ressource recouvre le matériel (e.g. les processeurs), le logiciel (e.g. les serveurs) et les données (e.g. les entrées). Le premier facteur repose sur une prédiction à partir de l'analyse statique de l'application et de la connaissance des temps d'exécution des fonctions du système. Le second facteur est fortement dépendant de la charge du système. Sa satisfaction repose sur deux solutions complémentaires : (1) le calcul statitique, à partir de la connaissance des exigences de l'application, d'un ordonnancement de l'ensemble des tâches ayant des contraintes temps-réel, et (2) la mise en oeuvre d'un algorithme d'ordonnancement qui privilégie l'exécution des tâches à contraintes temps-réel par rapport à celle des autres tâches.
Les contraintes temps-réel mou ont pour particularité de tolérer le non respect de certaines échéances lors de l'exécution des tâches. Cette tolérance est acceptée car les applications concernées ne relèvent pas du domaine des applications à sûreté critique. Le comportement erroné du système du point de vue des contraintes temps-réel n'a par conséquent pas d'incidence grave sur l'application. Deux solutions existent pour satisfaire des contraintes temps-réel mou :
Le choix pour l'une ou l'autre solution dépend des applications et de l'environnement d'exécution. Par exemple, une application s'appuyant sur Internet reposera sur une dégradation de la qualité de service. En revanche, un service commercial de vidéo à la demande par cable devra s'appuyer sur une réservation de ressources.
Notons enfin que pour les deux solutions préconisées et à l'instar des systèmes garantissant le respect de contraintes temps-réel dur, le système implante dans tous les cas une politique d'ordonnancement des tâches qui privilégie l'exécution des tâches ayant des contraintes temps-réel, par rapport aux exécutions des autres tâches. De même, les temps d'exécution associés aux différentes fonctions du système doivent pouvoir être bornés dans le cas d'une politique de réservation de ressources.
L'optimisation des performances à l'exécution des applications repose sur une répartition optimale de la charge entre les différents éléments de l'architecture distribuée. Deux approches complémentaires existent : (i) l'emploi de techniques de répartition de charge (mémoire ou calcul) en fonction de la charge du système et de l'application, et (ii) l'anticipation des appels aux fonctions du système de manière à ne pas attendre le moment de ces appels pour les exécuter.
Les stratégies de répartition de charge peuvent être statiques ou dynamiques. Les stratégies statiques sont adaptées aux environnements de programmation parallèle où il est possible d'allouer statiquement un ensemble de processeurs à une application. En revanche, elles ne peuvent être retenues pour les environnements d'exécution distribuée où les ressources sont partagées entre des applications indépendantes. Une stratégie de répartition de charge dynamique est par conséquent employée pour les environnements distribués. Une telle stratégie est définie en termes de trois politiques complémentaires :
De manière générale, une politique d'anticipation des accès a pour objectif de minimiser le temps d'accès à des données distantes en préchargeant les données préalablement à la requête d'accès effective. La réalisation d'une politique d'anticipation repose sur :