25.4. Traces dynamiques
PostgreSQL™ fournit un support
pour les traces dynamiques du serveur de bases de données. Ceci
permet l'appel à un outil externe à certains points du code pour
tracer son exécution. Actuellement, cette fonctionnalité a pour cible
les développeurs de bases de données car il requiert une certaine
familiarité avec le code.
Un certain nombre de points de trace, souvent appelés sondes, sont
déjà insérés dans le code source. Par défaut, les sondes sont
désactivées et l'utilisateur doit explicitement demander au script
configure de les rendre disponibles pour PostgreSQL™.
Actuellement, seul l'outil DTrace est supporté, outil qui est
disponible uniquement sur Solaris Express et Solaris 10+. Il est
attendu que DTrace soit disponible dans le futur sur FreeBSD et Mac
OS X. Supporter des outils de traces dynamiques est théoriquement
possible en modifiant les définitions des macros PG_TRACE dans src/include/pg_trace.h.
25.4.1. Compiler en activant les traces dynamiques
Par défaut, les sondes sont désactivées, donc vous aurez besoin
d'indiquer explicitement au script configure de les activer dans
PostgreSQL™. Pour inclure le
support de DTrace, ajoutez --enable-dtrace
aux options de configure. Lire Section 14.5,
« Procédure d'installation » pour plus
d'informations.
25.4.2. Sondes disponibles
Quelques sondes standards sont fournies dans le code source (bien
sûr, d'autres peuvent être ajoutés si nécessaire pour un problème
particulier). Elles sont précisées dans Tableau 25.3,
« Sondes disponibles ».
Tableau 25.3. Sondes disponibles
|
Nom
|
Paramètres
|
Aperçu
|
|
transaction__start
|
(int transactionId)
|
Début d'une nouvelle transaction.
|
|
transaction__commit
|
(int transactionId)
|
Fin réussie d'une transaction.
|
|
transaction__abort
|
(int transactionId)
|
Échec d'une transaction.
|
|
lwlock__acquire
|
(int lockid, int mode)
|
Un LWLock a été acquis.
|
|
lwlock__release
|
(int lockid, int mode)
|
Un LWLock a été lâché.
|
|
lwlock__startwait
|
(int lockid, int mode)
|
Un LWLock n'était pas immédiatement disponible et un
processus a commencé à attendre la disponibilité du
verrou.
|
|
lwlock__endwait
|
(int lockid, int mode)
|
Un processus a été libéré de son attente d'un LWLock.
|
|
lwlock__condacquire
|
(int lockid, int mode)
|
Un LWLock a été acquis avec succès quand l'appelant
indiquait sans attente.
|
|
lwlock__condacquire__fail
|
(int lockid, int mode)
|
Un LWLock n'a pas été acquis quand l'appelant indiquait
sans attente.
|
|
lock__startwait
|
(int locktag_field2, int lockmode)
|
Une requête pour un verrou lourd (lmgr lock) est en
attente car le verrou n'est pas disponible.
|
|
lock__endwait
|
(int locktag_field2, int lockmode)
|
Une requête pour un verrou lourd (lmgr lock) a terminé
son attente (autrement dit, il a acquis le verrou).
|
25.4.3. Utiliser les sondes
L'exemple ci-dessous montre un script DTrace pour l'analyse du
nombre de transactions sur le système, comme alternative à
l'interrogation régulière de pg_stat_database avant et après un test de
performance.
#!/usr/sbin/dtrace -qs
postgresql$1:::transaction-start
{
@start["Start"] = count();
self->ts = timestamp;
}
postgresql$1:::transaction-abort
{
@abort["Abort"] = count();
}
postgresql$1:::transaction-commit
/self->ts/
{
@commit["Commit"] = count();
@time["Total time (ns)"] = sum(timestamp - self->ts);
self->ts=0;
}
Notez comment le souligné double dans les noms de sonde doit être
remplacé par un trait d'union lors de l'utilisation d'un script
DTrace. À son exécution, le script de l'exemple D donne une sortie
comme :
# ./txn_count.d `pgrep -n postgres`
^C
Start 71
Commit 70
Total time (ns) 2312105013
Vous devez vous rappeler que les programmes de trace doivent être
écrits soigneusement, sinon les informations récoltées pourraient
ne rien valoir. Dans la plupart des cas où des problèmes sont
découverts, c'est l'instrumentation qui est erronée, pas le système
sous-jacent. En discutant des informations récupérées en utilisant
un tel système, il est essentiel de s'assurer que le script utilisé
est lui-aussi vérifié et discuter.
25.4.4. Définir les sondes
De nouvelles sondes peuvent être définies dans le code partout où
le développeur le souhaite bien que cela nécessite une nouvelle
compilation.
Une sonde peut être insérée en utilisant une des macros de trace.
Elles sont choisies suivant le nombre de variables à mettre à
disposition pour l'inspection de cette sonde. Tracer l'occurence
d'un événement se fait en une seule ligne, en utilisant seulement
le nom de la sonde, par exemple :
PG_TRACE (ma__nouvelle__sonde);
Des sondes plus complexes peuvent fournir une ou plusieurs
variables à l'inspection de l'outil des traces dynamiques en
utilisant la macro PG_TRACE
n
qui correspond au nombre de
paramètres après le nom de la sonde :
PG_TRACE3 (mon__evenement__complexe, varX, varY, varZ);
La définition de la sonde transaction__start est montrée ci-dessous
:
static void
StartTransaction(void)
{
...
/*
* génère un nouvel id de transaction
*/
s->transactionId = GetNewTransactionId(false);
XactLockTableInsert(s->transactionId);
PG_TRACE1(transaction__start, s->transactionId);
...
}
Notez comment l'ID de transaction est rendu disponible à l'outil de
traces dynamiques.
L'outil de traces dynamiques peut nécessiter une définition plus
complète de ces sondes. Par exemple, DTrace requiert que vous
ajoutez de nouvelles sondes dans le fichier src/backend/utils/probes.d comme indiqué ici :
provider postgresql {
...
probe transaction__start(int);
...
};
Vous devez faire attention que les types de données spécifiés pour
les arguments de la sonde correspondent aux types de données des
variables utilisées dans la macro PG_TRACE. Ceci n'est pas vérifié au moment de la
compilation. Vous pouvez vérifier que votre sonde nouvellement
ajoutée est disponible en recompilant, puis en exécutant le nouveau
binaire et, en tant que root, en exécutant une commande DTrace tel
que :
dtrace -l -n transaction-start