From 59ff4848942fcc4812ce93bf91db3663c5d1c1f0 Mon Sep 17 00:00:00 2001 From: Tom Lane <tgl@sss.pgh.pa.us> Date: Tue, 3 Aug 2004 23:42:59 +0000 Subject: [PATCH] Preliminary documentation for PITR. --- doc/src/sgml/backup.sgml | 454 +++++++++++++++++++++++++++++++++++++- doc/src/sgml/runtime.sgml | 26 ++- 2 files changed, 477 insertions(+), 3 deletions(-) diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml index 8b171f3697e..3b45ec17def 100644 --- a/doc/src/sgml/backup.sgml +++ b/doc/src/sgml/backup.sgml @@ -1,5 +1,5 @@ <!-- -$PostgreSQL: pgsql/doc/src/sgml/backup.sgml,v 2.40 2004/08/03 20:32:30 tgl Exp $ +$PostgreSQL: pgsql/doc/src/sgml/backup.sgml,v 2.41 2004/08/03 23:42:59 tgl Exp $ --> <chapter id="backup"> <title>Backup and Restore</title> @@ -381,6 +381,14 @@ tar -cf backup.tar /usr/local/pgsql/data <sect1 id="backup-online"> <title>On-line backup and point-in-time recovery</title> + <indexterm zone="backup"> + <primary>on-line backup</primary> + </indexterm> + + <indexterm zone="backup"> + <primary>point-in-time recovery</primary> + </indexterm> + <para> At all times, <productname>PostgreSQL</> maintains a <firstterm>write ahead log</> (WAL) that shows details of every change made to the database's data @@ -424,7 +432,7 @@ tar -cf backup.tar /usr/local/pgsql/data <listitem> <para> If we continuously feed the series of WAL files to another machine - that's been loaded with the same base backup, we have a <quote>hot + that's been loaded with the same base backup file, we have a <quote>hot standby</> system: at any point we can bring up the second machine and it will have a nearly-current copy of the database. </para> @@ -441,6 +449,448 @@ tar -cf backup.tar /usr/local/pgsql/data many situations where high reliability is needed. </para> + <para> + To recover successfully using an on-line backup, you need a continuous + sequence of archived WAL files that extends back at least as far as the + start time of your backup. So to get started, you should set up and test + your procedure for archiving WAL files <emphasis>before</> you take your + first base backup. Accordingly, we first discuss the mechanics of + archiving WAL files. + </para> + + <sect2 id="backup-archiving-wal"> + <title>Setting up WAL archiving</title> + + <para> + In an abstract sense, a running <productname>PostgreSQL</> system + produces an indefinitely long sequence of WAL records. The system + physically divides this sequence into WAL <firstterm>segment files</>, + which are normally 16Mb apiece (although the size can be altered when + building the server). The segment files are given numeric names that + reflect their position in the abstract WAL sequence. When not using WAL + archiving, the system normally creates just a few segment files and then + <quote>recycles</> them by renaming no-longer-needed segment files to + higher segment numbers. It's assumed that a segment file whose contents + precede the checkpoint-before-last is no longer of interest and can be + recycled. + </para> + + <para> + When archiving WAL data, we want to capture the contents of each segment + file once it is filled, and save that data somewhere before the segment + file is recycled for reuse. Depending on the application and the + available hardware, there could be many different ways of <quote>saving + the data somewhere</>: we could copy the segment files to an NFS-mounted + directory on another machine, or write them onto a tape drive, or batch + them together and burn them onto CDs, or something else entirely. To + provide the database administrator with as much flexibility as possible, + <productname>PostgreSQL</> tries not to make any assumptions about how + the archiving will be done. Instead, <productname>PostgreSQL</> lets + the administrator specify a shell command to be executed to copy a + completed segment file to wherever it needs to go. The command could be + as simple as a <application>cp</>, or it could invoke a complex shell + script --- it's all up to you. + </para> + + <para> + The shell command to use is specified by the <xref + linkend="guc-archive-command"> configuration parameter, which in practice + will always be placed in the <filename>postgresql.conf</filename> file. + In this string, + any <literal>%p</> is replaced by the absolute path of the file to + archive, while any <literal>%f</> is replaced by the file name only. + Write <literal>%%</> if you need to embed an actual <literal>%</> + character in the command. The simplest useful command is something + like +<programlisting> +archive_command = 'cp %p /mnt/server/archivedir/%f' +</programlisting> + which will copy archivable WAL segments to the directory + <literal>/mnt/server/archivedir</>. + </para> + + <para> + The archive command will be executed under the ownership of the same + user that the <productname>PostgreSQL</> server is running as. Since + the series of WAL files being archived contains effectively everything + in your database, you will want to be sure that the archived data is + protected from prying eyes; for example, archive into a directory that + does not have group or world read access. + </para> + + <para> + It is important that the archive command return zero exit status if and + only if it succeeded. Upon getting a zero result, + <productname>PostgreSQL</> will assume that the WAL segment file has been + successfully archived, and it may be overwritten with new data very + soon thereafter. However, a nonzero status tells + <productname>PostgreSQL</> that the file was not archived; it will try + again periodically until it succeeds. + </para> + + <para> + Speed of the archiving command is not important, so long as it can keep up + with the average rate at which your server generates WAL data. It is okay + if the archiving process falls a little behind (or even a lot behind, if + you don't mind the <literal>pg_xlog/</> directory filling up with + not-yet-archived segment files). + </para> + + <para> + If you are concerned about being able to recover right up to the current + instant, you may want to take additional steps to ensure that the current, + partially-filled WAL segment is also copied someplace. This is + particularly important if your server generates only little WAL traffic + (or has slack periods where it does so), since it could take a long time + before a WAL segment file is completely filled and ready to archive. + One possible way to handle this is to set up a <application>cron</> job + that periodically (once a minute, perhaps) identifies the current WAL + segment file and saves it someplace safe. The combination of the archived + WAL segments and the saved current segment will then be enough to ensure + you can always restore to within a minute of current time. This behavior + is not presently built into <productname>PostgreSQL</> because we did not + want to complicate the definition of the <xref + linkend="guc-archive-command"> by requiring it to keep track of + successively archived, but different, copies of the same WAL file. + The <xref linkend="guc-archive-command"> is only invoked on finished + WAL segments that will not change anymore; and except in the case of + retrying a failure, it will be called only once for any given file name. + </para> + + <para> + In writing your archive command, you should assume that the filenames to + be archived may be up to 64 characters long and may contain any + combination of ASCII letters, digits, and dots. It is not necessary to + remember the original full path (<literal>%p</>) but it is necessary to + remember the file name (<literal>%f</>). + </para> + </sect2> + + <sect2 id="backup-base-backup"> + <title>Making a Base Backup</title> + + <para> + The procedure for making a base backup is relatively simple: + <orderedlist> + <listitem> + <para> + Ensure that WAL archiving is enabled and working. + </para> + </listitem> + <listitem> + <para> + Connect to the database as a superuser, and issue the command +<programlisting> +SELECT pg_start_backup('label'); +</programlisting> + where <literal>label</> is any string you want to use to uniquely + identify this backup operation. (One good practice is to use the + full path where you intend to put the backup dump file.) It does + not matter which database within the cluster you connect to to issue + this command. You can ignore the result returned by the function; + but if it reports an error, deal with that before proceeding. + </para> + </listitem> + <listitem> + <para> + Perform the backup, using any convenient filesystem-backup tool + such as <application>tar</> or <application>cpio</>. It is neither + necessary nor desirable to stop normal operation of the database + while you do this. + </para> + </listitem> + <listitem> + <para> + Again connect to the database as a superuser, and issue the command +<programlisting> +SELECT pg_stop_backup(); +</programlisting> + If this returns successfully, you're done. + </para> + </listitem> + </orderedlist> + </para> + + <para> + It is not necessary to be very concerned about the amount of time elapsed + between <function>pg_start_backup</> and the start of the actual backup, + nor between the end of the backup and <function>pg_stop_backup</>; a + few minutes' delay won't hurt anything. You + must however be quite sure that these operations are carried out in + sequence and don't overlap. + </para> + + <para> + Be certain that your backup dump includes all of the files underneath + the database cluster directory (e.g., <literal>/usr/local/pgsql/data</>). + If you are using tablespaces that do not reside underneath this directory, + be careful to include them as well (and be sure that your backup dump + archives symbolic links as links, otherwise the restore will mess up + your tablespaces). + </para> + + <para> + You may, however, omit from the backup dump the files within the + <literal>pg_xlog/</> subdirectory of the cluster directory. This + slight complication is worthwhile because it reduces the risk + of mistakes when restoring. This is easy to arrange if + <literal>pg_xlog/</> is a symbolic link pointing to someplace outside + the cluster directory, which is a common setup anyway for performance + reasons. + </para> + + <para> + To make use of this backup, you will need to keep around all the WAL + segment files generated at or after the starting time of the backup. + To aid you in doing this, the <function>pg_stop_backup</> function + creates a <firstterm>backup history file</> that is immediately stored + into the WAL archive area. This file is named after the first WAL + segment file that you need to have to make use of the backup. For + example, if the starting WAL file is <literal>0000000100001234000055CD</> + the backup history file will be named something like + <literal>0000000100001234000055CD.007C9330.backup</>. (The second part of + this file name stands for an exact position within the WAL file, and can + ordinarily be ignored.) Once you have safely archived the backup dump + file, you can delete all archived WAL segments with names numerically + preceding this one. The backup history file is just a small text file. + It contains the label string you gave to <function>pg_start_backup</>, as + well as the starting and ending times of the backup. If you used the + label to identify where the associated dump file is kept, then the + archived history file is enough to tell you which dump file to restore, + should you need to do so. + </para> + + <para> + Since you have to keep around all the archived WAL files back to your + last full dump, your interval between full dumps would usually be chosen + based on how much storage you want to expend on archived WAL files. + You should also consider how long you are prepared to spend recovering, + if recovery should be necessary --- the system will have to replay all + those segments, and that could take awhile if it's been a long time + since the full dump. + </para> + + <para> + It's also worth noting that the <function>pg_start_backup</> function + makes a file named <literal>backup_label</> in the database cluster + directory, which is then removed again by <function>pg_stop_backup</>. + This file will of course be archived as a part of your backup dump file. + The backup label file includes the label string you gave to + <function>pg_start_backup</>, as well as the time at which + <function>pg_start_backup</> was run, and the name of the starting WAL + file. In case of confusion it will + therefore be possible to look inside a backup dump file and determine + exactly which backup session the dump file came from. + </para> + + <para> + It is also possible to make a backup dump while the postmaster is + stopped. In this case, obviously you can't use + <function>pg_start_backup</> or <function>pg_stop_backup</>, and + you will therefore be left to your own devices to keep track of which + backup dump is which and how far back the associated WAL files go. + It's generally better to follow the on-line backup procedure above. + </para> + </sect2> + + <sect2 id="backup-pitr-recovery"> + <title>Recovering with an On-line Backup</title> + + <para> + Okay, the worst has happened and you need to recover from your backup. + Here is the procedure: + <orderedlist> + <listitem> + <para> + Stop the postmaster, if it's running, and clean out all existing files + under the cluster data directory and under the root directories of any + tablespaces you are using. + (If there are recent, unarchived WAL segment files in + <literal>pg_xlog/</> that you want to use during restore, move these aside + instead of removing them.) + </para> + </listitem> + <listitem> + <para> + Restore the database files from your backup dump. Be careful that they + are restored with the right ownership (the database system user, not + root!) and with the right permissions. If you are using tablespaces, + you may want to verify that the symbolic links in <literal>pg_tblspc/</> + were correctly restored. + </para> + </listitem> + <listitem> + <para> + Remove any files present in <literal>pg_xlog/</>; these came from the + backup dump and are therefore probably obsolete rather than current. + If you didn't archive <literal>pg_xlog/</> at all, then re-create it, + and be sure to re-create the subdirectory + <literal>pg_xlog/archive_status/</> as well. + </para> + </listitem> + <listitem> + <para> + If you had unarchived WAL segment files that you saved aside in step 1, + copy them into <literal>pg_xlog/</>. (It's best to copy them, not move + them back in, so that you still have the unmodified files if the worst + happens and you have to start over.) + </para> + </listitem> + <listitem> + <para> + Create a recovery command file <literal>recovery.conf</> in the cluster + data directory, as discussed below. You may also want to temporarily + modify <literal>pg_hba.conf</> to prevent ordinary users from connecting + until you are sure the recovery has worked. + </para> + </listitem> + <listitem> + <para> + Start the postmaster. The postmaster will go into recovery mode and + proceed to read through the archived WAL files it needs. Upon completion + of the recovery process, the postmaster will rename + <literal>recovery.conf</> to <literal>recovery.done</> (to prevent + accidentally re-entering recovery mode in case of a crash later) and then + commence normal database operations. + </para> + </listitem> + <listitem> + <para> + Inspect the contents of the database to ensure you have recovered to + where you want to be. If not, return to step 1. If all is well, + let in your users by restoring <literal>pg_hba.conf</> to normal. + </para> + </listitem> + </orderedlist> + </para> + + <para> + The key part of all this is to set up a recovery command file + that describes how you want to recover and how far the recovery + should run. You can use <literal>recovery.conf.sample</> (normally + installed in the installation <literal>share/</> directory) as a + prototype. The one thing that you absolutely must specify in + <literal>recovery.conf</> is the <literal>restore_command</>, + which tells how to get back archived WAL file segments. Like + the <literal>archive_command</>, this is a shell command string. + It may contain <literal>%f</>, + which is replaced by the name of the desired log file, and <literal>%p</>, + which is replaced by the absolute path to copy the log file to. + Write <literal>%%</> if you need to embed an actual <literal>%</> + character in the command. The simplest useful command is something + like +<programlisting> +restore_command = 'cp /mnt/server/archivedir/%f %p' +</programlisting> + which will copy previously archived WAL segments from the directory + <literal>/mnt/server/archivedir</>. You could of course use something + much more complicated, perhaps even a shell script that requests the + operator to mount an appropriate tape. + </para> + + <para> + It is important that the command return nonzero exit status on failure. + The command <emphasis>will</> be asked for log files that are not present + in the archive; it must return nonzero when so asked. This is not an + error condition. Be aware also that the basename of the <literal>%p</> + path will be different from <literal>%f</>; do not expect them to be + interchangeable. + </para> + + <para> + WAL segments that cannot be found in the archive will be sought in + <literal>pg_xlog/</>; this allows use of recent un-archived segments. + However segments that are available from the archive will be used in + preference to files in <literal>pg_xlog/</>. The system will not + overwrite the existing contents of <literal>pg_xlog/</> when retrieving + archived files. + </para> + + <para> + Normally, recovery will proceed through all available WAL segments, + thereby restoring the database to current time (or as close as we can + get given the available WAL segments). But if you want to recover to + some previous point in time (say, right before the junior DBA dropped your + main transaction table), just specify the required stopping point in + <literal>recovery.conf</>. You can specify the stop point either by + date/time or by transaction ID. As of this writing only the date/time + option is very usable, since there are no tools to help you identify + which transaction ID to use. Note that the stop point must be after + the ending time of the backup (ie, the time of + <function>pg_stop_backup</>). You cannot use a base backup to recover + to a time when that backup was still going on. (To recover to such + a time, you must go back to your previous base backup and roll forward + from there.) + </para> + </sect2> + + <sect2 id="backup-timelines"> + <title>Timelines</title> + + <indexterm zone="backup"> + <primary>timelines</primary> + </indexterm> + + <para> + The ability to restore the database to a previous point in time creates + some complexities that are akin to science-fiction stories about time + travel and parallel universes. In the original history of the database, + perhaps you dropped a critical table at 5:15PM on Tuesday evening. + Unfazed, you get out your backup, restore to the point-in-time 5:14PM + Tuesday evening, and are up and running. In <emphasis>this</> history of + the database universe, you never dropped the table at all. But suppose + you later realize this wasn't such a great idea after all, and would like + to return to some later point in the original history? You won't be able + to if, while your database was up-and-running, it overwrote some of the + sequence of WAL segment files that led up to the time you now wish you + could get back to. So you really want to distinguish the series of + WAL records generated after you've done a point-in-time recovery from + those that were generated in the original database history. + </para> + + <para> + To deal with these problems, <productname>PostgreSQL</> has a notion + of <firstterm>timelines</>. Each time you recover to a point-in-time + earlier than the end of the WAL sequence, a new timeline is created + to identify the series of WAL records generated after that recovery. + (If recovery proceeds all the way to the end of WAL, however, we do not + start a new timeline: we just extend the existing one.) The timeline + ID number is part of WAL segment file names, and so a new timeline does + not overwrite the WAL data generated by previous timelines. It is + in fact possible to archive many different timelines. While that might + seem like a useless feature, it's often a lifesaver. Consider the + situation where you aren't quite sure what point-in-time to recover to, + and so have to do several point-in-time recoveries by trial and error + until you find the best place to branch off from the old history. Without + timelines this process would soon generate an unmanageable mess. With + timelines, you can recover to <emphasis>any</> prior state, including + states in timeline branches that you later abandoned. + </para> + + <para> + Each time a new timeline is created, <productname>PostgreSQL</> creates + a <quote>timeline history</> file that shows which timeline it branched + off from and when. These history files are necessary to allow the system + to pick the right WAL segment files when recovering from an archive that + contains multiple timelines. Therefore, they are archived into the WAL + archive area just like WAL segment files. The history files are just + small text files, so it's cheap and appropriate to keep them around + indefinitely (unlike the segment files which are large). You can, if + you like, add comments to a history file to make your own notes about + how and why this particular timeline came to be. Such comments will be + especially valuable when you have a thicket of different timelines as + a result of experimentation. + </para> + + <para> + The default behavior of recovery is to recover along the same timeline + that was current when the base backup was taken. If you want to recover + into some child timeline (that is, you want to return to some state that + was itself generated after a recovery attempt), you need to specify the + target timeline in <literal>recovery.conf</>. You cannot recover into + timelines that branched off earlier than the base backup. + </para> + </sect2> </sect1> <sect1 id="migration"> diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml index d552e6a34ff..95a8c23c822 100644 --- a/doc/src/sgml/runtime.sgml +++ b/doc/src/sgml/runtime.sgml @@ -1,5 +1,5 @@ <!-- -$PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.270 2004/07/24 19:51:22 tgl Exp $ +$PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.271 2004/08/03 23:42:59 tgl Exp $ --> <Chapter Id="runtime"> @@ -1342,6 +1342,30 @@ SET ENABLE_SEQSCAN TO OFF; </para> </listitem> </varlistentry> + + </variablelist> + </sect3> + <sect3 id="runtime-config-wal-archiving"> + <title>Archiving</title> + + <variablelist> + <varlistentry id="guc-archive-command" xreflabel="archive_command"> + <term><varname>archive_command</varname> (<type>string</type>)</term> + <listitem> + <para> + The shell command to execute to archive a completed segment of the + WAL file series. If this is an empty string (which is the default), + WAL archiving is disabled. Any <literal>%p</> in the string is + replaced + by the absolute path of the file to archive, while any <literal>%f</> + is replaced by the file name only. Write <literal>%%</> if you need + to embed an actual <literal>%</> character in the command. For more + information see <xref linkend="backup-archiving-wal">. This option + can only be set at server start or in the + <filename>postgresql.conf</filename> file. + </para> + </listitem> + </varlistentry> </variablelist> </sect3> -- GitLab