Cas d'usage avec sga_max_size > sga_target sous Linux

Depuis la 10g, nous savons qu’Oracle propose la gestion de mémoire ASMM (Automatic Shared Memory Management) qui permet dans le principe de s’affranchir du réglage des différents composants de la SGA (« buffer_cache » et « shared_pool » principalement, mais aussi « java_pool », « large_pool » et « streams_pool »).
Pour aller plus loin dans le concept, Oracle a ensuite proposé en 11g le mode AMM (Automatic Memory Management), qui a pour but de simplifier encore plus la gestion de la mémoire, en incluant l’ajustement automatique des PGA en vis à vis de la SGA et permettant ainsi des échanges d’allocation entre les PGA et la SGA.
La simplification de configuration avec AMM est très pratique pour tous les clients qui ne se posent pas de questions et ne veulent pas s’en poser, elle est adaptée pour une majorité de progiciels sur des serveurs de gamme moyenne.
Le diagramme suivant montre la relation entre les différentes définition des caches :
AMM
Par contre, sur les environnements plus conséquents (serveurs grande capacité, Engineered System) et plus stressés en terme de charge de travail, cela ne fonctionne pas toujours comme espéré !
Pour l’utilisation d’ASMM, si vous ne voulez pas avoir de surprises, il est d’usage de spécifier des valeurs minimales pour « db_cache_size » et « shared_pool_size » (Doc ID 295626.1).
Pour ce qui est de l’utilisation d’AMM, Oracle ne le recommande en fait tout simplement pas sous Linux 64bits, sur les environnements à mémoire conséquente et surtout en cluster, au profit de l’utilisation des « hugepages », configuration de l’usage de large page mémoire pour le système (Doc ID 749851.1).
Donc il reste la fonctionnalité ASMM pour laquelle il n’y a pas de conflit avec l’utilisation des « hugepages » et dont l’apport principal résulte dans l’ajustement automatique entre les différentes zones, apportant ainsi une certaine constance de performance vis à vis des fluctuations potentielles de la charge.
Dans les environnements de production, il est également courant d’avoir « sga_max_size » = « sga_target » : on ne spécifie pas « sga_max_size »  qui vaut alors par défaut « sga_target » lors du démarrage de l’instance.
Mais est-ce que positionner « sga_max_size » supérieur à « sga_target » peut servir à quelque chose ?
Le débat n’est pas nouveau et j’ai déterré une vieille note, qui date de 2007, depuis le forum « Oracle Comnunity », qui nécessite, c’est vrai, un peu de courage pour être lue en intégralité, mais qui permet de se faire une idée de la réponse.
Dans cette discussion Oracle community, SGA_MAX_SIZE != SGA_TARGET when?, un cas d’usage avec « sga_max_size » supérieur à « sga_target » est proposé et nous allons le voir ensemble :
Lorsque l’on a plusieurs instances sur un même serveur, l’idée serait de pouvoir échanger les quantités de mémoire entre les instances, sans avoir à  en redémarrer aucune.
Exemple à 2 instances sur un serveur à 2Go :
– On les démarre toutes les deux avec « sga_target » = 600M, « sga_max_size » = 900M.
– En fonction des besoins de charge, on envisage de pouvoir monter l’une ou l’autre à 900Mo en faisant varier « sga_target », mais jamais les deux en même temps pour laisser toujours suffisamment de mémoire disponible aux PGA des processus utilisateurs et au système.
– Lorsque la surcharge n’est plus de mise, on réduit « sga_target » d’autant et on laisse le processus MMAN organiser une nouvelle répartition.
AMMEX
Dans ce fil de discussion 537400, référencé plus haut, une remarque était déroutante :
Sur chacune des instances démarrées, la commande SQL « show sga » montre une taille allouée proche de sga_max_size et non de sga_target.
De  même, la commande unix « ipcs -m » montre une allocation de la valeur de « sga_max_size ».
Ce qui semblerait nous empêcher d’atteindre notre but avec 1800 Mo alloué pour les deux instances ?
Non ce n’est pas le cas ! 
(mais il ne faut pas paramétrer les « hugepages », qui elles réserveraient bien la valeur définie par « sga_max_size »)
Voici pourquoi :
En mode pages mémoire de 4K, rien n’est réellement réservé à l’allocation, les pages ne sont montées en mémoire et dédiées au processus Oracle correspondant que lorsqu’elle sont touchées (accédées par le process), positionner un « sga_max_size » plus grand n’aura d’autre effet que d’agrandir l’espace d’adressage possible pour les processus de l’instance, l’espace utilisé réellement s’arrêtant à la valeur de « sga_target ».
Mais attention : ce mécanisme est contrôlé par le paramètre « pre_page_sga », et à partir de la version 12c, il a maintenant comme valeur par défaut « TRUE » (Doc ID 1987975.1). Ce qui alloue toutes les pages jusqu’à « sga_max_size » aux processus Oracle de l’instance dès le démarrage de l’instance. Ce qui va à l’encontre du but recherché.
On peut trouver une justification du passage du paramètre à « TRUE » ici : en effet, dans les configurations utilisant la fonctionnalité inmemory où la SGA peut être très grande, il faut que les « columns store » soient initialisés rapidement, Oracle se devait de réimplémenter en background (processus sa0x) le «touch» des pages.
Mais revenons à notre cas d’usage : pas d’utilisation des hugepages et pre_page_sga =false en cas de version 12c.
Que se passe-t-il après la réduction de « sga_target » sur une des instances ?
Une fois que le processus de background MMAN a terminé sa réorganisation, on se retrouve bien avec une plus petite SGA de travail, mais les pages « au dessus » de la nouvelle sga_target sont toujours en mémoire ! De fait, Oracle n’a rien rendu à l’OS. Il s’interdit juste désormais d’accéder à cette zone. Par contre, si le système en a besoin, il va pourvoir réutiliser cet espace puisqu’il n’est plus utilisé par l’instance. Il mettra au fur et à mesure de l’usage ces pages inactives de l’instance dans le swap sur disque, à condition qu’il y ait suffisamment de place définie dans la zone de swap.
Ainsi, par ce mécanisme, si l’on ajuste « sga_target » de la deuxième instance de 600 Mo à 900 Mo après avoir descendu « sga_target » de la première de 900 Mo à 600 Mo, les 300 Mo de la première seront mis en swap et l’espace physique libéré sera alloué à la seconde, c’est bien le résultat escompté. Il s’agira de swap « inactif », qui n’impacte aucune des 2 instances. Et pour faire le flip flop, il suffira de « déswapper » la tranche inactive de chaque instance.
Ceci entraine qu’il faut prévoir d’avance dans le swap un surplus d’allocation de (« sga_max_size » – « sga_target ») par instance. Car une fois que toutes les instances auront utilisé au moins une fois leur poire pour la soif, celle-ci se retrouvera tôt ou tard dans le swap… jusqu’au shutdown de l’instance.
Sous Solaris, l’implémentation est différente : Solaris est capable de libérer de la mémoire partagée dynamiquement via DISM (Dynamic Intimate Shared Memory). Mais une note MOS nous recommande de ne pas l’utiliser sur des instances RAC de plus de 4 Go ! (Doc ID 1606318.1)… ce qui finalement restreint un peu l’intérêt.
Conclusion : la possibilité de positionner « sga_max_size » supérieure à « sga_target » en mode ASMM peut avoir une utilité sur des environnements à instances multiples, ou à instance unique avec charge OS fluctuante. 
Cependant, de par son fonctionnement particulier (avec swap «inactif»), il est délicat de l’utiliser pour des environnements de production sans en comprendre tous les effets. Il pourra offrir une certaine souplesse, on l’a vu, dans les environnements moins critiques… Je reste malgré tout assez dubitatif sur son utilisation effective avérée. J’ai vu peu de bases configurées avec cette possibilité plus de 12 ans après la sortie de la fonctionnalité. Et vous, l’utilisez vous ?