Snapshots в Cassandra — как пользоваться и восстанавливать данные?

от автора

Привет, Хабр! Меня зовут Евгений Абрамкин, я руководитель поддержки третьего уровня в направлении омниканальных решений Лиги Цифровой Экономики. Моя команда — последняя «инстанция» во флоу по решению инцидентов. Мы пишем доработки и фиксы, чтобы победить проблему клиента, а еще предоставляем оптимальную конфигурацию для системы, которая передана в эксплуатацию или требует масштабирования. Это может быть кластер Elasticsearch, балансировщики nginx или что поинтереснее — распределенная NoSQL СУБД Apache Cassandra.

В материале я расскажу про такую важную и необходимую функциональность Apache Cassandra, как Snapshots (они же снапшоты, они же снимки): как пользоваться, как восстанавливать и переносить данные. И совсем немного — про бэкап.

Я пропущу объяснение, что такое Apache Cassandra, и перейду сразу к использованию стандартной консольной утилиты, ориентируясь на то, что читатель уже верхнеуровнево знаком с Cassandra.

Что такое snapshot

Snapshot (далее по тексту «снимок») в Cassandra — это процесс создания копии данных из существующих SSTable файлов и записи их в отдельную директорию на диске. Это позволяет сохранить состояние данных в определенный момент времени и использовать эту копию для их восстановления в случае потери или повреждения, а также переноса из одного кластера Cassandra в другой. У вас должно быть достаточно свободного дискового пространства на узле кластера, чтобы можно было создавать снимки файлов данных. Их постоянное снятие может привести к тому, что диск будет со временем быстрее заполняться: снимок предотвращает удаление устаревших файлов данных. После того как snapshot сделан, вы можете переместить файлы резервных копий в другое место, если это необходимо, или удалить.

Снимок — это набор файлов, которые содержат данные из определенного кейспейса. Эти файлы хранятся в директории snapshot в формате SSTable. Создание снимка — относительно быстрый процесс, который не блокирует запись или чтение данных из кластера. Он может быть выполнен в любое время, и копия данных будет доступна для восстановления.

Важно отметить, что snapshot — не полное резервное копирование кластера Cassandra. Для этого необходимо использовать другие методы: инкрементное резервное копирование или репликацию данных на другой кластер.

Как создать snapshot в Cassandra

Для создания снимка в Cassandra используется стандартная команда nodetool snapshot.

Например, чтобы создать snapshot для кейспейса «phoenix», можно выполнить следующую команду в терминале:

nodetool snapshot phoenix   [cassandra@cassandra-09 ~]$ nodetool snapshot phoenix  Requested creating snapshot(s) for [phoenix] with snapshot name [1681564715891] and options {skipFlush=false}  Snapshot directory: 1681564715891 

Она создаст новый снимок для кейспейса «phoenix».

Проверить, что снимок создан и Cassandra может с ним работать, можно командой ниже:

nodetool listsnapshots   [cassandra@cassandra-09 ~]$ nodetool listsnapshots | grep phoenix  1681564715891                              phoenix   tag_views                  0 bytes1.43 KiB  1681564715891                              phoenix   tag_scanning               0 bytes879 bytes  1681564715891                              phoenix   metadata                   0 bytes903 bytes  1681564715891                              phoenix   offsetstore                0 bytes981 bytes  1681564715891                              phoenix   messages                   0 bytes1.42 KiB  1681564715891                              phoenix       tag_write_progress         0 bytes1002 bytes 

Сам снимок создается в каталоге data_directory/phoenix/table_name-UUID/snapshots/snapshot_name. Каждый каталог снимка содержит множество файлов .db, которые включают в себя данные на момент создания снимка. При выполнении команды можно использовать опцию —tag, чтобы было проще в дальнейшем работать со снимком. Листинг директории со снимком будет выглядеть так:

