Redis backup. Настраиваем резервное копирование Redis

08/11/2016

Сервер баз данных Redis хранит все данные в оперативной памяти, что может привести к их потере, если сервер будет внезапно остановлен, или компьютер потеряет питание. Для разрешения этой пролемы Redis, как известно, можно настроить на периодическое копирование содержимого оперативной памяти на диск, чтобы при следующем старте просто загрузить указанный файл обратно в память и продолжить работу. Однако это не решает проблему disaster recovery - восстановления с нуля, возможно даже на другой машине. Для этого redis backup нужно хранить в месте, отличном о том, где на данный момент работает сервер. Вы скажите, что нужно просто скопировать последний созданный Redis слепок данных на другую машину или в облако, и backup готов. Однако, может так оказаться, что вы будете копировать файл, который обычно называется dump.rdb, именно в тот момент, когда Redis решит делать очередной flush (копирование данных из памяти на диск), что может привести к невозможности восстановления в случае краха сервера.

Хорошим, казалось бы, вариантом создания redis backup будет, используя программу redis-cli, получить список всех ключей сервера с помощью команды KEYS \*, сделать DUMP их значений, записать в файл, а потом попытаться восстановить их с помощью команды RESTORE. И это действительно работает, но вот восстановить такой файл не всегда представляется возможным, потому что он может содержать разного рода непечатаемые символы, которые если и не заставят ваш терминал зависнуть, то уж точно не позволят ему корректно обработать значение таких ключей. Скорее всего вы получите сообщение вида

(error) ERR DUMP payload version or checksum are wrong

К счастью, redis-cli позволяет подключиться в серверу под видом slave, запросить копию данных и сохранить их в файл, который уже можно безбоязненно сохранить в любое место на удаленной системе. В этом случае вы получаете абсолютно консистентный redis backup, не вмешиваясь в протоколы работы сервера, а используете штатный механизм master-slave. Сделать это можно следующим способом из коммандной строки:

redis-cli --rdb backup.rdb

Данная команда заставит redis-cli попытаться подключиться в серверу на этой же машине по адресу 127.0.0.1 к порту 6379, запросить копию данных и сохранить их в файл backup.rdb в текущем каталоге. Если вы хотите подключиться к серверу не локально, а по сети, то возможно следующие дополнительный ключи к redis-cli будут для вас полезны:

-h задает IP-адрес сервера
-p задает TCP-порт сервера, если он отличен от 6379
-a задает пароль, если сервер требует таковой

Конечно же мы не хотим всё время помнить о том, что нам нужно сделать redis backup, а хотим, чтобы он проходил автоматически. Для этого создадим простой bash-скрипт:

#!/bin/bash
 
REDIS_HOST=${REDIS_HOST:=localhost}
REDIS_PORT=${REDIS_PORT:=6379}
REDIS_PASSWORD=""
DATE=$(date +%Y%m%d)
BACKUP_PATH="/mnt/backup"
DAYS_TO_KEEP="7"
 
if [ ! -e ${BACKUP_PATH} ];
  then mkdir -p ${BACKUP_PATH}
fi
 
rm -f $(find ${BACKUP_PATH} -type f -mtime +${DAYS_TO_KEEP})
 
if [ -f ${BACKUP_PATH}/${DATE}_dump.rdb ];
  then echo "File already exists"
  exit 0
else
  CLI_OPTS="\
    -h ${REDIS_HOST} \
    -p ${REDIS_PORT} \
    --rdb ${BACKUP_PATH}/${DATE}_dump.rdb"
  if [ ! -z ${REDIS_PASSWORD} ]; then
    CLI_OPTS="${CLI_OPTS} -a ${REDIS_PASSWORD}"
  fi
 
  redis-cli $CLI_OPTS
 
  if [ $? -eq 0 ]
    then echo "Backup succsess"
    else echo "Backup error"
  fi
fi

Измените 7 переменных в начале скрипта на свое усмотрение. Если сервер требует пароль впишите его, если нет, то просто оставьте пустые кавычки (""), переменную DATE можно не трогать - она допишет в начало названия файла с бэкапом текущую дату.  Не забудьте дать ему права на исполнение:

chmod +x NAME_OF_SCRIPT

Испытайте его - вы должны получить redis backup файл с названием, состоящим из текущей даты плюс "_dump.rdb". Теперь попробуйте на тестовом инстансе Redis загрузить бэкап в качестве основной базы. Получилось? Отлично! Можно смело интегрировать наш скрипт с полюбившимся вам scheduler'ом, которыми являются, например, CRON или Systemd Timer. Если же нет, пишите в комментариях, мы рассмотрим ваш случай более детально.

Темы: