forked from gleu/pgdocs_fr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
wal.xml
648 lines (597 loc) · 33.4 KB
/
wal.xml
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
<?xml version="1.0" encoding="ISO-8859-15"?>
<!-- Dernière modification
le $Date$
par $Author$
révision $Revision$ -->
<chapter id="wal">
<title>Fiabilité et journaux de transaction</title>
<para>
Ce chapitre explique comment les journaux de transaction sont utilisés pour
obtenir des traitements efficaces et fiables.
</para>
<sect1 id="wal-reliability">
<title>Fiabilité</title>
<para>
La fiabilité est une propriété importante de tout système de base de
données sérieux. <productname>PostgreSQL</productname> fait tout ce qui est
en son pouvoir pour garantir une fiabilité à toute épreuve. Un des aspects
de cette fiabilité est que toutes les données enregistrées par une
transaction
validée doivent être stockées dans un espace non volatile, un espace
non sensible aux coupures de courant, aux bogues du système d'exploitation
et aux problèmes matériels (sauf en cas de problème sur l'espace non
volatile, bien sûr). Écrire avec succès les données sur le stockage
permanent de l'ordinateur (disque dur ou un équivalent) est habituellement
suffisant pour cela. En fait, même si un ordinateur est vraiment
endommagé, si le disque dur survit, il peut être placé dans un autre
ordinateur avec un matériel similaire et toutes les transactions validées
resteront intactes.
</para>
<para>
Bien que forcer l'enregistrement des données périodiquement sur le disque
semble être une opération simple, ce n'est pas le cas. Comme les disques
durs sont beaucoup plus lents que la mémoire principale et les
processeurs, plusieurs niveaux de cache existent entre la mémoire principale
de l'ordinateur et les disques. Tout d'abord, il existe le tampon cache du
système d'exploitation, qui met en cache les blocs disque fréquemment utilisés
et combine les écritures sur le disque. Heureusement, tous les systèmes
d'exploitation donne un moyen de forcer les écritures du cache disque vers
le disque et <productname>PostgreSQL</productname> utilise ces fonctions (voir le
paramètre <xref linkend="guc-wal-sync-method"/> pour voir comment cela
se fait).
</para>
<para>
Ensuite, il pourrait y avoir un cache dans le contrôleur du disque dur ;
ceci est assez commun sur les cartes contrôleur <acronym>RAID</acronym>. Certains
de ces caches sont <firstterm>write-through</firstterm>, signifiant que les écritures
sont passées au lecteur dès qu'elles arrivent. D'autres sont
<firstterm>write-back</firstterm>, signifiant que les données sont passées au lecteur
un peu après. De tels caches peuvent apporter une faille dans la fiabilité car
la mémoire du cache du disque contrôleur est volatile et qu'elle perdra son
contenu à la prochaine coupure de courant. Des cartes contrôleur de meilleure
qualité ont des caches <firstterm>avec batterie</firstterm>, signifiant que la carte
dispose d'une batterie qui maintient le courant dans le cache en cas de perte
de courant. Une fois le courant revenu, les données seront écrites sur les
disques durs. Pour vérifier le cache en écriture sur
<productname>Linux</productname>, utilisez <command>hdparm
-I</command> ; il est activé si une étoile (<literal>*</literal>) est
affichée au côté de <literal>Write cache</literal>. <command>hdparm
-W</command> désactive le cache en écriture. Sur
<productname>FreeBSD</productname>, utilisez l'outil
<application>atacontrol</application>. (Pour les disques SCSI, utilisez
<ulink
url="http://sg.torque.net/sg/sdparm.html"><application>sdparm</application></ulink>
pour désactiver <literal>WCE</literal>.) Sur
<productname>Solaris</productname>, le cache en écriture du disque est
contrôlé par <ulink
url="http://www.sun.com/bigadmin/content/submitted/format_utility.jsp"><literal>format
-e</literal></ulink>. (Le système de fichiers Solaris <acronym>ZFS</acronym>
est sûr même avec un cache disque activé en écriture car il lance ses
propres commandes de vidage du chache disque.) Sur
<productname>Windows</productname> si <varname>wal_sync_method</varname>
vaut <literal>open_datasync</literal> (la valeur par défaut), le cache en
écriture est désactivé en décochant <literal>My Computer\Open\{sélectionner
le lecteur disque}\Properties\Hardware\Properties\Policies\Enable write
caching on the disk</literal>. De plus, sur Windows,
<literal>fsync</literal> et <literal>fsync_writethrough</literal> ne font
jamais de cache en écriture.
</para>
<para>
Et enfin, la plupart des disques durs ont des caches. Certains sont
<quote>write-through</quote> alors que d'autres sont
<quote>write-back</quote>. Les mêmes soucis sur la perte de données existent
pour ces deux types de cache. Les lecteurs IDE ont principalement des caches
<quote>write-back</quote> qui ne survivront pas à une perte de courant.
</para>
<para>
Quand le système d'exploitation envoie une demande d'écriture au disque,
il ne peut pas faire grand chose pour s'assurer que les données sont
arrivées dans un espace de stockage non volatile. Ce travail incombe à
l'administrateur : ce dernier doit s'assurer que tous les composants de
stockage assurent l'intégrité des données. Évitez les contrôleurs disques
ne disposant pas de caches protégés par batterie. Au niveau du disque,
désactivez le cache <quote>write-back</quote> si le disque ne garantit pas
que les données seront écrites avant un arrêt.
</para>
<para>
Un autre risque concernant la perte des données est dû aux opérations
d'écriture sur les plateaux du disque. Les plateaux sont divisés en
secteur de 512 octets généralement. Chaque opération de lecture ou écriture
physique traite un secteur entier. Quand la demande d'écriture arrive au
lecteur, elle pourrait contenir 512 octets, 1024 octets ou 8192 octets et
le processus d'écriture pourrait échouer à cause d'une perte de courant à
tout moment signifiant que certains octets pourraient être écrits et les
autres perdus. Pour se prévenir contre ce type d'échec,
<productname>PostgreSQL</productname> écrit périodiquement des images de page complète
sur le stockage permanent <emphasis>avant</emphasis> de modifier la page réelle sur
disque. En effectuant ceci, lors d'une récupération après un arrêt brutal,
<productname>PostgreSQL</productname> peut restaurer des pages écrites partiellement. Si
vous avez un contrôleur disque avec un cache préservé par batterie ou un
logiciel pour le système de fichiers qui protège les écritures de pages
incomplètes (c'est-à-dire ReiserFS 4), vous pouvez désactiver la création des images
de page en utilisant le paramètre <xref linkend="guc-full-page-writes"/>.
</para>
</sect1>
<sect1 id="wal-intro">
<title>Write-Ahead Logging (<acronym>WAL</acronym>)</title>
<indexterm zone="wal">
<primary>WAL</primary>
</indexterm>
<indexterm>
<primary>log transaction</primary>
<see>WAL</see>
</indexterm>
<para>
<firstterm>Write-Ahead Logging</firstterm> (<acronym>WAL</acronym>)
est une méthode conventionnelle pour s'assurer de l'intégrité des
données. Une description détaillée peut être trouvée dans la plupart
des livres sur le traitement transactionnel. Brièvement, le concept central
du <acronym>WAL</acronym> est d'effectuer les changements des fichiers de
données (donc les tables et les index) uniquement après que ces changements
ont été écrits de façon sûr dans un journal, appelé journal des
transactions. Si nous suivons cette procédure, nous n'avons
pas besoin d'écrire les pages de données vers le disque à chaque
validation de transaction car nous savons que, dans l'éventualité
d'une défaillance, nous serons capables de récupérer la base de
données en utilisant le journal : chaque changement qui n'a pas été
appliqué aux pages de données peut être ré-exécuté depuis les
enregistrements du journal (ceci est une récupération roll-forward,
aussi connue sous le nom de REDO).
</para>
<tip>
<para>
Comme les journaux de transaction permettent de restaurer le contenu des
fichiers de base de données après un arrêt brutal, les systèmes de
fichiers journalisés ne sont pas nécessaires pour stocker avec fiabilité
les fichiers de données ou les journaux de transactions. En fait, la
surcharge causée par la journalisation peut réduire les performances,
tout spécialement si la journalisation fait que les
<emphasis>données</emphasis> du système de fichiers sont envoyées sur
disque. Heureusement, l'envoi des données lors de la journalisation
peut souvent être désactivé avec une option de montage du système de
fichiers, par exemple <literal>data=writeback</literal> sur un système de
fichiers Linux ext3. Par contre, les systèmes de fichiers journalisés
améliorent la rapidité au démarrage après un arrêt brutal.
</para>
</tip>
<para>
Utiliser les journaux de transaction permet de réduire de façon
significative le nombre d'écritures sur le disque puisque seul le journal
a besoin d'être écrit sur le disque pour garantir qu'une
transaction a été validée plutôt que d'écrire dans chaque fichier de
données modifié par la transaction. Ce journal est écrit séquentiellement
ce qui fait que le coût de synchronisation du journal est largement moindre
que le coût d'écriture des pages de données. Ceci est tout spécialement
vrai pour
les serveurs gérant beaucoup de petites transactions touchant différentes
parties du stockage de données. De plus, quand le serveur traite plein de
petites transactions en parallèle, un <function>fsync</function> du
journal des transactions devrait suffire pour enregistrer plusieurs
transactions.
</para>
<para>
Les journaux de transaction rendent possible le support de sauvegarde
en ligne et de récupération à un moment, comme décrit dans la <xref
linkend="continuous-archiving"/>. En archivant les journaux de transaction,
nous pouvons supporter le retour à tout instant couvert par les données
disponibles dans les journaux de transaction : nous installons
simplement une ancienne sauvegarde physique de la base de données et nous
rejouons les journaux de transaction jusqu'au moment désiré. Qui plus est,
la sauvegarde physique n'a pas besoin d'être une image instantanée de
l'état de la base de données — si elle a été faite pendant une
grande période de temps, alors rejouer les journaux de transaction pour
cette période corrigera toute incohérence interne.
</para>
</sect1>
<sect1 id="wal-async-commit">
<title>Validation asynchrone (<foreignphrase>Asynchronous
Commit</foreignphrase></title>
<indexterm>
<primary>validation synchrone</primary>
</indexterm>
<indexterm>
<primary>validation asynchrone</primary>
</indexterm>
<para>
La <firstterm>validation asynchrone</firstterm> est une option qui
permet aux transactions de se terminer plus rapidement. Le risque encouru
est de perdre les transactions les plus récentes dans le cas où le serveur
s'arrête brutalement. Dans beaucoup d'applications, le compromis est
acceptable.
</para>
<para>
Comme le décrit la section précédente, la validation d'une
transaction est habituellement <firstterm>synchrone</firstterm> :
le serveur attend que les enregistrements des journaux de transaction
soient bien sauvegardés sur un disque avant de renvoyer l'information du
succès de l'opération au client. Ce dernier a donc la garantie qu'une
transaction validée est stockée de façon sûre, donc même
en cas d'arrêt brutal immédiatement après. Néanmoins, pour les petites
transactions, ce délai est une partie importante de la durée totale
d'exécution de la transaction. Sélectionner le mode de validation
asynchrone signifie que le serveur renvoie le succès de l'opération dès
que la transaction est terminée logiquement, donc avant que les
enregistrements du journal de transaction que cette transaction a
généré ne soient réellement stockées sur disque. Ceci peut apporter
une accélération importante pour les petites transactions.
</para>
<para>
La validation asynchrone introduit le risque des pertes de données.
Il existe un petit délai entre le moment où le rapport de la fin d'une
transaction est envoyé au client et celui où la transaction est réellement
enregistrée (c'est-à-dire le moment où le résultat de cette transaction
ne pourra pas être perdu même en cas d'arrêt brutal du serveur). Du coup,
la validation asynchrone ne devrait pas être utilisée si le client
se base sur le fait que la transaction est enregistrée de façon sûre.
Par exemple, une banque ne devra pas utiliser la validation asynchrone
pour l'enregistrement d'une transaction sur les opérations sur un
compte bancaire. Dans de nombreux autres scénarios, comme la trace
d'événements, il n'y a pas de garantie forte de ce type.
</para>
<para>
Le risque pris avec l'utilisation de la validation asynchrone concerne
la perte de données, pas la corruption de données. Si le serveur s'arrête
brutalement, il récupèrera en rejouant les journaux de transaction
jusqu'au dernier enregistrement qui a été envoyé au disque. La base
de données sera donc dans un état cohérent mais toutes les transactions
qui n'auront pas été enregistrées sur disque n'apparaîtront pas. L'effet
immédiat est donc la perte des dernières transactions. Comme les
transactions sont rejouées dans l'ordre de validation, aucune incohérence
ne sera introduite — par exemple, si la transaction B fait des
modifications sur les effets d'une précédente transaction A, il n'est pas
possible que les effets de A soient perdus alors que les effets de B
sont préservés.
</para>
<para>
L'utilisateur peut sélectionner le mode de validation de chaque
transaction, donc il est possible d'avoir en même temps des transactions
validées en synchrone et en asynchrone. Une grande flexibilité est
permise entre performance et durabilité de certaines transactions. Le
mode de validation est contrôlé par le paramètre utilisateur
<xref linkend="guc-synchronous-commit"/>, qui peut être modifié comme
tout autre paramètre utilisateur. Le mode utilisé pour toute
transaction dépend de la valeur de <varname>synchronous_commit</varname>
au début de la transaction.
</para>
<para>
Certaines commandes, par exemple <command>DROP TABLE</command>, sont
forcées en mode synchrone quelque soit la valeur du paramètre
<varname>synchronous_commit</varname>. Ceci a pour but de s'assurer de
la cohérence entre le système de fichiers du serveur et l'état logique
de la base de données. Les commandes gérant la validation en deux phases,
comme <command>PREPARE TRANSACTION</command>, sont aussi toujours
synchrones.
</para>
<para>
Si la base de données s'arrête brutalement lors du délai entre une
validation asynchrone et l'écriture des enregistrements dans le journal
des transactions, les modifications réalisées lors de cette transaction
<emphasis>seront</emphasis> perdues. La durée de ce délai est limitée
car un processus en tâche de fond (le <quote>wal writer</quote>) envoie
les enregistrements non écrits des journaux de transaction sur le
disque toutes les <xref linkend="guc-wal-writer-delay"/> millisecondes.
La durée maximum actuelle de ce délai est de trois fois
<varname>wal_writer_delay</varname> car le processus d'écriture des
journaux de transaction est conçu pour favoriser l'écriture de pages
complètes lors des périodes de grosses activités.
</para>
<caution>
<para>
Un arrêt en mode immédiat est équivalent à un arrêt brutal et causera
du coup la perte des validations asynchrones.
</para>
</caution>
<para>
La validation asynchrone fournit un comportement différent de la simple
désactivation de <xref linkend="guc-fsync"/>. <varname>fsync</varname> est
un paramètre pour le serveur entier qui modifie le comportement de toutes
les transactions. Cela désactive toute logique de
<productname>PostgreSQL</productname> qui tente de synchroniser les
écritures aux différentes parties de la base de données (c'est-à-dire
l'arrêt brutal du matériel ou du système d'exploitation, par un échec
de <productname>PostgreSQL</productname> lui-même) pourrait résulter
en une corruption arbitraire de l'état de la base de données. Dans de
nombreux scénarios, la validation asynchrone fournit la majorité des
améliorations de performances obtenues par la désactivation de
<varname>fsync</varname>, mais sans le risque de la corruption de données.
</para>
<para>
<xref linkend="guc-commit-delay"/> semble aussi très similaire à la
validation asynchrone mais il s'agit en fait d'une méthode de validation
synchrone (en fait, <varname>commit_delay</varname> est ignoré lors d'une
validation asynchrone). <varname>commit_delay</varname> a pour effet
l'application d'un délai juste avant qu'une validation synchrone tente
d'enregistrement les journaux de transaction sur disque, dans l'espoir
que la demande de synchronisation occasionnée par les écritures puissent
aussi servir à d'autres transactions validées à peu près en même temps.
Configurer <varname>commit_delay</varname> sert seulement quand beaucoup
de transactions sont validées en parallèle et il est difficile de
configurer correctement ce paramètre avec une valeur qui aide plus
qu'elle ne dessert.
</para>
</sect1>
<sect1 id="wal-configuration">
<title>Configuration des journaux de transaction</title>
<para>
Il y a plusieurs paramètres de configuration associés aux
journaux de transaction qui affectent les performances de la base de
données. Cette section explique leur utilisation. Consultez le
<xref linkend="runtime-config"/> pour des détails sur la
mise en place de ces paramètres de configuration.
</para>
<para>
Dans la séquence des transactions, les
<firstterm>points de contrôles</firstterm><indexterm><primary>points de
contrôle</primary></indexterm> (appelés
<foreignphrase>checkpoints</foreignphrase>) sont des
points qui garantissent que les fichiers de données ont été mis à
jour avec toutes les informations enregistrées dans le journal avant le
point de contrôle. Au moment du point de contrôle, toutes les
pages de données non propres sont écrites sur le disque et une
entrée spéciale, pour le point de contrôle, est écrite dans le
journal. (Les modifications étaient déjà envoyées dans les journaux de
transactions.)
En cas de défaillance, la procédure de récupération recherche le
dernier enregistrement d'un point de vérification dans les traces
(enregistrement connus sous le nom de <quote>redo log</quote>) à partir
duquel il devra lancer l'opération
REDO. Toute modification effectuée sur les fichiers de données avant ce point
est garantie d'avoir été enregistrée sur disque. Du coup, après un point de
vérification, tous les segments représentant des journaux de
transaction précédant celui
contenant le <quote>redo record</quote> ne sont plus nécessaires et peuvent
être soit recyclés soit supprimés (quand l'archivage des journaux de
transaction est activé, ces derniers doivent être archivés avant d'être
recyclés ou supprimés).
</para>
<para>
CHECKPOINT doit écrire toutes les pages de données modifiées sur disque, ce
qui peut causer une charge disque importante. Du coup, l'activité des
CHECKPOINT est diluée de façon à ce que les entrées/sorties disque
commencent au début du CHECKPOINT et se termine avant le démarrage du
prochain CHECKPOINT ; ceci minimise la dégradation des performances
lors des CHECKPOINT.
</para>
<para>
Le processus d'écriture en tâche de fond lance automatiquement un point de
contrôle de temps en temps : tous les <xref
linkend="guc-checkpoint-segments"/> journaux de transaction ou dès que <xref
linkend="guc-checkpoint-timeout"/> secondes se sont
écoulées. Les paramètres par défaut sont respectivement de trois journaux
et de 300 secondes. Il est également possible de forcer la création
d'un point de contrôle en utilisant la commande SQL
<command>CHECKPOINT</command>.
</para>
<para>
La réduction de <varname>checkpoint_segments</varname> et/ou
<varname>checkpoint_timeout</varname> implique
des points de contrôle plus fréquents. Cela permet une récupération
plus rapide après défaillance puisqu'il y a moins d'écritures à
synchroniser. Cependant, il faut équilibrer cela avec
l'augmentation du coût d'écriture des pages de données modifiées.
Si <xref linkend="guc-full-page-writes"/> est configuré (ce qui est la
valeur par
défaut), il reste un autre facteur à considérer. Pour s'assurer de la
cohérence des pages de données, la première modification d'une page de
données après chaque point de vérification résulte dans le traçage du contenu
entier de la page. Dans ce cas, un intervalle de points de vérification
plus petit augmentera le volume en sortie des journaux de transaction,
diminuant légèrement l'intérêt d'utiliser un intervalle plus petit et
impliquant
de toute façon plus d'entrées/sorties au niveau disque.
</para>
<para>
Les points de contrôle sont assez coûteux, tout d'abord parce qu'ils
écrivent tous les tampons utilisés, et ensuite parce que cela suscite un
trafic supplémentaire dans les journaux de transaction, comme indiqué
ci-dessus. Du coup, il est conseillé
de configurer les paramètres en relation assez haut pour que ces points de
contrôle ne surviennent pas trop fréquemment. Pour une vérification
rapide de l'adéquation de vos paramètres, vous pouvez configurer le
paramètre <xref
linkend="guc-checkpoint-warning"/>. Si les points de contrôle arrivent plus
rapidement que <varname>checkpoint_warning</varname> secondes, un message
est affiché dans les journaux applicatifs du serveur recommandant d'accroître
<varname>checkpoint_segments</varname>. Une apparition occasionnelle d'un
message ne doit pas vous alarmer mais, s'il apparaît souvent, alors les
paramètres de contrôle devraient être augmentés. Les opérations en masse,
comme les transferts importants de données via <command>COPY</command>,
pourraient être la cause
de l'apparition d'un tel nombre de messages d'avertissements si
vous n'avez pas configuré <varname>checkpoint_segments</varname> avec une valeur
suffisamment haute.
</para>
<para>
Pour éviter de remplir le système disque avec de très nombreuses
écritures de pages, l'écriture des pages modifiés pendant un point de
vérification est étalée sur une période de temps. Cette période est
contrôlée par <xref linkend="guc-checkpoint-completion-target"/>, qui
est donné comme une fraction de l'intervalle des points de vérification.
Le taux d'entrées/sorties est ajusté pour que le point de vérification
se termine quand la fraction donnée de
<varname>checkpoint_segments</varname> journaux de transaction a été
consommée ou quand la fraction donné de
<varname>checkpoint_timeout</varname> secondes s'est écoulée (la
condition que se verra vérifiée la première). Avec une valeur par
défaut de 0,5, <productname>PostgreSQL</productname> peut s'attendre à
terminer chaque point de vérification en moitié moins de temps qu'il ne
faudra pour lancer le prochain point de vérification. Sur un système
très proche du taux maximum en entrée/sortie pendant des opérations
normales, vous pouvez augmenter
<varname>checkpoint_completion_target</varname> pour réduire le chargement
en entrée/sortie dû aux points de vérification. L'inconvénient de ceci
est que prolonger les points de vérification affecte le temps de
récupération parce qu'il faudra conserver plus de journaux de transaction
si une récupération est nécessaire. Bien que
<varname>checkpoint_completion_target</varname> puisse valoir 1.0, il
est bien mieux de la configurer à une valeur plus basse que ça (au
maximum 0,9) car les points de vérification incluent aussi d'autres
activités en dehors de l'écriture des pages modifiées. Une valeur de 1,0
peut avoir pour résultat des points de vérification qui ne se terminent
pas à temps, ce qui aurait pour résultat des pertes de performance à
cause de variation inattendue dans le nombre de journaux nécessaires.
</para>
<para>
Il y aura toujours au moins un journal de transaction et normalement
pas plus de (2 + <varname>checkpoint_completion_target</varname>) *
<varname>checkpoint_segments</varname> + 1 journaux.
Chaque journal fait normalement 16 Mo (bien
que cette taille puisse être modifiée lors de la compilation du serveur).
Vous pouvez utiliser cela pour estimer l'espace disque nécessaire au
stockage des journaux de transaction. D'habitude, quand les vieux journaux
ne sont plus nécessaires, ils sont recyclés
(renommés pour devenir les prochains segments dans une séquence
numérotée). S'il y a plus de 3 * <varname>checkpoint_segments</varname> + 1
fichiers à cause d'un pic temporaire du taux d'écriture des journaux,
ceux inutilisés seront effacés au lieu d'être
recyclés jusqu'à ce que le système soit en-dessous de cette limite.
</para>
<para>
Il existe deux fonctions <acronym>WAL</acronym> internes couramment
utilisées :
<function>LogInsert</function> et <function>LogFlush</function>.
<function>LogInsert</function> est utilisée pour placer une
nouvelle entrée à l'intérieur des tampons <acronym>WAL</acronym> en mémoire
partagée. S'il n'y a plus
d'espace pour une nouvelle entrée, <function>LogInsert</function>
devra écrire (autrement dit, déplacer dans le cache du noyau) quelques
tampons <acronym>WAL</acronym> remplis. Ceci n'est pas désirable parce que
<function>LogInsert</function> est utilisée lors de chaque
modification bas niveau de la base (par exemple, lors de l'insertion d'une
ligne) quand un verrou exclusif est posé sur des pages de données
affectées. À cause de ce verrou, l'opération doit être aussi rapide
que possible. Pire encore, écrire des tampons <acronym>WAL</acronym>
peut forcer la création d'un nouveau journal, ce qui
peut prendre beaucoup plus de temps. Normalement, les tampons
<acronym>WAL</acronym> doivent être écrits et vidés par une requête
de <function>LogFlush</function> qui est faite, la plupart du
temps, au moment de la validation d'une transaction pour assurer
que les entrées de la transaction sont écrites vers un stockage
permanent. Sur les systèmes avec une importante écriture de journaux,
les requêtes de <function>LogFlush</function> peuvent ne pas
arriver assez souvent pour empêcher <function>LogInsert</function> d'avoir
à écrire lui-même sur disque. Sur de tels systèmes, on devrait augmenter le
nombre de tampons
<acronym>WAL</acronym> en modifiant le paramètre de configuration <xref
linkend="guc-wal-buffers"/>. Par défaut, le nombre de tampons est de 8.
Réhausser cette valeur augmente considérablement l'utilisation de la
mémoire partagée. Quand <xref linkend="guc-full-page-writes"/> est configuré
et que le système est très occupé, configurer cette variable avec une valeur
plus importante aide à avoir des temps de réponse plus réguliers
lors de la période suivant chaque point de vérification.
</para>
<para>
Le paramètre <xref linkend="guc-commit-delay"/> définit la durée
d'endormissement en micro-secondes du processus serveur après l'écriture
d'une entrée de validation dans le journal avec
<function>LogInsert</function> avant d'exécuter un
<function>LogFlush</function>. Ce délai permet aux autres
processus du serveur d'ajouter leurs entrées de validation dans le
journal afin de tout écrire vers le disque avec une seule
synchronisation du journal. Aucune mise en sommeil n'aura lieu si
<xref linkend="guc-fsync"/> n'est pas disponible ou si moins de
<xref linkend="guc-commit-siblings"/> autres sessions sont, à ce
moment, dans des transactions actives ; cela évite de dormir quand
il est improbable qu'une autre session fasse bientôt une
validation. Notez que dans la plupart des plate-formes, la
résolution d'une requête d'endormissement est de 10 millisecondes, donc
un <varname>commit_delay</varname> différent de zéro et configuré
entre 1 et 10000 micro-secondes a le même effet. Les bonnes
valeurs pour ce paramètre ne sont pas encore claires ; les essais
sont encouragés.
</para>
<para>
Le paramètre <xref linkend="guc-wal-sync-method"/> détermine la façon dont
<productname>PostgreSQL</productname> demande au noyau de forcer les mises
à jour des journaux de transaction sur le disque. Toutes les options
ont un même comportement dans la mesure où la fiabilité ne disparaît pas,
mais c'est avec des options spécifiques à la plate-forme que la rapidité
la plus importante sera observée. Notez que ce paramètre est ignoré si
<varname>fsync</varname> a été désactivé.
</para>
<para>
Activer le paramètre de configuration <xref linkend="guc-wal-debug"/> (à
supposer que <productname>PostgreSQL</productname> ait été compilé avec le
support de ce paramètre) permet d'enregistrer chaque appel
<acronym>WAL</acronym> à <function>LogInsert</function> et
<function>LogFlush</function> dans les journaux applicatifs du serveur.
Cette option
pourrait être remplacée par un mécanisme plus général dans le futur.
</para>
</sect1>
<sect1 id="wal-internals">
<title>Vue interne des journaux de transaction</title>
<para>
Le mécanisme <acronym>WAL</acronym> est automatiquement disponible ;
aucune action n'est requise de la part de l'administrateur excepté
de s'assurer que l'espace disque requis par les journaux de transaction
soit présent et que tous les réglages soient faits (regardez
la <xref linkend="wal-configuration"/>).
</para>
<para>
Les journaux de transaction sont stockés dans le répertoire
<filename>pg_xlog</filename> sous le répertoire de données, comme un ensemble
de fichiers, chacun d'une taille de 16 Mo généralement (cette taille
pouvant être modifiée en précisant une valeur pour l'option
<option>--with-wal-segsize</option> de configure lors de la construction
du serveur). Chaque fichier est divisé en pages de généralement 8 Ko
(cette taille pouvant être modifiée en précisant une valeur pour l'option
<option>--with-wal-blocksize</option> de configure). Les en-têtes de
l'entrée du journal sont décrites dans
<filename>access/xlog.h</filename> ; le contenu de l'entrée dépend
du type de l'événement qui est enregistré. Les fichiers
sont nommés suivant un nombre qui est toujours incrémenté et qui
commence à <filename>000000010000000000000000</filename>. Les nombres ne
bouclent pas actuellement, mais cela devrait prendre beaucoup de temps
pour épuiser le stock de nombres disponibles.
</para>
<para>
Il est avantageux que les journaux soient situés sur un autre disque que
celui des fichiers principaux de la base de données. Cela peut
se faire en déplaçant le répertoire
<filename>pg_xlog</filename> vers un autre emplacement (alors que
le serveur est arrêté) et en créant un lien
symbolique de l'endroit d'origine dans le répertoire principal de
données au nouvel emplacement.
</para>
<para>
Le but de <acronym>WAL</acronym>, s'assurer que le journal est écrit
avant l'altération des entrées dans la base, peut être mis en échec par
les disques<indexterm><primary>disques durs</primary></indexterm> qui
rapportent une écriture
réussie au noyau quand, en fait, ils ont seulement mis en cache
les données et ne les ont pas encore stockés sur le disque. Une
coupure de courant dans ce genre de situation peut toujours mener à
une corruption irrécupérable des données. Les administrateurs
devraient s'assurer que les disques contenant les journaux de
transaction de <productname>PostgreSQL</productname> ne
produisent pas ce genre de faux rapports.
</para>
<para>
Après qu'un point de contrôle ait été fait et que le journal ait été
écrit, la position du point de contrôle est sauvegardée dans le
fichier <filename>pg_control</filename>. Donc, quand la
restauration doit se faire, le serveur lit en premier
<filename>pg_control</filename> et ensuite l'entrée du point de
contrôle ; ensuite, il exécute l'opération REDO en parcourant vers
l'avant à partir de la position du journal indiquée dans l'entrée du
point de contrôle. Parce que l'ensemble du contenu des pages de
données est sauvegardé dans le journal à la première modification de
page après un point de contrôle (en supposant que <xref
linkend="guc-full-page-writes"/> n'est pas désactivé), toutes les pages
changées depuis le point de contrôle seront restaurées dans un état cohérent.
</para>
<para>
Pour gérer le cas où <filename>pg_control</filename> est corrompu, nous
devons permettre le parcours des segments de journaux
existants en ordre inverse — du plus récent au plus ancien — pour
trouver le dernier point de vérification. Ceci n'a pas encore été implémenté.
<filename>pg_control</filename> est assez petit (moins d'une page disque)
pour ne pas être sujet aux problèmes d'écriture partielle et, au moment où
ceci est écrit, il n'y a eu aucun rapport d'échecs de la base de données
uniquement à cause de son incapacité à lire <filename>pg_control</filename>.
Donc, bien que cela soit théoriquement un point faible,
<filename>pg_control</filename> ne semble pas être un problème en pratique.
</para>
</sect1>
</chapter>