[cassandra@cassandra-09 messages]$ ll  -rw-r--r--. 1 cassandra cassandra        694 Apr 14 12:59 manifest.json  -rw-r--r--. 1 cassandra cassandra         43 Mar 20 15:12 me-4459-big-CompressionInfo.db  -rw-r--r--. 1 cassandra cassandra      16784 Mar 20 15:12 me-4459-big-Data.db  -rw-r--r--. 1 cassandra cassandra         10 Mar 20 15:12 me-4459-big-Digest.crc32  -rw-r--r--. 1 cassandra cassandra         72 Mar 20 15:12 me-4459-big-Filter.db  -rw-r--r--. 1 cassandra cassandra       1965 Mar 20 15:12 me-4459-big-Index.db  -rw-r--r--. 1 cassandra cassandra       5603 Mar 27 11:13 me-4459-big-Statistics.db  -rw-r--r--. 1 cassandra cassandra        164 Mar 20 15:12 me-4459-big-Summary.db  -rw-r--r--. 1 cassandra cassandra         92 Mar 20 15:12 me-4459-big-TOC.txt  -rw-r--r--. 1 cassandra cassandra       1783 Apr 14 12:59 schema.cql

Кроме того, можно использовать опцию —table для создания снимка только для одной таблицы внутри кейспейса.
Например:

nodetool snapshot phoenix ‑table messages

Эта команда создаст снимок только для таблицы «messages» для кейспейса «phoenix».

Восстановление данных с помощью команды sstableloader

SSTableLoader — это инструмент командной строки в Cassandra, используемый для загрузки SSTable (Sorted String Table) в кластер. Последний — это отсортированный набор данных, который представляет собой неизменяемый файл на диске. SSTable состоит из двух файлов: файла данных и файла индекса. Это основной механизм хранения данных в Cassandra.

Инструмент SSTableLoader обычно применяется для восстановления данных из снимков, а также для их переноса между кластерами (например, чтобы обогатить тестовый кластер продуктивными данными для нагрузочного тестирования).

Для восстановления данных с помощью команды sstableloader необходимо выполнить следующие шаги:

1. Создайте снимок при помощи команды nodetool snapshot:

nodetool snapshot <keyspace>

где <keyspace> — название кейспейса, для которого создается снимок.

2. Скопируйте все SSTable-файлы из директории

<data_directory>/<keyspace>/<table_name-UUID>/snapshots/<snapshot_name> на новый узел кластера или на текущий узел кластера <data_directory>/<keyspace>/<table_name-UUID>, в зависимости от задачи — восстановление или перенос данных.

3. Запустите команду sstableloader:

sstableloader -d <destination_node> <path_to_sstable_directories>

где <destination_node> — IP-адрес узла кластера, на который загружаются данные, а <path_to_sstable_directories> — путь к директориям, содержащим SSTable-файлы, скопированные из снимка.

[cassandra@cassandra-09 ]$ sstableloader -d cassandra-09 /var/lib/cassandra/ssd/data/phoenix/messages/  Established connection to initial hosts  Opening sstables and calculating sections to stream  Streaming relevant part of /var/lib/cassandra/ssd/data/phoenix/messages/md-20-big-Data.db /var/lib/cassandra/ssd/data/phoenix/messages/md-20-big-Data.db /var/lib/cassandra/ssd/data/phoenix/messages/me-9-big-Data.db /var/lib/cassandra/ssd/data/phoenix/messages/md-48-big-Data.db /var/lib/cassandra/ssd/data/phoenix/messages/me-21-big-Data.db /var/lib/cassandra/ssd/data/phoenix/messages/me-18-big-Data.db to [/10.10.10.07, /10.10.10.08, /10.10.10.09]  progress: [/10.78.222.233]0:1/18 0  % total: 0% 13.845KiB/s (avg: 0.045KiB/s)  progress: [/10.78.222.233]0:2/18 25 % total: 0% 27.346MiB/s (avg: 27.798KiB/s)  progress: [/10.78.222.233]0:3/18 30  % total: 0% 8.729MiB/s (avg: 33.436KiB/s)  progress: [/10.78.222.233]0:4/18 35  % total: 0% 12.431MiB/s (avg: 41.715KiB/s)  progress: [/10.78.222.233]0:5/18 40  % total: 0% 82.531MiB/s (avg: 306.882KiB/s)  progress: [/10.78.222.233]0:6/18 45 % total: 12% 28.052MiB/s (avg: 4.930MiB/s)  progress: [/10.78.222.233]0:7/18 45 % total: 16% 8.972MiB/s (avg: 5.508MiB/s)  progress: [/10.78.222.233]0:8/18 50 % total: 20% 9.683MiB/s (avg: 5.996MiB/s)  progress: [/10.78.222.233]0:9/18 55 % total: 87% 184.800KiB/s (avg: 8.640MiB/s)  progress: [/10.78.222.233]0:10/18 60 % total: 87% 42.059MiB/s (avg: 8.650MiB/s)  progress: [/10.78.222.233]0:11/18 65 % total: 91% 9.853MiB/s (avg: 8.694MiB/s)  progress: [/10.78.222.233]0:12/18 70 % total: 95% 758.657MiB/s (avg: 9.053MiB/s)  progress: [/10.78.222.233]0:13/18 75 % total: 98% 27.475MiB/s (avg: 9.294MiB/s)  progress: [/10.78.222.233]0:14/18 80 % total: 99% 12.327MiB/s (avg: 9.319MiB/s)  progress: [/10.78.222.233]0:15/18 85 % total: 99% 28.579MiB/s (avg: 9.322MiB/s)  progress: [/10.78.222.233]0:16/18 90 % total: 99% 2.056MiB/s (avg: 9.321MiB/s)  progress: [/10.78.222.233]0:17/18 95% total: 100% 4.485MiB/s (avg: 9.321MiB/s)  progress: [/10.78.222.233]0:18/18 100% total: 100% 0.000KiB/s (avg: 8.697MiB/s)   Summary statistics:     Connections per host: 1     Total files transferred : 18     Total bytes transferred : 262.110MiB     Total duration      : 30138 ms     Average transfer rate   : 8.697MiB/s     Peak transfer rate  : 9.322MiB/s

4. Дождитесь завершения загрузки данных. На листинге команды выше — это вывод Summary statistics.

5. Проверьте, что ваши данные загрузились через консольную утилиту cqlsh:

cassandra@cqlsh> select * from phoenix.messages;

После выполнения команды sstableloader данные из снимка будут загружены в кластер. Если на его узле уже существуют данные для кейспейса, то из снимка они будут добавлены к уже существующим.

Далее после восстановления данных или переноса на новый кластер необходимо выполнить nodetool repair:

nodetool repair <keyspace_name>

Резервное копирование кластера

Цель статьи — рассказать про стандартный инструмент снятия снимков и работы с восстановлением или переносом данных, но я хочу подсветить и тему резервного копирования (бэкап). Для такого действия с кластером Cassandra можно использовать несколько подходов:

1. Использовать nodetool snapshot и выполнять его с помощью cron. Бюджетно и «из коробки», но не идеальный способ, так как необходимо регулярно создавать снимки данных и сохранять их в отдельное хранилище.

2. Применять Incremental Backups в Cassandra. Тоже работает «из коробки». Для создания инкрементных резервных копий нужно выставить true для incremental_backups в файле конфигурации Cassandra (cassandra.yaml), либо выполнив nodetool enablebackup для включения и nodetool disablebackup для выключения. Процесс восстановления данных такой же, как и при nodetool snapshot, но нужно тщательно следить за местом на дисках!

3. Прибегать к различным инструментам резервного копирования, таким как rsync, scp, tar. Вместе с обвязкой скриптами они будут копировать все файлы данных Cassandra, а именно SSTable, в отдельное хранилище. Снова не идеальное решение, но имеет место быть.

4. Использовать [Medusa for Apache Cassandra], комплексный инструмент резервного копирования и восстановления как одной ноды, так и целого кластера. Есть возможность интеграции с S3 совместимыми хранилищами, например с Minio. Настройка Medusa, перечисление всех плюсов и минусов — тема для отдельной статьи.

Выводы

  • Восстановление данных из cнимка (snapshot) — самый быстрый и простой способ вернуть данные в случае частичной потери или аварии в кластере.

  • Не забывайте создавать резервные копии для предотвращения потери данных в будущем.

