jeudi 17 février 2011

Suivi de la consommation (et donc du cout) d’un rôle Windows Azure

La question fatidique avant adoption de Windows Azure est bien sûr de savoir combien l’hébergement dans le cloud va couter concrètement. L’état actuel des APIs de Windows Azure ne permet pas de répondre directement à cette question.

La méthode la plus simple pour déterminer la consommation des instances déployées dans le cloud, et donc d’en déduire le cout, est d’utiliser l’API de diagnostic de Windows Azure, qui permet (entre autres) d'utiliser des compteurs de performance. Il faut donc déterminer les compteurs à utiliser et parvenir à configurer la production automatique des données de diagnostic. L’exemple suivant montre comment configurer un Web Role pour qu’il enregistre automatiquement et périodiquement le nombre total d’octets sortants de toutes les instances du rôle :

public override bool OnStart()
        {
            DiagnosticMonitorConfiguration diagnosticMonitorConfiguration = DiagnosticMonitor.GetDefaultInitialConfiguration();
            PerformanceCounterConfiguration performanceCounterConfiguration = new PerformanceCounterConfiguration();
            performanceCounterConfiguration.CounterSpecifier = @"\Applications ASP.NET(__Total__)\Total de demandes sortantes en octets";
            performanceCounterConfiguration.SampleRate = TimeSpan.FromSeconds(10);
            diagnosticMonitorConfiguration.PerformanceCounters.DataSources.Add(performanceCounterConfiguration);
            diagnosticMonitorConfiguration.PerformanceCounters.ScheduledTransferPeriod = TimeSpan.FromMinutes(1.0);
            CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(RoleEnvironment.GetConfigurationSettingValue("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString"));
            DiagnosticMonitor.Start(cloudStorageAccount, diagnosticMonitorConfiguration);
            return base.OnStart();
        }



Au bout d’une minute (comme configuré dans le code), la table WADPerformanceCountersTable est créée :


image


Elle contient bien les données du compteur de performance :


image


On remarque aisément que le Role écrit dans la table toutes les minutes, en insérant à chaque fois 6 enregistrements, étant donné que SimpleRate a été défini à 10 secondes.


En staging ou en production, les noms des compteurs de performance sont logiquement en Anglais. On pourra utiliser ASP.NET Applications(__Total__)\Request Bytes In Total et ASP.NET Applications(__Total__)\Request Bytes Out Total à la place.


Etant donné que les données sont dans une Table Azure, un simple mécanisme de filtrage OData et des calculs simples permettent de déduire le cout quotidien ou mensuel en fonction des tarifs Azure.


A noter également : les mêmes compteurs permettent de connaitre la consommation en bande passante de n’importe quel site, afin de prévoir le cout potentiel avant une migration dans le cloud.

samedi 5 février 2011

List et LinkedList

N’importe quel cours théorique abordant les structures de données informatiques présente 2 manières fondamentales de considérer un ensemble d’éléments homogènes : le tableau ou la liste chaînée. Le tableau place les éléments de façon contiguë en mémoire :

image

De telle sorte que le tableau lui même soit représenté par la référence mémoire “r” vers le premier élément du tableau. L’accès à un élément à un indice donné “i” du tableau est extrêmement simple, puisqu’il suffit de calculer l’adresse r + i*(taille d’un élément du tableau). Ainsi, les tableaux sont particulièrement adaptés au stockage de données ayant une taille fixe et au parcours séquentiel du tableau, ce qui convient à la plupart des cas. Néanmoins, les tableaux sont immutables, ce qui veut dire que leur taille ne peut pas être modifiée après création. Autrement dit, toute opération de modification de la taille d’un tableau ne peut être effectuée qu’en créant un autre tableau avec la nouvelle taille, en copiant les données de l’ancien tableau vers le nouveau et en détruisant l’ancien.

En revanche, avec la liste chaînée, les adresses mémoire de chaque élément sont indépendantes :

image

Chaque élément de la liste contient ses propres données et des références vers l’élément suivant et l’élément précédent. La création d’une liste chaînée est moins rapide que la création d’un tableau puisqu’il faut réaliser toutes les associations entre les éléments successifs. Le parcours est également moins rapide car il faut accéder à des zones mémoires qui ne sont pas forcément adjacentes. Cependant, dans tous les cas où on a besoin d’une structure de données souple, dynamique, supportant de nombreuses opérations d’insertion et de suppression notamment, la liste chaînée sera plus adaptée.

En C#, il est assez étonnant de constater que List<T> est le type choisi sans aucune réflexion préalable la plupart du temps. La classe List<T> manipule en interne un tableau simple :

image

Elle a donc les mêmes avantages et les mêmes inconvénients que le tableau. Par exemple, lors de la méthode Add utilisée généralement à outrance, un appel à EnsureCapacity :

image

Modifie la Capacity du tableau interne :

image

Ce qui entraîne une recopie du tableau interne dans un tableau plus grand si la capacité du tableau initial est dépassée :

image

En d’autres termes, List<T> n’est qu’une classe permettant de manipuler un tableau monodimensionnel de façon aisée.

Le Framework .NET contient néanmoins une implémentation d’une véritable liste chaînée matérialisée par la classe LinkedList<T>, et de chaque noeud par la classe LinkedListNode<T>. Contrairement à ce que ce nom pourrait faire penser, LinkedList<T> n’hérite pas de List<T> ni même de IList ; il n’y a pas d’indexeur, peu de méthodes disponibles, mais il s’agit tout de même une structure souple permettant de manipuler un ensemble de données homogènes.

Le choix entre une List et une LinkedList peut ne pas être trivial, en particulier lorsque des contraintes de performance sont exprimées. Il convient donc, au quotidien, pour le développeur .NET, de veiller à une utilisation adéquate de List<T>.