Настройка резервного копирования уверенно занимает одно из важнейших мест в деятельности администратора. В зависимости от задач резервного копирования, типов приложений и вида данных резервное копирование может осуществляться с помощью различных инструментов, таких как rsync, duplicity, rdiff-backup, bacula и других, коих существует огромное множество.
Помимо осуществления самого процесса резервного копирования, который бы отвечал потребностям организации, существует ряд проблем, которые неизбежно возникают при осуществлении резервного копирования, одна из которых — увеличение нагрузки на дисковую подсистему, что может приводить к деградации производительности приложений.
Решение данной задачи не является простым — часто администратор вынужден идти на компромиссы, которые ведут к тому, что продолжительность процедуры увеличивается или периодичность резервного копирования уменьшается с ежедневного до еженедельного. Данные компромиссы неизбежны и являются вынужденной реакцией на существующие технические ограничения.
И, тем не менее, основной вопрос остается открытым. Как же осуществлять резервное копирование таким образом, чтобы основные приложения получали приемлемое качество обслуживания? Операционные системы семейства UNIX предоставляют штатный механизм управления приоритетами ввода-вывода для приложений, который называется ionice, кроме того, конкретные реализации UNIX предоставляют свои механизмы, которые позволяют наложить дополнительные ограничения. К примеру, в случае GNU/Linux существует механизм cgroups, который позволяет ограничить полосу пропускания (для физически подключенных устройств) и установить относительный приоритет для группы процессов.
Тем не менее, в некоторых случаях таких решений недостаточно и необходимо ориентироваться на фактическое "самочувствие" системных процессов, которое отражают такие параметры системы как Load Average или %IOWait. В этом случае на помощь может прийти подход, который я успешно применяю уже достаточно продолжительное время при осуществлении резервного копирования данных с LVM2 с помощью dd.
Описание задачи
Имеется сервер GNU/Linux, на котором настроено хранилище, использующее LVM2 и для данного сервера каждую ночь осуществляется процедура резервного копирования тома, которая выполняется с помощью создания снимка раздела и запуска dd + gzip:
ionice -c3 dd if=/dev/vg/volume-snap bs=1M | gzip --fast | ncftpput ...
При осуществлении резервного копирования хочется выполнить его максимально быстро, но опытным путем замечено, что при повышение %IOWait до 30%, качество обслуживание дисковой системой приложений становится неприемлемым, поэтому необходимо держать его ниже данного уровня. Требуется реализовать ограничительный механизм, который бы обеспечивал обработку в предельно допустимых значениях %IOWait.
Поиск решения
Изначально для решения был применен подход с ionice -с3
, но он не давал стабильного результата. Механизмы, основанные на cpipe и cgroups (throttling) были отброшены как не дающие возможности копировать данные быстро, если %IOWait в норме. В итоге было выбрано решение, основанное на мониторинге %IOWait и приостановке/возобновлении процесса dd с помощью сигналов SIGSTOP, SIGCONT совместно с сервисом статистики sar.
Решение
Схематично решение выглядит следующим образом:
- Запрашиваем статистику в течение N секунд и получаем среднее значение %IOWait;
- Определяем действие:
a. Если значение %IOWait < 30, то возобновляем процесс (SIGCONT);
b. Если значение %IOWait > 30, останавливаем процесс (SIGSTOP), увеличиваем счетчик; - Если процесс остановлен дольше чем N x K, возобновляем процесс и останавливаем его снова через 2 секунды
Скорее всего п.3 вызывает вопросы. Зачем такое странное действие? Дело в том, что в рамках резервного копирования осуществляется передача данных по FTP на удаленный сервер и если процесс копирования остановлен достаточно продолжительное время, то мы можем потерять соединение по таймауту. Для того, чтобы этого не произошло, мы выполняем принудительное возобновление и остановку процесса копирования даже в том случае, если находимся в "красной" зоне.
Код решения приведен ниже.
#!/bin/bash
INTERVAL=10
CNTR=0
while :
do
CUR_LA=`LANG=C sar 1 $INTERVAL | grep Average | awk '{print $6}' | perl -pe 'if ($_ > 30) { print "HIGH "} else {print "LOW "}'`
echo $CUR_LA
MARKER=`echo $CUR_LA | awk '{print $1}'`
if [ "$MARKER" = "LOW" ]
then
CNTR=0
pkill dd -x --signal CONT
continue
else
let "CNTR=$CNTR+1"
pkill dd -x --signal STOP
fi
if [ "$CNTR" = "5" ]
then
echo "CNTR = $CNTR - CONT / 2 sec / STOP to avoid socket timeouts"
CNTR=0
pkill dd -x --signal CONT
sleep 2
pkill dd -x --signal STOP
fi
done
Данное решение успешно решило проблему с перегрузкой IO на сервере, при этом не ограничивает скорость жестко, и уже несколько месяцев служит верой и правдой, в то время, как решения, основанные на предназначенных для этого механизмах, не дали положительного результата. Стоит отметить, что значение параметра, получаемое sar может быть легко заменено на Load Average и иные параметры, которые коррелируют с деградацией сервиса. Данный скрипт вполне подходит и для задач, в которых применяется не LVM2 + dd, а, к примеру, Rsync или другие инструменты резервного копирования.
C помощью cgroups возможно таким же образом реализовать не остановку, а ограничение полосы, если речь идет о копировании данных с физического блочного устройства.
PS: Скрипт приведен без редактуры в оригинальном виде.
Комментарии (21)
librarian
07.07.2017 17:35Не совсем понимаю почему нужно посылать сигналы приложению, если всё таки можно по тем же самым метрикам изменять лимиты в cgroups.
ivankudryavtsev
07.07.2017 17:44Вы правы, можно и через cgroups, но вот у меня такой скрипт. Историческая данность, так сказать)
mrobespierre
08.07.2017 03:27а вы точно пробовали? в cgroups-v1 ограничение по диску, емнип, было, но не работало, а cgroups-v2 есть только в новеньких ядрах (4.4+ кажется)
orlando33
07.07.2017 17:41+3Почти тоже самое можно сделать одной строкой cpuwatch 10 ionice -c2 -n7 dd if=…
При большой нагрузке на IO, автоматически будет расти avg, что в свою очередь будет останавливать dd.ivankudryavtsev
07.07.2017 17:53+1А нет, видимо, не буду, нету cpuwatch в Debian, похоже, исключительно утилита из CPanel.
Sirikid
08.07.2017 01:31+2Легким движением руки
grep Average | awk '{print $6}' | perl -pe 'if ($_ > 30) { print "HIGH "} else {print "LOW "}'
превращается в
awk '/Average/ { if ($6 > 30) print "HIGH "; else print "LOW " }'
Sleuthhound
08.07.2017 15:03>>резервного копирования тома, которая выполняется с помощью создания снимка раздела и запуска dd + gzip
Откройте для себя ZFS и не мучайтесь этой ерундой.ivankudryavtsev
08.07.2017 15:21А каким образом ZFS поможет в решении проблемы резервного копирования и роста IO?
Sleuthhound
08.07.2017 19:15?
Таким, что на zfs чертовски удобно делать снапшоты, чертовски удобно работать с томами (добавить-удалить диск в пул и прочее) и все резервное копирование заключается в грамотном управлении политикой создания и удаления снапшотов. Не нужно писать какие-то адские скрипты создания архивов, и прочее, вы просто копируете данные с разных серверов или раб. ПК (например я копирую с помощью rsync данные с файлового сервера win2012 И с кучи linux серверов) на сервер с zfs, ночью создаю новые снапшоты с определенным сроком хранения, удаляю старые (5 строчек в cron) и все. При любой аварии я моментально могу достать данные (хоть 1 файл) без распаковки архивов, без ожидания.ivankudryavtsev
08.07.2017 19:28Мне кажется, что я, все же, про другое пишу. Если Вы захотите решить проблему именно резервного копирования, что никак со снэпшотами не связано, то проблема так или иначе себя проявит и zfs тут не при чем.
Sleuthhound
08.07.2017 20:54Проблема сохранения отзывчивости приложений при больших дисковых операциях решается путем выделения под backup отдельного сервера, который ничем кроме хранения бэкапа не занимается.
У меня в компании так и сделано, стоит старенький HP Proliant ML150 с 6 SATA дисками по 3 Tb c ZFS.
И никаких проблем нет. Цена б/у сервера — 7-10 т.р., диски берутся тоже самые обычные (WD Red), просто делается RAIDZ со spare диском. Итого за 55 т.р. имеем нормальный сервер для хранения бэкапов для небольшой компании и никакого гемороя с перегрузками IO.ivankudryavtsev
08.07.2017 21:35Честно говоря, я не очень понимаю при чем здесь ZFS, но пытаюсь понять.
1. Я понимаю что ZFS превосходит LVM2 в аспектах сжатия данных, в производительности снэпшотов, в дедупликации данных (по крайней мере на Solaris, возможно, FreeBSD).
2. Неважно что у меня на том сервере откуда я копирую данных — LVM2 и ZFS, операция копирования генерирует дополнительные IO, кроме того, в зависимости от условий она еще может «вымывать» буферный кэш, что ведет к еще большему росту IO, в результате чего приложения могут столкнуться с ситуацией, что им IO не хватает.
3. Статья о том, как приостановить бэкап, если наблюдается ситуация, что приложения начали голодать по IO.
4. Статья не о том, как эффективно организовать сервер хранения бэкапов.
Теперь вопрос: в чем именно Ваша точка зрения в контексте метода [остановки приложения резервного копирования], который я предлагаю, и как ZFS (в контексте статьи речь видимо идет о zfsonlinux) помогает в осуществлении резервного копирования (принципиально), а не в контексте лучше/хуже, что позволяет приложениям не голодать по IO?
ps: я копирую 11 ТБ томов виртуальных машинSleuthhound
10.07.2017 12:36Теперь вопрос: в чем именно Ваша точка зрения
А Вы прочитайте мой коммент внимательней, там вполне все понятно.
Вы написали:
резервного копирования тома, которая выполняется с помощью создания снимка раздела и запуска dd + gzip
Я написал:
Откройте для себя ZFS и не мучайтесь этой ерундой.
Все. Мой комментарий касался только 1 вашей фразы про то, что Вы делаете рез.копирование через запуска dd + gzip
Как вы притормаживаете ресурсоемкую дисковую операцию при росте IO я вообще не оспариваю.ivankudryavtsev
10.07.2017 14:48А чем плох dd и gzip? Как это связано с zfs?
Sleuthhound
10.07.2017 14:56А чем плох dd и gzip?
Вы еще спросите чем плох пароль 123456 и как это связано с безопасностью.
А тем и плох dd и gzip, что насилуя ими диск, Вы поднимаете IO до небес, а потом жалуетесь, что плохая отзывчивость web-приложений.ivankudryavtsev
10.07.2017 15:02Давайте смотреть на вещи трезво, it depends. По нескольким причинам.
1. Gzip не насилует диск;
2. Gzip имеет на dd успокаивающее действие, поскольку замедляет dd;
3. dd осуществляет последовательное чтение, нам помогает readahead, при использовании direct мы не вымываем буферный кэш;
4. В зависимости от заполненности FS и от объема изменений, dd может быть лучше и хуже чем другой метод. Скопировать FS с миллионами мелких картинок, к примеру, будет быстрее с помощью dd чем rsync;
5. Статья не про dd, а про способ остановки;
6. Я не до конца понимаю при чем здесь ZFS и зачем вы начали про нее разговор?
kolu4iy
08.07.2017 15:18+1Я открыл для себя другое правило: в продакшн — ничего модного. У моей компании нет на это денег.
Когда мода заглохнет и %продукт% станет мейнстримом и будет включен в основных дистрибутивах по умолчанию — пора.
mrobespierre
тоже так делал, а потом побенчил и пришел к bs=64K и lzop — размер чуть больше, но по CPU и времени сильно «дешевле»