Après avoir rencontré quelques anomalies dans la gestion de ISM sous Solaris x86 (voir l'analyse du bug), nous allons étudier la manière de le contourner. Pour rappel le bug est le suivant : non partage de la table de pages en ISM. Les workarounds mis en oeuvre ici concernent uniquement les bases de données Oracle. Cependant certains d'entre eux peuvent vous aider à adresser ce type de problème dans contextes différents. Je remercie Alain et Thierry (consultants Oracle) pour l'aide apportée sur la mise en place de ces workarounds (notamment sur la partie Oracle base de données).
Ce bug a toujours existé dans Solaris 10x86, et pourtant personne ne l'a remarqué. Et pourquoi donc !? Il faut deux éléments pour qu'il devienne visisble sur le système :
- Une taille de ISM importante (supérieur à 80 Go environ)
- Une multitude d'attachements / détachements à cette ISM
Sans ces deux conditions, le dysfonctionnement n'est pas impactant pour le système (la consommation du serveur n'est pas affectée par des Spin locks provenant du bug). Il y a deux manières de controurner ce problème :
- La taille de l'ISM
- Diminuer le nombre d'attachements / détachements
Diminuer la taille de l'ISM va un peu à l'encontre de l'histoire !! Possédant des serveurs de plus en plus capacitifs (512 Go de RAM voir plus maintenant), et ne pas en profiter pleinement, c'est un peu ridicule. Une approche plus constructive serait de découper le segment ISM par plusieurs segments de plus petites tailles. Solaris a bien des qualités mais ne posséde malheuresement pas celle de découper un segment ISM (à l'inverse de Linux : voir shmmax et shmall).
Reste que le monde informatique est bien fait !! L'architecture des serveurs x86 (je parle des serveurs produits actuellement) fonctionne en utilisant le schéma mémoire NUMA. Pour simplifier, le temps d'accès à la mémoire dépend de sa localisation par rapport aux processeurs. Solaris utilise pleinement ces fonctionnalités à travers les locality groups (lgrp). La mémoire est implicitement découpée par le système Solaris. La base de données Oracle est capable de découper son segment de mémoire partagée sur les différents locality groups disponibles sur le serveurs. Quand je vous disais que le monde informatique était bien fait !! Il s'agit d'activer une option lors du démarrage de la base de données.
L'autre approche est de limiter le nombre d'attachements / détachements. Même si diminuer le nombre d'utilisateurs reste une solution, je ne vous la conseille pas !! Par contre utiliser les fonctionnalités d'Oracle base de données nous permet de répondre à ce besoin. Il s'agit d'utiliser soit la fonctionnalité de Shared Server soit la fonctionnalité de Database Resident Connection Pooling. La dernière fonctionnalité étant disponible en version 11g.
Le protocol de tests est assez simple : lancement de 50 connexions simultanées (via sqlplus). Chaque sqlplus provoque une connexion / déconnexion à la base toutes les 2 secondes. L'activité du système est surveillée par la commande vmstat, les locks (et leurs temps) sont tracés avec un petit script Dtrace. Tous les tests ont été réalisés avec une SGA de 200 Go et 25 Go de shared pool.
Résultats obtenus :
Cas 1 : Reproduction du problème
Paramétrage | Aucun |
Durée des 50 connexions | 2m16s |
Charge CPU | Saturé en mode Système |
Nombre de locks Spin et Block | Des milliers de Spin et Block |
Temps des locks Spin | Spin de quelques ms à 700ms |
Temps des locks Block | Block de quelques ms à plusieurs milliers de ms |
Cas 2 : Utilisation de NUMA
Paramétrage | Activation de NUMA |
Durée des 50 connexions | 32s |
Charge CPU | 60% en mode système - 5% en mode user |
Nombre des locks Spin et Block | Des milliers de Spin et Block |
Temps des locks Spin | Spin inférieur à 1ms |
Temps des locks Block | Block compris entre 10ms et 100ms |
Remarques :
- 4 lgrps disponibles sur le serveur
- 3 segments ISM de 50 Go + 1 segment ISM de 75 Go (50 Go de SGA et 25 Go PGA)
- 1 segment ISM de quelques Mo pour la gestion des 4 autres segments
Cas 3 : Utilisation de Data Resident Connection Pooling dans Oracle
Paramétrage | Activation du Data Resident Connection Pooling |
Durée des 50 connexions | 26s |
Charge CPU | Inférieur à 5% en mode système et user |
Nombre des locks Spin et Block | Quelques appels lors de la création des processus de pool |
Temps des locks Spin | Quelques nanosecondes |
Temps des locks Block | Aucun |
Remarques :
- Lors du test, un hang non expliqué est apparu
- Les limitations fonctionnelles de connexions au même schéma sont à valider par l'applicatif
Cas 4 : Utilisation de Shared Server
Paramétrage | Activation des Shared Server |
Durée des 50 connexions | 24s |
Charge CPU | Inférieur à 5% en mode système et user |
Nombre des locks Spin et Block | Quelques appels lors de la création des processus de pool |
Temps des locks Spin | Quelques nanosecondes |
Temps des locks Block | Aucun |
Remarques :
- Quelques ajustements à faire : nombre de serveurs, large pool, taille de la UGA
- Fonctionnalités présentes depuis plusieurs versions d'Oracle base de données
Les 3 workarounds présentés ici permettent d'augementer la taille de la SGA de votre base Oracle sur Solaris x86 sans saturer votre système. Les fonctionnalités présentes dans Oracle (Data Resident Connection Pooling et Shared Servers) permettent même de masquer complétement le bug ISM : les attachements / détachements sont supprimés. Cependant leur mise en oeuvre nécessite un paramétrage à faire valider par les utilisateurs. L'option NUMA est plus simple à mettre en oeuvre mais dépend surtout de votre architecture matérielle : nombre de lgrps disponibles sur votre système (j'écris en ce moment un petit artcile à ce sujet).
Ci-joint quelques références sur ce sujet :
- Chapitre 16 "Support for NUMA and CMT Hardware" dans Solaris internals
- Application and Networking Architecture in Oracle DB
- Configuring Oracle Database for Shared Server
- Tuning Shared Server
- About Databe Resident Connection Pooling
- Configuring Database Resident Connection Pooling