Pull to refresh

Резервное копирование томов LVM2 с защитой от перегрузок IO с использованием сигналов SIGSTOP, SIGCONT

Reading time 4 min
Views 4.6K

Настройка резервного копирования уверенно занимает одно из важнейших мест в деятельности администратора. В зависимости от задач резервного копирования, типов приложений и вида данных резервное копирование может осуществляться с помощью различных инструментов, таких как 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.


Решение


Схематично решение выглядит следующим образом:


  1. Запрашиваем статистику в течение N секунд и получаем среднее значение %IOWait;
  2. Определяем действие:
    a. Если значение %IOWait < 30, то возобновляем процесс (SIGCONT);
    b. Если значение %IOWait > 30, останавливаем процесс (SIGSTOP), увеличиваем счетчик;
  3. Если процесс остановлен дольше чем 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: Скрипт приведен без редактуры в оригинальном виде.

Tags:
Hubs:
+9
Comments 23
Comments Comments 23

Articles