UMGUM.COM (лучше) 

Bacula + Clickhouse backup ( Резервное копирование БД "(Yandex) Clickhouse" посредством "Bacula". )

28 апреля 2021

OS: "Linux Debian 8/9/10", "Linux Ubuntu 18/20 LTS".
Application: "Bacula 5.2/7.4/9.0", "clickhouse-client".

Задача: наладить выгрузку резервной копии "баз данных" колоночной (column-oriented) СУБД "(Yandex) Clickhouse" посредством "Bacula".

Резервное копирование содержимого "баз данных" прямым копированием из файлов как правило невозможно и требуется предварительная выгрузка консистентного "дампа" в заранее известную директорию. Сделаем это, воспользовавшись встроенной возможностью "Bacula" исполнения произвольных скриптов на стороне клиента до и после процедуры непосредственного резервного копирования.

Для резервного копирования БД "Clickhouse" большого объёма, от сотен гигабайт до петабайт, лучше воспользоваться специализированными инструментами "clickhouse-copier" или "clickhouse-backup". В случае скромных размеров до сотни гигабайт вполне достаточно выгрузки конфигурации и данных в текстовых форматах SQL и TSV.


Предварительная настройка СУБД.

Подготавливать к выгрузке SQL-дампа сервер СУБД не требуется. Нужен только доступ от имени обладающего достаточными привилегиями пользователя.

СУБД "Clickouse" активно развивается, и в репозиториях несущих операционных систем наверняка будет сильно устаревшая, относительно резервируемого сервера, версия клиента. Лучше подключить репозиторий разработчиков СУБД и загрузить свежее программное обеспечение оттуда:

# apt-get install -y apt-transport-https ca-certificates dirmngr
# apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv E0C56BD4
# echo -e "# Official APT-repository (Yandex) Clickhouse\ndeb [arch=amd64] https://repo.clickhouse.tech/deb/stable/ main/" >> /etc/apt/sources.list.d/clickhouse.list
# apt-get update && apt-get install -y clickhouse-client pigz

Предварительная настройка клиента "Clickhouse".

Для упрощения дальнейших процедур опишем параметры подключения к целевой СУБД в конфигурационном файле:

# vi /root/.clickhouse-client.xml

<config>
  <user>default</user>
  <password></password>
  <host>127.0.0.1</host>
  <port>9000</port>
  <secure>False</secure>
</config>

Защитим файл, содержащий секретные сведения, от доступа посторонних:

# chmod go-rwx /root/.clickhouse-client.xml

Проверим, возможно ли подключение к СУБД с использованием нашего файла конфигурации:

# clickhouse-client -q "SELECT 1"

Скрипт резервного копирования БД "Clickhouse".

Немного странно, но официальный арсенал инструментов "Clickhouse" не позволяет выгружать одной командой содержимое сразу всей БД - это можно делать только применительно к каждой таблице по отдельности. Для реализации недостающего функционала мною был написан простой bash-скрипт, запрашивающий список БД, запрашивающий список таблиц этих БД, и выгружающий отдельно структуру таблиц, а также данные как таковые в виде текстовых файлов:

# vi /usr/local/bin/clickhouse-backup-tsv.sh && chmod +x /usr/local/bin/clickhouse-backup-tsv.sh

#!/bin/bash
# Author: Narozhniy Andrey, 2021, NSU
# Usage: /usr/local/bin/clickhouse-backup-tsv.sh /output/backup/dir

# Checking existence configuration with connection parameters
[ ! -f "/root/.clickhouse-client.xml" ] && { echo "Configuration file missing. Backup aborted."; exit 1; }
CONFIG="--config-file /root/.clickhouse-client.xml"

# Defining a directory for uploading backups
OUTDIR=${1:-'./'}
mkdir -p "${OUTDIR}"
[ ! -z "$(ls -A ${OUTDIR})" ] && { echo "Output directory not empty. Backup aborted."; exit 1; }

# Query and iterating over databases
while read -r DB ; do

  # Skipping system database
  [ "${DB}" == "system" ] && { echo "Skip \"system\" database."; continue; }

  # Preparing directories for data
  mkdir -p "${OUTDIR}/${DB}"

  # Query and iterating over tables from database
  while read -r TABLE ; do

    # Skipping table views
    [[ "${TABLE}" == ".inner."* ]] && { echo "Skip materialized view \"${TABLE}\" (${DB})."; continue; }
    echo "Export table \"${TABLE}\" from database \"${DB}\"..."

    # Querying the table structure as SQL
    clickhouse-client ${CONFIG} -q "SHOW CREATE TABLE ${DB}.${TABLE}" > "${OUTDIR}/${DB}/${TABLE}_schema.sql"

    # Dump table data as TSV (tab separated values)
    clickhouse-client ${CONFIG} -q "SELECT * FROM ${DB}.${TABLE} FORMAT TabSeparated" | pigz > "${OUTDIR}/${DB}/${TABLE}_data.tsv.gz"

  done < <(clickhouse-client ${CONFIG} -q "SHOW TABLES FROM ${DB}")
done < <(clickhouse-client ${CONFIG} -q "SHOW DATABASES")

exit $?

Конфигурирование "Bacula".

Дополняем описание задания резервного копирования сервиса "Clickhouse" следующими блоками конфигурации:

# vi /etc/bacula/client.d/example.net.conf

....
FileSet {
....

  Include {
    ....

    # Директория резервных копий "дампов баз данных"
    File = "/var/backups/bacula-clickhouse"
  }
}
....

Job {
  Name = "example.net"
  Type = Backup
  ....

  # Запуск выгрузки резервной копии всех локальных "баз данных" Clickhouse в формате TSV:
  RunScript {
    RunsWhen = Before
    FailJobOnError = No

    # Зачищаем и воссоздаём место для сохранения "дампа"
    Command = "rm -rf /var/backups/bacula-clickhouse"
    Command = "mkdir -p /var/backups/bacula-clickhouse"

    # Запускаем выгрузку резервной копии БД:
    # (с парольной аутентификацией, из типового месторасположения такового)
    Command = "/bin/bash -c '/usr/local/bin/clickhouse-backup-tsv.sh /var/backups/bacula-clickhouse 1>/var/log/bacula-clickhouse.log 2>&1'"
  }
  #
  RunScript {
    RunsWhen = After
    RunsOnFailure = yes

    # По завершению всех процедур задания высвобождаем ресурсы
    Command = "rm -rf /var/backups/bacula-clickhouse"
  }
}

Проверяем корректность конфигурации и применяем таковую:

# bacula-dir -c /etc/bacula/bacula-dir.conf -t
# /etc/init.d/bacula-dir reload

Выше я заворачиваю содержимое директивы "Command" в дополнительный контейнер из "/bin/bash" - это требуется потому, что по умолчанию "Bacula FD" запускает свои команды в интерпретаторе "Dash", синтаксис которого отличается от привычного мне "Bash".


Заметки и комментарии к публикации:


Оставьте свой комментарий ( выразите мнение относительно публикации, поделитесь дополнительными сведениями или укажите на ошибку )