jeudi 1 décembre 2011

Pool de connexion

Ces derniers temps, j'ai travaillé sur les pools de connexion ( pool client, pool serveur de type MTS ) . En particulier, j'ai repris le prototype de pool client présenté dans un message précédent et vite touché ses limites. Lorsque je l'ai utilisé en lien avec un pool serveur de type MTS, j'ai rencontré des erreurs ORA-3113 ( perte de connexion ) lorsque j'augmentais la charge du client en terme de processus concurrents. Losque je l'employais plus classiquement en utilisant des sessions de type dedicated, les erreurs ORA-3113 cessaient, mais des erreurs ORA-1000 ( trop de curseurs ouverts pour une session, vue v$open_cursor ) survenaient malgré une gestion correcte du curseur.

Suite à l'instabilité de mon prototype, j'ai décidé de le faire évoluer en suivant les exemples de la documentation PRO*C sur la gestion des applications utilisant des threads ( chapitre 11 ).  J'ai donc remplacé les processus par des threads; le segment de mémoire partagé est devenu inutile, le contexte de session étant passé en paramètre de la fonction pthread_create. Par rapport au prototype initial, il manque l'acquisition d'une connexion dans le pool avant l'exécution de la requête . Pour ce faire, on peut définir le pool de sessions en tant que variable globale afin qu'il soit partagé par tous les threads et le protéger via des mutex, l'équivalent des sémaphores pour les threads.

Une fois ces modifications effectuées, j'ai pu monter en charge avec un pool serveur de type MTS ou sans pool serveur sans déclencher les erreurs ORA du précédent programme.

Le source et les objets associés ( makefile, sqlnet.ora, tnsnames.ora, variables d'environnement ) sont disponibles dans ce répertoire.

Ce type de pilote permet de mettre en évidence des latences sur les différentes parties d'une architecture client/serveur:
- Client ( = zone Solaris 10 ): capping cpu insuffisant, débit de la carte éthernet à augmenter;
- Réseau ( = TCP/IP ): latence réseau excessive, effet de congestion si réseau non dédié ( snoop ou sonde => OPNET );
- Serveur ( = partition AIX + instance Oracle 10.2 ): paramétrage du MTS à revoir ( dispatcher, shared server ), SDU à optimiser.

Si vous effectuez un truss sur ce type de client ( programme PRO*C + client oracle ), vous allez observer les appels systèmes des sockets TCP ( socket, connect, read/write, close ). En s'appuyant sur les exemples du livre TCP/IP Sockets in C: Practical Guide for Programmers, on peut écrire un client/serveur de type TCP et avoir ainsi une idée de la qualité du réseau en terme de performance.

Exemple d'un client TCP incluant un pool de socket et d'un serveur TCP de type écho.

Si vous recherchez une durée d'exécution constante des requêtes de l'ordre de 10 ms ou moins, il est alors nécessaire d'envisager une autre solution que celle proposée par un SGBD classique ( client, socket TCP, instance, baie de disques ) et vous orienter par exemple vers un système mémoire ( client, cache mémoire, socket TCP, instance, baie de disques ). Dans cet ordre d'idée, Timesten peut être une solution à tester.