Statistiques et montée en charge de votre application web XMLRAD

Jean-Philippe Bempel

Pour suivre l'évolution de votre application en production ou pour diagnostiquer un problème de montée en charge ou de lenteur, XMLRAD vous fournit en standard dans toutes les applications générées des outils précieux de statistiques. Ces outils vont vous permettre d'évaluer la montée en charge de votre application ou de détecter une partie de votre application à optimiser. ♪

- Titre : Statistiques et montée en charge de votre application web XMLRAD

- Auteur : Jean-Philippe Bempel

- Parution : 15 décembre 2005

- Licence : Copyright ® 2005 Jean-Philippe Bempel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- Introduction

- La file de requêtes

- Les écrans de statistiques

- Montée en charge

- Optimisation/Performance counters

- Conclusion

- Liens

Introduction

Pour suivre l'évolution de votre application en production ou pour diagnostiquer un problème de montée en charge ou de lenteur, XMLRAD vous fournit en standard dans toutes les applications générées des outils précieux de statistiques. Ces outils vont vous permettre d'évaluer la montée en charge de votre application ou de détecter une partie de votre application à optimiser.

Nous allons voir dans cet article le fonctionnement de la file de requêtes, les statistiques fournies pour chaque application, comment calculer la montée en charge de votre application et comment optimiser l'exécution.

La file de requêtes

Une application XMLRAD a une file requêtes intégrée permettant de gérer la concurrence d'accès et la distribution des requêtes à traiter. Voici comment est traitée une requête HTTP par l'application :

la requête HTTP est passée du serveur web à l'application (DLL ISAPI, module Apache, Servlet…) qui cherche une XMLCollection libre pour exécuter la requête. Une XMLCollection est l'ensemble des ressources nécessaire à l'exécution d'une requête : XMLModules, XMLServices, Connexion à la base de données. Il peut y avoir une ou plusieurs XMLCollections en parallèle, permettant ainsi l'exécution concurrente de requêtes. Les ressources sont ainsi dupliquées par XMLCollection, évitant ainsi un partage de ces ressources et d'éventuels goulots d'étranglement dans l'exécution dus à la synchronisation d'accès aux ressources partagées. Il ne peut donc s'exécuter qu'une requête par XMLCollection. Si toutes les XMLCollections sont prises, la requête est mise dans une file d'attente jusqu'à qu'une XMLCollection se libère. Si le temps d'attente est trop long (paramétré par XMLC_MaxWaitingTime), la requête est rejetée en TimeOut.

Le Dashboard est un écran permettant de visualiser en temps réel les requêtes s'exécutant dans les XMLCollctions et celles en attentes dans la file de requêtes. Vous pouvez y accéder via l'action XMLC_Dashboard ou le portail d'administration XMLC_AdmPortal.

Dans l'exemple ci-dessus, il y a deux requêtes en exécution dans les XMLCollections, donc toutes autres requêtes sont stockées dans la file en attente de distribution.

Si vous avez un processus long et que vous voulez suivre sa progression dans le Dashboard, utilisez les méthodes Stack/Unstack de l'objet XMLRequest (cf. Appendix 12 : Programmer's reference). Exemple :

Delphi

var
I: Integer;
begin
XMLRequest.Stack('MyProcess');
for I := 1 to 1000 do
begin
XMLRequest.Stack(IntToStr(I)+'/1000');
// Long process
XMLRequest.Unstack;
end;
XMLRequest.Unstack;
end;

JScript

XMLRequest.Stack("MyProcess");
for (i = 1; i <= 1000; i++)
{
XMLRequest.Stack(i+"/1000");
// Long process
XMLRequest.Unstack();
}
XMLRequest.Unstack();

C#

XMLRequest.Stack("MyProcess");
for (int i = 1; i <= 1000; i++)
{
XMLRequest.Stack(i.ToString()+"/1000");
// Long process
XMLRequest.Unstack();
}
XMLRequest.Unstack();

Java

