Стаття резервне копіювання утилітою dump

Про необхідність резервного копіювання говорити сенсу немає: якщо системний адміністратор не розуміє цього, то після першого ж збою або злому сервера або просто при випадковому видаленні цінної інформації задумається про нього. Хочу поділитися своїм, нехай і не багатим, досвідом в цій галузі.

Систем резервного копіювання придумано багато, але не всі однаково корисні в умовах утрудненого доступу до сервера: програма востановления повинна уміщатися на завантажувальному змінному носії і працювати з нього без установки в систему.

dump - традиційна утиліта резервного копіювання для unix-подібних операційних систем. Вона може працювати з десятьма рівнями інкрементальних дампов, записувати їх на стріммерние стрічки, на будь-які блокові пристрої і просто в файли на іншому розділі. Відновлювати можна як розділ цілком, так і окремі файли і директорії.

Працює утиліта безпосередньо з блоковим пристроєм, що містить файлову систему, і оперує деревом вузлів (inode). Вона може копіювати дані як з демонтованого утройства, так і з використовуваного - змонтованого. Для інкрементального бекапу використовується час модифікації inode.

У файлі / etc / dumpdates зберігається інформація про час проведення кожного рівня інкрементального копіювання для кожного розділу. Для конкретного пристрою інформація там з'являється тільки після створення дампа нульового рівня і оновлюється при кожному наступному скиданні дампа будь-якого рівня.

Dump може архівувати дані на льоту, використовуючи різні алгоритми стиснення. Які саме - краще впоратися в мануалі (man dump) на свою ОС. Для Linux це: zlib, bzlib і lzo. Zlib і bzlib підтримують 9 рівнів стиснення і, відповідно, різну швидкість скидання дампа. Lzo працює швидше. Одночасне використання компресії і Стриммер можливо, якщо стриммер підтримує блоки змінної довжини.

Скидається дамп може бути розділений на томи - автоматично, щодо заповнення пристрою одержувача, або на шматки зазначеної довжини.

Приклад створення дампа: скидається дамп нульового рівня, стискається бібліотекою bzlib на шостому рівні компресії, нарізається на томи по 700000 блоків по 1кб (кожен файл поміщається на одному CD або по 6 файлів на DVD), тому автоматично іменуються з префіксом root- і складаються в директорію / mnt / backup / 0 (в точці / mnt / backup подмонтіровать окремий розділ). Після закінчення оновлюється запис у файлі / etc / dumpdates.

dump -0 -f / mnt / backup / 0 / root- -uMB 700000 -j6 /

Робота з restore.

Відновлення з дампа виконує команда restore. Досконально розібратися з її параметрами я ще не встиг. Рекомендую почати вивчення мануала (man restore) раніше, ніж буде потрібно відновлювати дані! Розповім, як відновлював директорію з дампа.

Експортував список файлів, виділив потрібні і помістив повні шляхи до них в файл в поточній директорії.

restore -t -M -f / mnt / backup / 0 / var- | \
grep '^ / var / www / virtuals / mysite / www / data' | \
awk ''> List

Потім відновив їх з дампа в поточну директорію.

restore -x -M -f / mnt / backup / 0 / var- -X list

Стратегія резервного копіювання.

