Про необхідність резервного копіювання говорити сенсу немає: якщо системний адміністратор не розуміє цього, то після першого ж збою або злому сервера або просто при випадковому видаленні цінної інформації задумається про нього. Хочу поділитися своїм, нехай і не багатим, досвідом в цій галузі.
Систем резервного копіювання придумано багато, але не всі однаково корисні в умовах утрудненого доступу до сервера: програма востановления повинна уміщатися на завантажувальному змінному носії і працювати з нього без установки в систему.
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 '
Потім відновив їх з дампа в поточну директорію.
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 можна задати у відповідному розділі форуму.