xmlRequest.stack("MyProcess");
for (int i = 1; i <= 1000; i++)
{
xmlRequest.stack(i.toString()+"/1000");
// Long process
xmlRequest.unstack();
}
xmlRequest.uUnstack();

Ainsi, le suivi du processus apparait dans la colonne à droite avec la pile d'appels (cf. capture ci-dessus).

Les écrans de statistiques

Une application XMLRAD intègre des écrans de statistiques permettant de connaitre avec précision le temps mis par chaque XMLModule, XMLService, XMLInstruction ou gestionnaire d'événements

Dans l'écran de statistiques principal, on retrouve les temps de l'application. Les colonnes sont organisées toujours de la même façon :

- Avg : temps moyen par requête ;

- Req : nombre de requêtes ;

- CPUTime : temps cpu cumulé ;

- MinCPU : temps minimal d'une requête ;

- MaxCPU : temps maximal d'une requête ;

- LasstCPUTime : temps de la dernière requête.

Dans les statistiques globales (XMLApplication) sont compris :

- Client upload : lorsque l'on uploade un fichier sur le serveur ;

- stream response : envoi du flux HTML au client ;

- Initialize : temps d'initialisation de l'application à la première requête.

Par pool on retrouve :

- Threads : nombres de threads ou de XMLCollections ;

- Overhead : temps avant distribution de la requête ;

- Wait : temps d'attente moyen des requêtes avant exécution.

Dans les statistiques du pool, on retrouve les temps des événements BeforeDispatch, OnAuthenticate, OnAuthorize et AfterDispatch, ainsi que la répartition par XMLModule.

Dans les statistiques du XMLModule, on retrouve la répartition des temps par XMLService et Query.

Dans les statistiques du XMLService, on retrouve les temps d'exécution globaux du XMLGram (temps moyen, nombre de requêtes et dernière exécution) ainsi que la répartition des temps par Instruction et gestionnaire d'événement. Les StandardParams correspondent au temps de construction et d'ajout dans le document OutputDoc des XMLC_Params, Locales et XMLC_Profile. Le XSL correspond au temps de transformation de la grappe XML en HTML.

Pour chaque XMLInstruction nous avons aussi la répartition des fetchs effectués (essentiellement pour le DBExtract) :

- Count : nombre de fetches ;

- Avg : temps moyen d'un fetch ;

- PerReq : temps moyen des fetches par requête.

Montée en charge

Avec tous les outils fournis par XMLRAD, comment puis-je prévoir la montée en charge de mon application XMLRAD ? Est-ce que je suis capable de servir 50 ? 100 ? 200 ou plus d'utilisateurs ?

Le nombre de XMLCollections (ou le nombre de threads) indique combien de requêtes vont pouvoir être traitées en concurrence puisque l'on n'a qu'une requête traitable par XMLCollection. Si on augmente le nombre de XMLCollection, on pourra traiter autant de requêtes concurrentes.
Cependant, par processeur (et maintenant par cœur) il ne peut s'exécuter qu'un seul thread (ou XMLCollection) à la fois. Si l'on multiplie les threads, le système d'exploitation devra changer le thread qui s'exécute sur le processeur plus souvent. Or, ce changement a un coût et dépassé un certain nombre de threads le processeur passe plus de temps à changer de contexte d'exécution de thread qu'à exécuter le code lui-même. Il n'est donc pas pertinent d'augmenter le nombre de XMLCollections qui ne ferait que ralentir l'exécution globale de toutes les requêtes.
Il est en fait intéressant de limiter le nombre de XMLCollection à une par processeur, plus une additionnelle. Ce qui donne sur une architecture monoprocesseur deux XMLCollections, sur un biprocesseur ou « dual core », trois XMLCollections, et ainsi de suite.

Dans les configurations où la base de données est sur une autre machine que le serveur web, il est envisageable d'augmenter le nombre de XMLCollections, car la majorité du temps de traitement sera d'attendre les résultats de la base de données et le transfert réseau.

