Как настроить резервное копирование ClickHouse: руководство к действию
Сегодня я расскажу о своем опыте настройки резервного копирования по расписанию для on-premise кластера баз данных ClickHouse. Метод, который я опишу здесь, предполагает дополнительную загрузку данных на FTP-сервер, что, по моему мнению, достаточно эффективно для баз данных размером до 3-5 ТБ в сжатом виде.
Прежде чем мы приступим к работе, Сделайте все необходимое, чтобы избежать следующего:
- Отказ оборудования.
- Эксплуатационные ошибки, например, неправильно выполненный запрос.
- Нарушения безопасности или взломы.
Несмотря на то, что ClickHouse прекрасно справляется с задачей смягчения последствий аппаратных сбоев благодаря функции репликации, защита от двух последних виновников лежит на нас.
Для резервного копирования очень часто используют облачные хранилища, такие как S3, но я выбираю FTP-сервера. Почему? Потому, что случае взлома сервера ClickHouse наши резервные файлы будут защищены от хакеров.
Стратегия резервного копирования
Локальное резервное копирование: Мы создаем полные резервные копии на каждой реплике ежедневно. на удивление, они занимают мало места (благодаря методу резервного копирования, о котором мы расскажем позже) и обеспечивают более быстрое восстановление по сравнению с загрузкой данных из удаленного хранилища.
Удаленное резервное копирование: Для удаленного хранилища нам не нужно создавать резервные копии реплик каждого шарда. Если данные на одном из шардов будут повреждены, мы сможем восстановить все его реплики с помощью одной единственной резервной копии. Как это сделать? Проводить полное резервное копирование в непиковые периоды, а затем регулярно выполнять инкрементное резервное копирование. Наша система предусматривает еженедельное полное резервное копирование, дополняемое ежедневными инкрементами. Для наглядности: передача нашей еженедельной резервной копии размером 300x3 ГБ на FTP-сервер занимает около 2 часов.
Утилита резервного копирования
В функционале ClickHouse есть собственная опция резервного копирования, но тут важно учесть пару важных моменты:
- она дублирует данные, в результате чего резервные копии занимают больше места в локальном хранилище на каждом из узлов ClickHouse.
- единственная возможная интеграция с удаленным хранилищем на данный момент – это S3.
Итак, гвоздь нашей программы - утилита clickhouse-backup .
- использует способность ClickHouse создавать копии данных с помощью жестких ссылок, обеспечивая локальное резервное копирование со значительной экономией места.
- более универсальна благодаря поддержке удаленных хранилищ: azblob, S3, gcs, cos, ftp(s), sftp, а также собственных решений.
- open-source инструмент.
Установка утилиты резервного копирования
Итак, давайте установим утилиту clickhouse-backups:
#!/bin/bash OS=linux ARCH=amd64 CLICKHOUSE_BACKUP_VERSION=2.4.1 CLICKHOUSE_BACKUP_ARCHIVE=clickhouse-backup-$OS-$ARCH.tar.gz CLICKHOUSE_BACKUP_CONFIG_FILE=/etc/clickhouse-backup/config.yml CLICKHOUSE_BACKUP_RUN_SCRIPT_FILE=/etc/default/clickhouse-backup-run.sh sudo apt-get update wget https://github.com/Altinity/clickhouse-backup/releases/download/v$CLICKHOUSE_BACKUP_VERSION/$CLICKHOUSE_BACKUP_ARCHIVE tar -zxvf $CLICKHOUSE_BACKUP_ARCHIVE rm $CLICKHOUSE_BACKUP_ARCHIVE mv build/$OS/$ARCH/clickhouse-backup /usr/bin/clickhouse-backup rm -r build
Теперь нам нужно настроить ее. Давайте создадим файл /etc/clickhouse-backup/config.yml:
general:
remote_storage: sftp
...
backups_to_keep_local: 7 # keep 7 last backups locally.
backups_to_keep_remote: 0 # sftp server is responsible for cleanup.
clickhouse:
username: username
password: password
host: host
port: 9000
disk_mapping: {}
skip_tables:
— system.*
— INFORMATION_SCHEMA.*
— information_schema.*
— _temporary_and_external_tables.*
...
sftp:
address: host
username: username
password: password
port: 22
key: “”
path: “clickhouse-backups/{shard}”
...
Следующим шагом будет подготовка Bash-скрипта, способного выполнять полное и инкрементальное резервное копирование, а также работать с локальными и удаленными пунктами назначения резервных копий на основе заданных аргументов. Давайте создадим и сохраним его здесь: /etc/default/clickhouse-backup-run.sh.
#!/bin/bash
# full/incremental backup parameter
if [[ $1 == "full" ]]; then
IS_FULL=true
elif [[ $1 == "incremental" ]]; then
IS_FULL=false
else
echo "full/incremental not specified"
exit 1;
fi
# local/remote backup parameter
if [[ $2 == "local" ]]; then
CREATE_COMMAND="create"
elif [[ $2 == "remote" ]]; then
CREATE_COMMAND="create_remote"
else
echo "local/remote not specified"
exit 1;
fi
DATETIME=$(date -u +%Y-%m-%dT%H-%M-%S)
BACKUP_NAME_FULL="auto_full_$DATETIME"
BACKUP_NAME_INCREMENTAL="auto_incremental_$DATETIME"
# monitoring API call, f.e. healthchecks.io
BACKUP_HEALTH_CHECK=$BACKUP_HEALTH_CHECK
if [[ $IS_FULL == true ]]; then
echo "Starting full ($CREATE_COMMAND) backup"
echo "Creating backup $BACKUP_NAME_FULL"
clickhouse-backup $CREATE_COMMAND $BACKUP_NAME_FULL
exit_code=$?
if [[ $exit_code != 0 ]]; then
echo "clickhouse-backup create $BACKUP_NAME_FULL FAILED and return $exit_code exit code"
exit $exit_code
else
curl -fsS -m 10 --retry 5 -o /dev/null $BACKUP_HEALTH_CHECK
fi
else
echo "Starting incremental ($CREATE_COMMAND) backup"
# for incremental backup, take previous backup name
# based on dates in auto generated backup names.
BACKUP_NAME_PREV="$(clickhouse-backup list remote | grep -E '^auto_' | tail -n 1 | cut -d " " -f 1)"
echo "Creating backup $BACKUP_NAME_INCREMENTAL as diff from $BACKUP_NAME_PREV"
clickhouse-backup $CREATE_COMMAND --diff-from-remote=$BACKUP_NAME_PREV $BACKUP_NAME_INCREMENTAL
exit_code=$?
if [[ $exit_code != 0 ]]; then
echo "clickhouse-backup create $BACKUP_NAME_FULL FAILED and return $exit_code exit code"
exit $exit_code
else
curl -fsS -m 10 --retry 5 -o /dev/null $BACKUP_HEALTH_CHECK
fi
fi
И, наконец, давайте составим расписание выполнения скрипта. Для каждой реплики должно быть добавлено задание cron, которое будет выполнять только локальное резервное копирование:
#!/bin/bash SCRIPT_FILE=/etc/default/clickhouse-backup-run.sh CRON_FILE=/etc/cron.d/clickhouse-backup cat <<EOF > $CRON_FILE 0 5 * * * root /bin/bash $SCRIPT_FILE full local EOF chmod 600 $CRON_FILE echo 'done'
Для одной реплики каждого шарда мы запланируем и локальное, и удаленное резервное копирование:
#!/bin/bash SCRIPT_FILE=/etc/default/clickhouse-backup-run.sh CRON_WEEKLY_FILE=/etc/cron.d/clickhouse-backup-weekly CRON_DAILY_FILE=/etc/cron.d/clickhouse-backup-daily cat <<EOF > $CRON_WEEKLY_FILE 0 5 * * 6 root /bin/bash $SCRIPT_FILE full remote EOF chmod 600 $CRON_WEEKLY_FILE cat <<EOF > $CRON_DAILY_FILE 0 5 * * 0-5 root /bin/bash $SCRIPT_FILE incremental remote EOF chmod 600 $CRON_DAILY_FILE echo 'done'
Все готово! Хотя не совсем…
Защита и очистка FTP-сервера
Мы успешно запланировали локальное резервное копирование и защитили его путем загрузки на FTP-сервер. Однако это вызывает опасения по поводу потенциальной уязвимости в случае взлома сервера ClickHouse. Хакер может воспользоваться этой брешью и получить доступ к учетным данным FTP-сервера, что потенциально позволит ему удалить наши резервные копии.
Что нужно сделать, чтобы такого не было:
- Для пользователя FTP настройте chroot-тюрьму;
- Запланируйте задание cron для перемещения резервных копий из каталога пользователя FTP. Последняя резервная копия должна постоянно храниться в каталоге, поскольку ее метаданные необходимы для инкрементных резервных копий:
#!/bin/bash
BACKUPS_DIR=/mount/ftp/clickhouse-backups
BACKUPS_HIDDEN_DIR=/mount/clickhouse-backups-hidden
if [ -d "$BACKUPS_DIR" ]; then
echo "$BACKUPS_DIR exists"
else
echo "$BACKUPS_DIR doesn't exist, exit..."
exit 1
fi
cd $BACKUPS_DIR
SHARDS="$(ls -d shard-*)"
for SHARD in $SHARDS
do
echo "Working on $SHARD directory..."
BACKUPS=($(ls $SHARD | grep -E '^auto_' | sort -t_ -k3))
BACKUPS_COUNT=${#BACKUPS[*]}
echo "Found $BACKUPS_COUNT backups"
unset 'BACKUPS[${#BACKUPS[@]}-1]'
if [[ $BACKUPS_COUNT -gt 1 ]]; then
echo "Moving backups"
for BACKUP in "${BACKUPS[@]}"
do
echo "Moving $BACKUP to "$BACKUPS_HIDDEN_DIR/$SHARD/$BACKUP""
mkdir -p "$BACKUPS_HIDDEN_DIR/$SHARD"
mv "$SHARD/$BACKUP/" "$BACKUPS_HIDDEN_DIR/$SHARD/$BACKUP"
done
else
echo "No backups to move"
fi
done
Очистка
Мы хотим хранить на FTP только последние N резервных копий, поэтому давайте запланируем очистку:
#!/bin/bash
BACKUPS_HIDDEN_DIR=/mount/clickhouse-backups-hidden
BACKUPS_TO_KEEP=15
if [ -d "$BACKUPS_HIDDEN_DIR" ]; then
echo "$BACKUPS_HIDDEN_DIR exists"
else
echo "$BACKUPS_HIDDEN_DIR doesn't exist, exit..."
exit 1
fi
cd $BACKUPS_HIDDEN_DIR
SHARDS="$(ls -d shard-*)"
for SHARD in $SHARDS
do
echo "Working on $SHARD directory..."
BACKUPS=($(ls $SHARD | grep -E '^auto_' | sort -t_ -k3))
BACKUPS_COUNT=${#BACKUPS[*]}
echo "Found $BACKUPS_COUNT backups"
if [[ $BACKUPS_COUNT -gt $BACKUPS_TO_KEEP ]]; then
echo "Cleaning up backups"
BACKUPS_TO_CLEANUP=$(($BACKUPS_COUNT - $BACKUPS_TO_KEEP))
for BACKUP in "${BACKUPS[@]:0:$BACKUPS_TO_CLEANUP}"
do
echo "Removing $BACKUP from "$BACKUPS_HIDDEN_DIR/$SHARD""
rm -r "$BACKUPS_HIDDEN_DIR/$SHARD/$BACKUP"
done
else
echo "No backups to cleanup"
fi
done
Заключение
Правильный мониторинг и тестирование резервных копий очень важны. Для того чтобы данные всегда можно было восстановить, создание резервных копий должно контролироваться на автоматической основе, а также вручную.
Узнать об успешном завершении/ ошибки резервного копирования можно с помощью инструмента мониторинга заданий cron, который отправляет в Slack соответствующие предупреждения. Кроме того, в Notion есть доска задач, которая автоматически создает задачу «Проверка резервного копирования» каждый месяц. Специалист регулярно проверяет, создаются ли резервные копии и можно ли из них восстановить сервер. Обязательно воспользуйтесь данным инструментом.




