Partager l'article ! Intimate Shared Memory (ISM) et Solaris x86 (1er partie): Petit sujet qui m'a tenu en haleine. Pour faciliter sa compréhension ...
Petit sujet qui m'a tenu en haleine. Pour faciliter sa compréhension je le découpe en deux parties : une première partie sur un problème d'initialisation d'un segment de type ISM et une seconde partie sur un dysfonctionnement de l'ISM. Les deux sous Solaris x86 uniquement.
Mais de quoi parlons nous ? Quelques explications sont nécessaires. Pour partager des données et synchroniser des évènements entre processus, le système Solaris utilise un framework nommé IPC (InterProcess Communication). Ce framework contient plusieurs objets IPC dont le standard POSIX IPC : POSIX semaphores, POSIX shared memory et POSIX message queues.
J'évoque ici l'objet IPC : POSIX shared memory. Cet objet est notamment utilisé dans les bases de données (en tout cas Oracle et Sybase). Pour les "spécialistes" de ces produits, il s'agit ni plus ni moins de la fameuse SGA. Pour nous, les "spécialistes" du système nous appelons cela un segment SHM (Segment sHared Memory). Lors du démarrage d'une instance Sybase ou Oracle, un segment SHM est initialisé avec une taille spécifique. Si cette taille n'est pas disponible, l'instance ne s'active pas.
Par défaut, la création d'un segment SHM :
Les ingénieurs Solaris ont donc optimisé la gestion de ce segment SHM : ISM (Intimate Shared Memory).
L'ISM corrige les problèmatique d'un segment SHM classique :
L'utilisation de ce type de segment est devenu le standard pour les bases de données : la SGA fonctionne donc avec un segment ISM sous Solaris.
D'où mon problème : ma base de données Oracle 11g r2 sous Solaris 10x86 (update 9) n'utilise pas un segment ISM mais un simple segment SHM !!! Analysons un peu tout cela.
En espectant l'espace d'adresse du process Oracle (ici pmon), j'ai étais surpris de constater que la SGA utilisait un segment SHM classique :
# pmap -x 10735
10735: ora_pmon_XXXX22
Address Kbytes
RSS Anon Locked Mode Mapped File
0000000000400000 222240 91144 -
- r-x-- oracle
000000000DD17000 1180 676
208 - rw--- oracle
000000000DE3E000 136
32 32 - rw--- oracle
000000000DE60000 1828 1644
1632 - rw--- [ heap ]
0000000060000000 4
4 - - r--s- [ shmid=0x4000003c ]
0000000060001000 2097156 2028692
- - rwxs- [ shmid=0x4000003c ]
FFFFFD7FFCAA0000 64
8 8 - rwx-- [ anon ]
FFFFFD7FFCABE000 72
8 8 - rw--- [ anon ]
FFFFFD7FFCAD0000 64
12 12 - rw--- [ anon ]
[...]
L'initialisation d'un segment type ISM provient du demandeur et non du système. J'ai donc décidé de vérifier les logs de démarrage de l'instance Oracle (fichier alert.log). Je suis tombé sur ce message fort intéressant :
Mon Nov 21 16:38:40 2011
Starting ORACLE instance (normal)
WARNING: Not enough physical memory for SHM_SHARE_MMU segment of size 0x0000000080002000 [flag=0x4000]
Lors de l'activation de l'instance, Oracle a tenté d'activer un segment type ISM sans y être parvenu. Le message indiquant l'erreur suivante : Not enough physical memory for SHM_SHARE_MMU segment. Tiens donc pas assez de mémoire ? Alors que la SGA demandée correspondait à seulement 2 Go ? La vérité était ailleurs...
Pour mieux reproduire le problème, j'ai décidé d'écrire un petit programme C me permettant de créer un segment type ISM. Contrairement à ce que je pensais, ce n'est pas lors de la création du segment que le type ISM est spécifié mais lors d'un attachement.
La création et l'attachement correspondent aux appels suivants :
shmget(2, size, 0660 | IPC_CREAT | IPC_EXCL)
shmat(shmid, (void *)0, SHM_SHARE_MMU)
Le flag SHM_SHARE_MMU de la fonction shmat permet l'utilisation de l'ISM. L'exécution de mon petit programme C m'a permis d'activer sans problème un segment ISM de 10 Go.
# ./ishm
shmid: 1526726689
# ipcs -m
IPC status from <running system> as of Tue Jan 10 11:26:10 CET 2012
T ID
KEY MODE OWNER GROUP
Shared Memory:
m 1526726689 0x2 --rw-rw----
root root
[...]
# pmap -x 24680
24680: ./ishm
Address Kbytes
RSS Anon Locked Mode Mapped File
0000000000400000 4
4 - - r-x-- ishm
0000000000410000 8
8 8 - rw--- ishm
FFFFFD7F80000000 1048576 1048576 - 1048576 rwxsR [ ism
shmid=0x5b000021 ]
FFFFFD7FFF210000 64
64 64 - rwx-- [ anon ]
FFFFFD7FFF230000 24
12 12 - rwx-- [ anon ]
FFFFFD7FFF240000 1276 712
- - r-x-- libc.so.1
FFFFFD7FFF380000 4
4 4 - rwx-- [ anon ]
FFFFFD7FFF38F000 36
36 36 - rw--- libc.so.1
FFFFFD7FFF398000 16
4 4 - rw--- libc.so.1
FFFFFD7FFF3AE000 244 244
- - r-x-- ld.so.1
FFFFFD7FFF3F0000 4
4 4 - rwx-- [ anon ]
FFFFFD7FFF3FB000 8
8 8 - rwx-- ld.so.1
FFFFFD7FFF3FD000 8
8 8 - rwx-- ld.so.1
FFFFFD7FFFDFE000 8
8 8 - rw--- [ stack ]
---------------- -------- --------- ----- ---------
total Kb 1050280 1049692 156
1048576
Mais où était mon problème ? Oracle doit en faire un peu plus ? J'ai donc tracé les appels systèmes lors du démarrage d'une instance.
[...]
6362: shmget(672617948, 1073754112, 0660|IPC_CREAT|IPC_EXCL) = 83886086
6362: shmget(672617949, 0,
0) Err#2 ENOENT
6362: shmget(672617950, 0,
0) Err#2 ENOENT
6362: shmget(672617951, 0,
0) Err#2 ENOENT
6362: shmat(83886086, 0x60000000,
040000) Err#22 EINVAL
6362: shmat(83886086, 0x60000000,
0) = 0x60000000
[...]
Oracle s'attache en spécifiant une adresse mémoire 0x60000000. J'ai donc modifié mon petit programme C en spécifiant la même adresse d'attachement et j'ai obtenu à ma grande surprise l'erreur suivante :
# ./ishm
shmat: Invalid argument
J'ai obtenu la même erreur que le démarrage de la base Oracle. Bingo ! Lors de l'appel à la fonction shmat (si on spécifie l'adresse 0x60000000) l'attachement ne s'effectue pas. Mais pourquoi ? Dépassant un peu mes compétances j'ai ouvert un call au support Oracle.
Réponse du support Oracle : la valeur 0x60000000 n'est pas divisible (valeur entière) par l'ensemble des tailles de pages disponibles sur le système Solaris 10x86. Il faut donc désactiver la taille de pages posant problème (option désactivée dans le kernel patch suivant 144489-17). Le workaround n'est pas applicable en production (boot en mode kernel debugging + modification avant chargement du kernel de la valeur largepagesupport).
En vérifiant mes tailles de pages disponibles sur mon serveur DL380 G7, j'obtiens le résultat suivant :
# pagesize -a
4096
2097152
1073741824
Tiens donc, on peut utiliser des tailles de pages de 1Go !? Et bizarrement c'est avec cette taille de pages où la valeur 0x60000000 n'est pas divisible en une valeur entière. L'application du patch supprime la possibilité d'utiliser cette taille de pages.
Voilà donc la fin de la 1er partie sur ISM et Solaris 10x86. La 2ème partie fait référence à un bug dans la gestion de l'ISM uniquement pour Solaris 10x86 (et Solaris 11x86). Bug que j'ai eu le privilège de découvrir en exclusivité...
Ci-joint quelques références sur ce sujet :
| Février 2012 | ||||||||||
| L | M | M | J | V | S | D | ||||
| 1 | 2 | 3 | 4 | 5 | ||||||
| 6 | 7 | 8 | 9 | 10 | 11 | 12 | ||||
| 13 | 14 | 15 | 16 | 17 | 18 | 19 | ||||
| 20 | 21 | 22 | 23 | 24 | 25 | 26 | ||||
| 27 | 28 | 29 | ||||||||
|
||||||||||