Supposons qu'en moyenne vos requêtes soient traitées en 100 ms par votre application. On peut donc traiter 10 requêtes par seconde sur une architecture monoprocesseur et le double pour un biprocesseur ou « dual core ».
Maintenant il faut aussi prendre en compte que l'utilisateur n'envoie pas des requêtes en permanence et qu'il doit prendre le temps de lire la page résultante de sa requête par exemple. En fonction de votre application, à vous de fixer le nombre de secondes entre chaque requête. Si on prend par exemple 20 secondes entre chaque requête, l’application va pouvoir servir 200 utilisateurs en simultané.
Il faut aussi prendre en compte que l'utilisateur n'envoie pas de façon permanente toutes les 20 secondes une requête et qu'elles sont réparties sur le temps de travail. Le nombre de 200 utilisateurs n'est donc pas une limite, mais au-delà les temps de réponse peuvent devenir plus longs dans la limite du temps d'attente maximum dans la file de requêtes (XMLC_MaxWaitingTime).

Si maintenant vous arrivez dans votre application à réduire le temps moyen à 80 ms par exemple, vous pouvez maintenant absorber 1000 / 80 * 20 = 250 utilisateurs. En gagnant 20 ms de temps moyen, on a gagné 50 utilisateurs.
Il est clair que plus les requêtes seront traitées rapidement plus vous allez pouvoir gérer d'utilisateurs sur un même serveur.

Optimisation/Performance counters

D'après nos calculs de montée en charge, il est finalement très important d'arriver à optimiser le temps de traitement des requêtes pour pouvoir gérer plus d'utilisateurs sur un même serveur. Grâce aux écrans de statistiques vous allez pouvoir déterminer quels sont les XMLServices qui consomment le plus de temps.
En zoomant sur ces XMLServices, vous allez pour chaque requête SQL évaluer si le temps de traitement de cette requête est convenable ou non. Si par exemple une requête qui ne récupère qu'un seul enregistrement met près de 500 ms à s'exécuter, il y a de fortes chances pour qu'il manque des index sur les champs ou que les jointures ne soient pas executées dans le bon sens.
On peut aussi envisager de mettre certaines requêtes en cache par exemple les listes de référence qui ne sont pas susceptibles de changer fréquemment comme la liste des pays.

À d'autres endroits, ce sera les gestionnaires d'événements qui prendront trop de temps. Une révision du code de ces gestionnaires s'impose. Mais les écrans de statistiques s'arrêtent là, et nous n'avons pas une mesure plus fine de ce qui pourrait prendre du temps dans le traitement d'un gestionnaire d'événement.
Pour affiner vos mesures, vous pouvez utiliser les méthodes StartPerformanceCounter/EndPerformanceCounter de l'objet XMLCollection (cf Appendix 12: Programmer's reference).
Exemple:

Delphi

begin
XMLCollection.StartPerformanceCounter('MyProcess');
try
// Long process
finally
XMLCollection.EndPerformanceCounter;
end;
end;

JScript

XMLCollection.StartPerformanceCounter("MyProcess");
try
{
// Long process
}
finally
{
XMLCollection.EndPerformanceCounter();
}

C#

XMLCollection.StartPerformanceCounter("MyProcess");
try
{
// Long process
}
finally
{
XMLCollection.EndPerformanceCounter();
}

Java

xmlCollection.startPerformanceCounter("MyProcess");
try
{
// Long process
}
finally
{
xmlCollection.endPerformanceCounter();
}

Dans les statistiques il y a un onglet Perf permettant de lister tous les performance counters que vous avez pu mettre dans le code.

Conclusion

Nous avons vu dans cet article le fonctionnement de la file de requêtes avec l'écran permettant de suivre en temps réel les requêtes, les écrans de statistiques, comment calculer la montée en charge de votre application et comment l'optimiser.

Les outils que XMLRAD met à votre disposition pour toutes applications vous permettent de diagnostiquer les problèmes de performances et de vous aider dans les calculs de montée en charge de votre application. Vous pouvez ainsi suivre même en production l'évolution des applications.

Liens

- Appendix 12 : Programmer's reference