This repository has been archived by the owner on May 26, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 71
/
postgresql_backup.tex
193 lines (121 loc) · 20 KB
/
postgresql_backup.tex
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
\chapter{Бэкап и восстановление PostgreSQL}
\begin{epigraphs}
\qitem{Есть два типа администраторов~--- те, кто не делает бэкапы, и те, кто уже делает}{Народная мудрость}
\qitem{Если какая-нибудь неприятность может произойти, она случается}{Закон Мэрфи}
\end{epigraphs}
\section{Введение}
Любой хороший сисадмин знает~--- бэкапы нужны всегда. Насколько бы надежной ни казалась Ваша система, всегда может произойти случай, который был не учтен, и из-за которого могут быть потеряны данные.
Тоже самое касается и PostgreSQL баз данных. Посыпавшийся винчестер на сервере, ошибка в файловой системе, ошибка в другой программе, которая перетерла весь каталог PostgreSQL и многое другое приведет только к плачевному результату. И даже если у Вас репликация с множеством слейвов, это не означает, что система в безопасности~--- неверный запрос на мастер (\lstinline!DELETE/DROP/TRUNCATE!), и у слейвов такая же порция данных (точнее их отсутствие).
Существуют три принципиально различных подхода к резервному копированию данных PostgreSQL:
\begin{itemize}
\item SQL бэкап;
\item Бэкап уровня файловой системы;
\item Непрерывное резервное копирование;
\end{itemize}
Каждый из этих подходов имеет свои сильные и слабые стороны.
\section{SQL бэкап}
Идея этого подхода в создании текстового файла с командами SQL. Такой файл можно передать обратно на сервер и воссоздать базу данных в том же состоянии, в котором она была во время бэкапа. У PostgreSQL для этого есть специальная утилита~--- \lstinline!pg_dump!. Пример использования \lstinline!pg_dump!:
\begin{lstlisting}[language=Bash,label=lst:backups1,caption=Создаем бэкап с помощью pg\_dump]
$ pg_dump dbname > outfile
\end{lstlisting}
Для восстановления такого бэкапа достаточно выполнить:
\begin{lstlisting}[language=Bash,label=lst:backups2,caption=Восстанавливаем бэкап]
$ psql dbname < infile
\end{lstlisting}
При этом базу данных \lstinline!dbname! потребуется создать перед восстановлением. Также потребуется создать пользователей, которые имеют доступ к данным, которые восстанавливаются (это можно и не делать, но тогда просто в выводе восстановления будут ошибки). Если нам требуется, чтобы восстановление прекратилось при возникновении ошибки, тогда потребуется восстанавливать бэкап таким способом:
\begin{lstlisting}[language=Bash,label=lst:backups3,caption=Восстанавливаем бэкап]
$ psql --set ON_ERROR_STOP=on dbname < infile
\end{lstlisting}
Также, можно делать бэкап и сразу восстанавливать его в другую базу:
\begin{lstlisting}[language=Bash,label=lst:backups4,caption=Бэкап в другую БД]
$ pg_dump -h host1 dbname | psql -h host2 dbname
\end{lstlisting}
После восстановления бэкапа желательно запустить \lstinline!ANALYZE!, чтобы оптимизатор запросов обновил статистику.
А что, если нужно сделать бэкап не одной базы данных, а всех, да и еще получить в бэкапе информацию про роли и таблицы? В таком случае у PostgreSQL есть утилита \lstinline!pg_dumpall!. \lstinline!pg_dumpall! используется для создания бэкапа данных всего кластера PostgreSQL:
\begin{lstlisting}[language=Bash,label=lst:backups5,caption=Бэкап кластера PostgreSQL]
$ pg_dumpall > outfile
\end{lstlisting}
Для восстановления такого бэкапа достаточно выполнить от суперпользователя:
\begin{lstlisting}[language=Bash,label=lst:backups6,caption=Восстановления бэкапа PostgreSQL]
$ psql -f infile postgres
\end{lstlisting}
\subsection{SQL бэкап больших баз данных}
Некоторые операционные системы имеют ограничения на максимальный размер файла, что может вызывать проблемы при создании больших бэкапов через \lstinline!pg_dump!. К счастью, \lstinline!pg_dump! можете бэкапить в стандартный вывод. Так что можно использовать стандартные инструменты Unix, чтобы обойти эту проблему. Есть несколько возможных способов:
\begin{itemize}
\item \textbf{Использовать сжатие для бэкапа}
Можно использовать программу сжатия данных, например GZIP:
\begin{lstlisting}[language=Bash,label=lst:backups7,caption=Сжатие бэкапа PostgreSQL]
$ pg_dump dbname | gzip > filename.gz
\end{lstlisting}
Восстановление:
\begin{lstlisting}[language=Bash,label=lst:backups8,caption=Восстановление бэкапа PostgreSQL]
$ gunzip -c filename.gz | psql dbname
\end{lstlisting}
или
\begin{lstlisting}[language=Bash,label=lst:backups9,caption=Восстановление бэкапа PostgreSQL]
cat filename.gz | gunzip | psql dbname
\end{lstlisting}
\item \textbf{Использовать команду split}
Команда split позволяет разделить вывод в файлы меньшего размера, которые являются подходящими по размеру для файловой системы. Например, бэкап делится на куски по 1 мегабайту:
\begin{lstlisting}[language=Bash,label=lst:backups10,caption=Создание бэкапа PostgreSQL]
$ pg_dump dbname | split -b 1m - filename
\end{lstlisting}
Восстановление:
\begin{lstlisting}[language=Bash,label=lst:backups11,caption=Восстановление бэкапа PostgreSQL]
$ cat filename* | psql dbname
\end{lstlisting}
\item \textbf{Использовать пользовательский формат дампа \lstinline!pg_dump!}
PostgreSQL построен на системе с библиотекой сжатия Zlib, поэтому пользовательский формат бэкапа будет в сжатом виде. Это похоже на метод с использованием GZIP, но он имеет дополнительное преимущество~--- таблицы могут быть восстановлены выборочно. Минус такого бэкапа~--- восстановить возможно только в такую же версию PostgreSQL (отличаться может только патч релиз, третья цифра после точки в версии):
\begin{lstlisting}[language=Bash,label=lst:backups12,caption=Создание бэкапа PostgreSQL]
$ pg_dump -Fc dbname > filename
\end{lstlisting}
Через psql такой бэкап не восстановить, но для этого есть утилита \lstinline!pg_restore!:
\begin{lstlisting}[language=Bash,label=lst:backups13,caption=Восстановление бэкапа PostgreSQL]
$ pg_restore -d dbname filename
\end{lstlisting}
\end{itemize}
При слишком большой базе данных, вариант с командой split нужно комбинировать со сжатием данных.
\section{Бэкап уровня файловой системы}
Альтернативный метод резервного копирования заключается в непосредственном копировании файлов, которые PostgreSQL использует для хранения данных в базе данных. Например:
\begin{lstlisting}[language=Bash,label=lst:backups14,caption=Бэкап PostgreSQL файлов]
$ tar -cf backup.tar /usr/local/pgsql/data
\end{lstlisting}
Но есть два ограничения, которые делает этот метод нецелесообразным, или, по крайней мере, уступающим SQL бэкапу:
\begin{itemize}
\item PostgreSQL база данных должна быть остановлена, для того, чтобы получить актуальный бэкап (PostgreSQL держит множество объектов в памяти, буферизация файловой системы). Излишне говорить, что во время восстановления такого бэкапа потребуется также остановить PostgreSQL;
\item Не получится восстановить только определенные данные с такого бэкапа;
\end{itemize}
Как альтернатива, можно делать снимки (snapshot) файлов системы (папки с файлами PostgreSQL). В таком случае останавливать PostgreSQL не требуется. Однако, резервная копия, созданная таким образом, сохраняет файлы базы данных в состоянии, как если бы сервер базы данных был неправильно остановлен. Поэтому при запуске PostgreSQL из резервной копии, он будет думать, что предыдущий экземпляр сервера вышел из строя и восстановит данные в соответствии с данными журнала WAL. Это не проблема, просто надо знать про это (и не забыть включить WAL файлы в резервную копию). Также, если файловая система PostgreSQL распределена по разным файловым системам, то такой метод бэкапа будет очень ненадежным~--- снимки файлов системы должны быть сделаны одновременно. Почитайте документацию файловой системы очень внимательно, прежде чем доверять снимкам файлов системы в таких ситуациях.
Также возможен вариант с использованием \lstinline!rsync! утилиты. Первым запуском rsync мы копируем основные файлы с директории PostgreSQL (PostgreSQL при этом продолжает работу). После этого мы останавливаем PostgreSQL и запускаем повторно \lstinline!rsync!. Второй запуск \lstinline!rsync! пройдет гораздо быстрее, чем первый, потому что будет передавать относительно небольшой размер данных, и конечный результат будет соответствовать остановленной СУБД. Этот метод позволяет делать бэкап уровня файловой системы с минимальным временем простоя.
\section{Непрерывное резервное копирование}
PostgreSQL поддерживает упреждающую запись логов (Write Ahead Log, WAL) в \lstinline!pg_xlog! директорию, которая находится в директории данных СУБД. В логи пишутся все изменения, сделанные с данными в СУБД. Этот журнал существует прежде всего для безопасности во время краха PostgreSQL: если происходят сбои в системе, базы данных могут быть восстановлены с помощью <<перезапуска>> этого журнала. Тем не менее, существование журнала делает возможным использование третьей стратегии для резервного копирования баз данных: мы можем объединить бэкап уровня файловой системы с резервной копией WAL файлов. Если требуется восстановить такой бэкап, то мы восстанавливаем файлы резервной копии файловой системы, а затем <<перезапускаем>> с резервной копии файлов WAL для приведения системы к актуальному состоянию. Этот подход является более сложным для администрирования, чем любой из предыдущих подходов, но он имеет некоторые преимущества:
\begin{itemize}
\item Не нужно согласовывать файлы резервной копии системы. Любая внутренняя противоречивость в резервной копии будет исправлена путем преобразования журнала (не отличается от того, что происходит во время восстановления после сбоя);
\item Восстановление состояния сервера для определенного момента времени;
\item Если мы постоянно будем <<скармливать>> файлы WAL на другую машину, которая была загружена с тех же файлов резервной базы, то у нас будет находящийся всегда в актуальном состоянии резервный сервер PostgreSQL (создание сервера горячего резерва);
\end{itemize}
Как и бэкап файловой системы, этот метод может поддерживать только восстановление всей базы данных кластера. Кроме того, он требует много места для хранения WAL файлов.
\subsection{Настройка}
Первый шаг~--- активировать архивирование. Эта процедура будет копировать WAL файлы в архивный каталог из стандартного каталога \lstinline!pg_xlog!. Это делается в файле \lstinline!postgresql.conf!:
\begin{lstlisting}[label=lst:backups15,caption=Настройка архивирования]
archive_mode = on # enable archiving
archive_command = 'cp -v %p /data/pgsql/archives/%f'
archive_timeout = 300 # timeout to close buffers
\end{lstlisting}
После этого необходимо перенести файлы (в порядке их появления) в архивный каталог. Для этого можно использовать функцию \lstinline!rsync!. Можно поставить функцию в \lstinline!cron! и, таким образом, файлы могут автоматически перемещаться между хостами каждые несколько минут:
\begin{lstlisting}[language=Bash,label=lst:backups16,caption=Копирование WAL файлов на другой хост]
$ rsync -avz --delete prod1:/data/pgsql/archives/ \
/data/pgsql/archives/ > /dev/null
\end{lstlisting}
В конце необходимо скопировать файлы в каталог \lstinline!pg_xlog! на сервере PostgreSQL (он должен быть в режиме восстановления). Для этого необходимо в каталоге данных PostgreSQL создать файл \lstinline!recovery.conf! с заданной командой копирования файлов из архива в нужную директорию:
\begin{lstlisting}[label=lst:backups17,caption=recovery.conf]
restore_command = 'cp /data/pgsql/archives/%f "%p"'
\end{lstlisting}
Документация PostgreSQL предлагает хорошее описание настройки непрерывного копирования, поэтому данная глава не будет углубляться в детали (например, как перенести директорию СУБД с одного сервера на другой, какие могут быть проблемы). Более подробно вы можете почитать по \href{http://www.postgresql.org/docs/current/static/continuous-archiving.html}{этой ссылке}.
\section{Утилиты для непрерывного резервного копирования}
Непрерывное резервное копирования - один из лучших способов для создания бэкапов и их восстановления. Нередко бэкапы сохраняются на той же файловой системе, на которой расположена база данных. Это не очень безопасно, т.к. при выходе дисковой системы сервера из строя вы можете потерять все данные (и базу, и бэкапы), или попросту столкнуться с тем, что на жестком диске закончится свободное место. Поэтому лучше, когда бэкапы складываются на отдельный сервер или в <<облачное хранилище>> (например \href{http://aws.amazon.com/s3/}{AWS S3}). Чтобы не писать свой <<велосипед>> для автоматизации этого процесса на сегодняшний день существует набор программ, которые облегчают процесс настройки и поддержки процесса создания бэкапов на основе непрерывного резервного копирования.
\input{backups/wal_e}
\input{backups/barman}
\input{backups/pg_arman}
\section{Заключение}
В любом случае, усилия и время, затраченные на создание оптимальной системы создания бэкапов, будут оправданы. Невозможно предугадать когда произойдут проблемы с базой данных, поэтому бэкапы должны быть настроены для PostgreSQL (особенно, если это продакшн система).