Я вибрав для сервера таку стратегію:
  • Раз на квартал або раз на рік (за смаком і потреби) скидається дамп нульового рівня. Він найбільший і містить всю інформацію з розділу. Тому, щоб не мучитися з багатогігабайтними дампами, варто робити його не часто.
  • Кілька частіше (раз на місяць) скидається дамп першого рівня. Причому, щоб він не збігся за часом з нульовим дампом, зробимо його 15-го числа. Він буде містити всі накопичуються зміни і з часом буде зростати до чергового нульового дампа. Це теж масивний дамп (залежить від швидкості зміни даних на диску).
  • Раз в тиждень скидається дамп другого рівня. Він збирає в один дамп зміни за тиждень, накопичені більш високими рівнями дампов. Його потрібно регулярно копіювати в віддалене сховище.
  • На інші дні тижня - Інкрементальний - більш високі рівні: 3, 4, 5, 6, 7 і 8. Вони невеликі і кожен містить зміни тільки за один день. Копіювати їх чи ні - питання збереження даних. Краще буде копіювати - інакше сенсу в цих дампи буде мало.
  • Для оперативного скидання вручну залишимо 9-й рівень. Це може стати в нагоді при "несподіваних" помилки адміністратора, коли треба буде відновити старі версії конфігов або випадково видалені файли, і потрібно щоб вони були не з нічного бекапу, а як можна свіже.

Скидання дампов краще проводити вночі, в той час, коли сервер не навантажений і не зайнятий іншими запланованими завданнями. Оптимально підходить період з 3-х до 5-ї ранку. Можна вибрати будь-який інший момент, визначивши на практиці період найменшого навантаження.

Автоматизація та оптимізація dump.

Для запланованого запуску я використовував cron (навряд чи в Unix варто вибирати інший планувальник). Завдання повинні запускатися від імені root-а. Тому вони можуть бути занесені: або root-ом утилітою crontab. або записані в файлі / etc / crontab.

Приклад - фрагмент / etc / crontab:

05 5 * * 6 root dump -8 -f / mnt / backup / 0 / root- -uMB 700000 -j6 /
05 5 * * 5 root dump -7 -f / mnt / backup / 0 / root- -uMB 700000 -j6 /
05 5 * * 4 root dump -6 -f / mnt / backup / 0 / root- -uMB 700000 -j6 /
05 5 * * 3 root dump -5 -f / mnt / backup / 0 / root- -uMB 700000 -j6 /
05 5 * * 2 root dump -4 -f / mnt / backup / 0 / root- -uMB 700000 -j6 /
05 5 * * 1 root dump -3 -f / mnt / backup / 0 / root- -uMB 700000 -j6 /
05 5 * * 7 root dump -2 -f / mnt / backup / 0 / root- -uMB 700000 -j6 /
05 4 15 * * root dump -1 -f / mnt / backup / 0 / root- -uMB 700000 -j6 /
35 3 1 1,4,7,10 * root dump -0 -f / mnt / backup / 0 / root- -uMB 700000 -j6 /

І так треба повторити для кожного копируемого розділу. Це незручно, громіздко і є ймовірність, що процеси копіювання накладуться один на одного за часом і тим самим тільки сповільняться. Пора щось написати для зручності і автоматизації.

# Перевірити, що параметер - число від 0 до 9. Можна і погуманее метод взяти.
if # 91; _ $ 1. = _0 # 93; # 91; _ $ 1. = _1 # 93; # 91; _ $ 1. = _2 # 93; \
# 91; _ $ 1. = _3 # 93; # 91; _ $ 1. = _4 # 93; # 91; _ $ 1. = _5 # 93; \
# 91; _ $ 1. = _6 # 93; # 91; _ $ 1. = _7 # 93; # 91; _ $ 1. = _8 # 93; \
# 91; _ $ 1. = _9 # 93; ;
then
echo "System backup: invalid argument!"
echo "Usage: dump.sh "
exit 1;
fi

echo "Start system backup. Level $ DL."

# Старі дампи, з поточного рівня і вище, можна видалити, щоб не займали місце.
for N in `seq $ 9`
do
rm -f / mnt / backup / $ / *
done

# Виконуємо скидання для кожного розділу.
dump -f / mnt / backup / $ / root- - $ uMB 700000 -j6 /
dump -f / mnt / backup / $ / home- - $ uMB 700000 -j6 / home
dump -f / mnt / backup / $ / var- - $ uMB 700000 -j2 / var

echo "System backup complete."
exit 0

Тоді запуск бекапу проводиться так:

/ Root / bin / dump.sh 0

Так як dump працює з inode, а не іменами файлів, то для виключення потрібно передати команді список inode, які не потрібно поміщати в дамп. Робиться це ключами -e або -E. Перший ключ задає список inode прямо в командному рядку, а другий ключ задає ім'я текстового файлу, що містить список inode (по одному на рядок). Якщо inode належить директорії, то в дамп не потрапить сама директорія і все вище розміщені файли і директорії.

Номер inode для файлу або директорії можна отримати за допомогою команди stat:

stat -c% i / etc / dumpdates

Таким способом можна зробити список inode і додати їх в рядок з dump. але якось не зручно і не гнучко це. Наприклад, краще буде, якщо в нульовий дамп увійдуть всі файли і директорії, а в більш високі прописати виключення. Треба тільки автоматизувати процес.

В кінцевому підсумку у мене вийшла така програма на Perl. У ній ще не вистачає можливості роботи з шаблонами в іменах файлів (wildcards).

use strict;
use Config. INI. Reader;

my $ CONFIG = '/etc/dumper.conf';

# За умовчанням нехай буде 9-й рівень.
my $ level = 9;
# Дефолтні параметри.
my% config = # 40;
'Dump-dir' => '/ mnt / back / backups / system'.
# 41; ;
my # 40; $ Fd. $ ini # 41; ;

# Наш єдиний параметер - повинен бути цифрою.
if # 40; $ ARGV # 91; 0 # 93; =

# Розбираємо список файлів, розділених двокрапкою, і створюємо для них список inode.
sub get_inode_list # 40; $)
# 123;
my # 40; $ File. @list # 41; ;

for $ file # 40; split ':'. $ _ # 91; 0 # 93; # 41;
# 123;
next unless # 40; - e $ file # 41; ;
push @list. # 40; stat # 40; $ file # 41; # 41; # 91; 1 # 93; ;
# 125;

return @list;
# 125;

# Щоб не писати свій парсер конфіга, я вибрав формат ini і встановив відповідний модуль.
$ Ini = Config. INI. Reader -> read_file # 40; $ CONFIG # 41; ;

# У розділі "*" вказані загальні параметри.
if # 40 ;. exists $ ini -> # 123; '*' # 125; # 41;
# 123;
print STDERR "*** Config error! \ n";
exit 1;
# 125;

# Заміщає дефолтні параметри значеннями з конфіга.
% Config = # 40; % Config. % # 123; $ Ini -> # 123; '*' # 125; # 125; # 41; ;

if # 40 ;. exists $ config # 123; 'Jobs' # 125; # 41;
# 123;
print STDERR "*** Job's list not found! \ n";
exit 1;
# 125;

print "*** Requested dump level is '$ level'. \ n";
print "*** Delete old backups:". join # 40; ','. # 40; $ Level. 9 # 41; # 41 ;. ". \ N";

for my $ n # 40; $ Level. 9 # 41;
# 123;
my @files = glob # 40; join # 40; '/'. $ config # 123; 'Dump-dir' # 125 ;. $ N. '*' # 41; # 41; ;
next unless # 40; @files # 41; ;
my @cmd = # 40; 'Rm'. '-f'. @files # 41; ;
print join # 40; ''. @cmd # 41 ;. "\ N";
system @cmd;
# 125;

print "*** System backup begun. \ n";

# У пункті "jobs" перераховані імена "завдань".
# На кожну задачу в конфіги треба створити однойменний блок з параметрами.
L_jobs. for my $ job # 40; split ''. $ config # 123; 'Jobs' # 125; # 41;
# 123;
unless # 40; exists $ ini -> # 123; $ job # 125; exists $ ini -> # 123; $ job # 125; # 123; 'Fs' # 125; exists $ ini -> # 123; $ job # 125; # 123; 'Dump' # 125; # 41;
# 123;
print STDERR "*** Job '$ job': not properly configured! \ n";
next L_jobs;
# 125;

unless # 40; - e $ ini -> # 123; $ job # 125; # 123; 'Fs' # 125; # 41;
# 123;
print STDERR "*** Job '$ job': wrong fs assign! \ n";
next L_jobs;
# 125;

my @args = # 40; "- $". '-f'. join # 40; '/'. $ config # 123; 'Dump-dir' # 125 ;. $ Level. $ Ini -> # 123; $ job # 125; # 123; 'Dump' # 125; # 41; # 41; ;

if # 40; exists $ ini -> # 123; $ job # 125; # 123; 'Params' # 125; # 41;
# 123;
push @args. split ''. $ Ini -> # 123; $ job # 125; # 123; 'Params' # 125; ;
# 125;

# Параметр виду "exc #" - на кожен рівень дампа. Містить список винятків з бекапу.
if # 40; exists $ ini -> # 123; $ job # 125; # 123; "Exc $ level" # 125; # 41;
# 123;
my @inodes = get_inode_list # 40; $ Ini -> # 123; $ job # 125; # 123; "Exc $ level" # 125; # 41; ;

if # 40; @inodes! = 0 # 41;
# 123;
push @args. '-e'. join # 40; ','. @inodes # 41; ;
# 125;
# 125;

my @cmd = # 40; 'Dump'. @args. $ Ini -> # 123; $ job # 125; # 123; 'Fs' # 125; # 41; ;
print join # 40; ''. @cmd # 41 ;. "\ N";
system @cmd;
# 125;

print "*** System backup complete. \ n";
exit 0;

Встановлюється він легко:

  • Розпакувати і зайти в отриману директорію
  • ./Makefile.PL
  • make install

# 91; * # 93;
dump-dir = / mnt / backup
jobs = root home var

# 91; home # 93;
fs = / home
dump = home-
params = -uMB 700000 -j6


# 91; root # 93;
fs = /
dump = root-
params = -uMB 700000 -j6

exc0 =
exc1 = / tmp
exc2 = / tmp
exc3 = / tmp: / root / tmp; Експерименти root-а в бекап поміщати не треба
exc4 = / tmp: / root / tmp
exc5 = / tmp: / root / tmp
exc6 = / tmp: / root / tmp
exc7 = / tmp: / root / tmp
exc8 = / tmp: / root / tmp
exc9 = / tmp: / root / tmp

# 91; var # 93;
fs = / var
dump = var-
params = -uMB 700000 -j2

exc0 =
exc1 = / var / spool / postfix; пошту бекап не потрібно
exc2 = / var / spool / postfix: / var / lib / mysql: / var / named / chroot / var / named / data; бази та інші динамічні дані
exc3 = / var / spool / postfix: / var / lib / mysql: / var / named / chroot / var / named / data: / var / log: / var / www / virtuals / logs; всілякі логи теж
exc4 = / var / spool / postfix: / var / lib / mysql: / var / named / chroot / var / named / data: / var / log: / var / www / virtuals / logs
exc5 = / var / spool / postfix: / var / lib / mysql: / var / named / chroot / var / named / data: / var / log: / var / www / virtuals / logs
exc6 = / var / spool / postfix: / var / lib / mysql: / var / named / chroot / var / named / data: / var / log: / var / www / virtuals / logs
exc7 = / var / spool / postfix: / var / lib / mysql: / var / named / chroot / var / named / data: / var / log: / var / www / virtuals / logs
exc8 = / var / spool / postfix: / var / lib / mysql: / var / named / chroot / var / named / data: / var / log: / var / www / virtuals / logs
exc9 = / var / spool / postfix: / var / lib / mysql: / var / named / chroot / var / named / data: / var / log: / var / www / virtuals / logs

Запускається dumper так:

/ Root / bin / dumper.pl 0

Питання з програмування на Perl можна задати у відповідному розділі форуму.

Схожі статті