P.S.

Бонус: скрипт для клонирования кейспеса, подходит для работы с тестовым окружением:
#!/bin/bash  cloneKeyspace()  {  local username="${1}"  local start_host="${2}"  local hostnames="${3}"  local keyspace_source="${4}"  local keyspace_destination="${5}"  local data_dir="/var/lib/cassandra/ssd/data"​  echo "Drop ${keyspace_destination} keyspace"  ssh ${username}@${start_host} "cqlsh -u cassandra -p password ${start_host} -e 'DROP KEYSPACE ${keyspace_destination}'"  for hostname in $(echo $hostnames | sed "s/,/ /g")  do    echo "Delete ${keyspace_destination} keyspace directory"    ssh ${username}@${hostname} "sudo rm -rf ${data_dir}/${keyspace_destination}"  done  if ssh ${username}@${start_host} "echo 2>&1"; then   ssh ${username}@${start_host} "cqlsh -u cassandra -p password ${start_host} -e 'DESCRIBE KEYSPACE ${keyspace_source}' > ${keyspace_source}.txt"   ssh ${username}@${start_host} "sed -i 's/${keyspace_source}/${keyspace_destination}/g' ${keyspace_source}.txt"   ssh ${username}@${start_host} "cqlsh -u cassandra -p password ${start_host} -f '${keyspace_source}.txt'"   ssh ${username}@${start_host} "rm ${keyspace_source}.txt"        echo "Success on Keyspace Schema clone: "${start_host}  else    echo "Failed on Keyspace Schema clone: "${start_host}  fi    for hostname in $(echo $hostnames | sed "s/,/ /g")  do     if ssh ${username}@${hostname} "echo 2>&1"; then      echo "Clear snapshot copy on ${hostname}"      ssh ${username}@${hostname} "nodetool clearsnapshot -t copy"      echo "Create new snapshot copy on ${hostname}"      ssh ${username}@${hostname} "nodetool snapshot -t copy ${keyspace_source}"      echo "Success on Cassandra snapshot: "${hostname} ${keyspace_source}            sleep 20            ssh ${username}@${hostname} "sudo mv ${data_dir}/${keyspace_source}/metadata-*/snapshots/copy/* ${data_dir}/${keyspace_destination}/metadata-*/"      ssh ${username}@${hostname} "sudo mv ${data_dir}/${keyspace_source}/snapshots-*/snapshots/copy/* ${data_dir}/${keyspace_destination}/snapshots-*/"      ssh ${username}@${hostname} "sudo mv ${data_dir}/${keyspace_source}/messages-*/snapshots/copy/* ${data_dir}/${keyspace_destination}/messages-*/"      ssh ${username}@${hostname} "sudo mv ${data_dir}/${keyspace_source}/tag_scanning-*/snapshots/copy/* ${data_dir}/${keyspace_destination}/tag_scanning-*/"            ssh ${username}@${hostname} "nodetool clearsnapshot -t copy"           echo "Success on Cassandra mv of snapshot files to destination: "${keyspace_destination}      ssh ${username}@${hostname} "nodetool refresh ${keyspace_destination} snapshots"      ssh ${username}@${hostname} "nodetool refresh ${keyspace_destination} messages"      ssh ${username}@${hostname} "nodetool refresh ${keyspace_destination} metadata"      ssh ${username}@${hostname} "nodetool refresh ${keyspace_destination} tag_scanning"            echo "Success on Cassandra nodetool refresh on destination keyspace: "${keyspace_destination}     else      echo "Failed on Cassandra snapshot: "${hostname}     fi  done    if ssh ${username}@${start_host} "echo 2>&1"; then   ssh ${username}@${start_host} "nodetool repair -full ${keyspace_destination}"   echo "Success on Keyspace repair: "${start_host} ${keyspace_destination}  else   echo "Failed on Keyspace repair : "${start_host} ${keyspace_destination}  fi    echo "Script processing completed!"  }  ​  cloneKeyspace "${1}" "${2}" "${3}" "${4}" "${5}"  


ссылка на оригинал статьи https://habr.com/ru/articles/730424/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *