Восстановление данных в MySQL из снимка EBS

от автора

Это короткое руководство, возможно, поможет кому-то, кто использует AWS (и, в частности, MySQL на инстансе EC2), восстановить данные в MySQL из снимка EBS (регулярное создание которых любой предусмотрительный системный администратор, конечно же, настраивает заблаговременно — с помощью ec2‑consistent‑snapshot, например)

Прежде всего нужно открыть EC2 Management Console, и в разделе ELASTIC BLOCK STORE → Snapshots найти подходящий снимок (обычно это последний снимок раздела).

Далее нужно щёлкнуть на снимке правой кнопкой мышки и выбрать «Create Volume». В Availability Zone при этом нужно выбрать тот же регион, в котором находится инстанс EC2.

После этого нужно перейти в раздел ELASTIC BLOCK STORE → Volumes и, опять же, щёлкнуть правой кнопкой мышки на появившийся раздел. В меню нужно выбрать пункт «Attach Volume», после чего в появившемся модальном окне выбрать инстанс EC2 и нажать «Yes, Attach».

Всё — на сервере должно появиться новое блочное устройство. Теперь можно запустить dmesg | tail и посмотреть, какой идентификатор был присвоен для подключённого блочного устройства. Допустим, это xvdg. Тогда ФС может располагаться, например, на /dev/xvdg1 (зависит от предпочтений того, кто создавал таблицу разделов).

Создаём новый каталог, и монтируем раздел в этот каталог:

mkdir /mnt/backup mount /dev/xvdg1 /mnt/backup 

Для того, чтобы получить необходимые данные из бэкапа, включим дополнительный экземпляр MySQL, работающий с отдельной директорией данных:

sudo -u mysql /usr/libexec/mysqld --basedir=/usr --datadir=/mnt/backup/mysql --plugin-dir=/usr/lib64/mysql/plugin --log-error=/var/log/mysqld_backup.log --pid-file=/var/run/mysqld/mysqld_backup.pid --socket=/var/lib/mysql/mysql_backup.sock --port=5523 

Теперь попробуем подключиться к запущенному экземпляру MySQL:

mysql -h 127.0.0.1 -P 5523 

Если подключиться удалось, можно начинать процесс восстановления данных.

Для примера рассмотрим довольно простой сценарий: администратор-стажёр менял в продакшене значение для конкретного поля конкретного объекта, но отвлёкся на размышления о вечном, и случайно забыл написать в SQL‑запросе WHERE. Ну, ничего страшного — с кем не бывает.

Таким образом, теперь мы хотим восстановить значения поля sex в website.profile. Причём даже не для всех записей, а где-то для трети (потому что администратор был, конечно, задумчивый, но не настолько, чтобы не нажать Ctrl + C, поняв, что запрос явно выполняется подозрительно долго). Для этого в шелле основной базы данных создадим файл, содержащий нужные идентификаторы:

select id from profile where sex="test" into outfile '/tmp/profile_id_list'; 

Соответственно, будет создан файл /tmp/profile_id_list, где будут идентификаторы тех записей, поле sex которых нужно восстановить из бэкапа.

Далее пишем restore.py:

import MySQLdb  db = MySQLdb.connect(host="127.0.0.1",                      port=5523,                      user="user",                      passwd="password",                      db="website")  c = db.cursor()  f = open("/tmp/profile_id_list")  for profile_id in f.readlines():     c.execute(         "select sex from profile where id=%s",         (profile_id,)     )     print "update profile set sex=\"%s\" where id=%s;" % (         c.fetchone()[0],         profile_id[:-1]     ) 

И записываем SQL‑файл для восстановления sex:

python restore.py > restore.sql 

Проверяем, что файл в порядке (например, количество строк можно посмотреть с помощью wc -l restore.sql), и, затем, выполняем SQL‑запросы из файла:

mysql website < restore.sql 

Проверяем, что всё успешно восстановилось.

Теперь можно удалить /tmp/profile_id_list и прочие файлы, и, соответственно, выключить MySQL‑сервер:

mysqladmin -u root -p -h 127.0.0.1 -P 5523 shutdown 

Далее просто отмонтируем раздел и удалим каталог, в который он монтировался:

umount /mnt/backup rm -r /mnt/backup 

А в AWS Management Console, соотвественно, заходим в раздел ELASTIC BLOCK STORE → Volumes и отключаем виртуальное блочное устройство (Detach Volume). После этого его можно удалить (Delete Volume).

Ещё можно снова зайти в раздел со снимками (ELASTIC BLOCK STORE → Snapshots) и как-нибудь отметить те снимки, где (судя по времени создания снимка) есть неправильные данные (например, отразить это в имени снимка). Альтернатива — вообще удалить снимок. Но это решение хуже с той точки зрения, что именно этот снимок может понадобиться кому-то ещё (для восстановления совершенно других данных, которые именно в этом снимке могут быть как раз в полном порядке). Поэтому лучше по умолчанию предполагать, что любой современный (а тем более самый последний) снимок может содержать ценные данные, и на всякий случай не удалять их какое-то время (например, неделю).

И напоследок совет. У MySQL есть режим, в котором нельзя выполнить запрос DELETE или UPDATE, если в нём не указано условие WHERE, в котором однозначно задаётся конкретный объект. Поэтому, если вы случайно забыли добавить WHERE, то вы просто получите ошибку:

ERROR 1175 (HY000): You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column

Для включения такого режима достаточно добавить к опциям команды mysql, по вкусу: ‑‑i‑am‑a‑dummy или ‑‑safe‑updates.

Аналогичного эффекта можно добиться, добавив в файл ~/.my.cnf строку safe‑updates (что удобно, например, если вы запускаете команду mysql вообще без всяких опций, и всё автоматически берётся из ~/.my.cnf).

Кстати, по умолчанию этот режим добавляет ещё пару ограничений (которые, впрочем, можно отключить, но на практике это требуется редко): для select_limit устанавливается значение 1000, а для max_join_size — 1000000.

ссылка на оригинал статьи http://habrahabr.ru/post/218821/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *