Elasticsearch хранит данные в шардах — каждый шард это по сути отдельный индекс Lucene на диске. Просто скопировать файлы нельзя: движок непрерывно пишет в сегменты, и «холодный» снимок директории окажется повреждённым. Единственный надёжный способ бэкапа, который поддерживает Elastic, — это снапшоты через _snapshot API.

Снапшот фиксирует состояние индексов в конкретный момент и записывает его в snapshot repository — внешнее хранилище за пределами кластера. Именно это важно: если кластер сломается целиком, данные в репозитории останутся нетронутыми.


Snapshot repository: типы хранилищ

Перед первым снапшотом нужно зарегистрировать репозиторий. Поддерживаемые типы:

ТипОписание
fsОбщая файловая система (NFS, network share)
s3AWS S3 (плагин repository-s3)
gcsGoogle Cloud Storage (плагин repository-gcs)
azureAzure Blob Storage (плагин repository-azure)
found-snapshotsВстроенный тип Elastic Cloud — настраивается автоматически

Для s3, gcs и azure нужно установить соответствующий плагин на каждой ноде кластера. Для fs — сетевой каталог, смонтированный одинаково на всех нодах, и настройка path.repo в elasticsearch.yml.

Критичное правило: в один репозиторий пишет только один кластер. Если два кластера пишут в одно хранилище, это приведёт к повреждению снапшотов. Если второй кластер (например, DR-площадка) только читает оттуда — подключайте его с "readonly": true.


Шаг 1: зарегистрировать репозиторий

PUT /_snapshot/my_backup_repo
{
  "type": "fs",
  "settings": {
    "location": "/mnt/snapshots/my_cluster"
  }
}

ES ответит {"acknowledged": true}. После регистрации автоматически запускается верификация: все ноды проверяют доступность пути. Посмотреть зарегистрированные репозитории:

GET /_snapshot

Для S3 структура немного другая:

PUT /_snapshot/s3_repo
{
  "type": "s3",
  "settings": {
    "bucket": "my-es-backups",
    "region": "eu-west-1",
    "base_path": "prod-cluster"
  }
}
Проверь себя
Представьте: у вас два кластера ES — production и staging. Оба подключены к одному snapshot repository с правом записи. Что может пойти не так?

Шаг 2: создать снапшот

Снапшот всего кластера — без параметров в теле:

PUT /_snapshot/my_backup_repo/snapshot_2024_06_27

По умолчанию запрос возвращается сразу, не дожидаясь завершения (снапшот создаётся в фоне). Чтобы дождаться результата:

PUT /_snapshot/my_backup_repo/snapshot_2024_06_27?wait_for_completion=true

Если нужно сохранить только часть индексов:

PUT /_snapshot/my_backup_repo/snapshot_catalog
{
  "indices": "products,orders,users-*",
  "ignore_unavailable": true,
  "include_global_state": false,
  "metadata": {
    "comment": "before price migration"
  }
}

ignore_unavailable: true — снапшот не упадёт, если какого-то индекса нет. include_global_state: false — сохраняем только данные, без настроек кластера и шаблонов. metadata — произвольные заметки (до 1024 байт), удобно для аудита.

Снапшоты инкрементальные: каждый следующий копирует только новые сегменты Lucene, которых не было в предыдущих. Хранить их недорого — пространство на диске не дублируется.

sequenceDiagram participant ES as Elasticsearch participant Repo as Snapshot Repository Note over ES,Repo: Настройка ES->>Repo: PUT /_snapshot/my_repo Repo-->>ES: acknowledged: true Note over ES,Repo: Создание бэкапа ES->>Repo: PUT /_snapshot/my_repo/snap_1 Repo-->>ES: state: SUCCESS Note over ES,Repo: Восстановление ES->>Repo: POST /_snapshot/my_repo/snap_1/_restore Repo-->>ES: индексы восстановлены
sequenceDiagram
    participant ES as Elasticsearch
    participant Repo as Snapshot Repository

    Note over ES,Repo: Настройка
    ES->>Repo: PUT /_snapshot/my_repo
    Repo-->>ES: acknowledged: true

    Note over ES,Repo: Создание бэкапа
    ES->>Repo: PUT /_snapshot/my_repo/snap_1
    Repo-->>ES: state: SUCCESS

    Note over ES,Repo: Восстановление
    ES->>Repo: POST /_snapshot/my_repo/snap_1/_restore
    Repo-->>ES: индексы восстановлены
Жизненный цикл снапшота: регистрация репозитория → создание → восстановление

Просмотр и удаление снапшотов

Список снапшотов в репозитории:

GET /_snapshot/my_backup_repo/_all

Конкретный снапшот с деталями:

GET /_snapshot/my_backup_repo/snapshot_2024_06_27

В ответе будут статус (SUCCESS, IN_PROGRESS, FAILED), список индексов и временны́е метки. Удалить снапшот:

DELETE /_snapshot/my_backup_repo/snapshot_2024_06_27

При удалении ES не трогает сегменты, на которые ссылаются другие снапшоты — дедупликация встроена на уровне файлов.

Проверь себя
Снапшоты snap_1 и snap_2 создавались последовательно и разделяют общие сегменты данных. Что произойдёт с этими сегментами, если удалить snap_1?

Шаг 3: восстановить данные

Базовое восстановление всего снапшота:

POST /_snapshot/my_backup_repo/snapshot_2024_06_27/_restore

Восстановить конкретные индексы:

POST /_snapshot/my_backup_repo/snapshot_2024_06_27/_restore
{
  "indices": "products,orders",
  "include_global_state": false,
  "include_aliases": true
}

Нюанс: нельзя восстановить индекс поверх открытого с тем же именем. Два варианта:

1. Закрыть (POST /products/_close) или удалить существующий индекс, затем восстановить.

2. Восстановить под другим именем через rename_pattern и rename_replacement.

Второй вариант удобен, когда нельзя останавливать production-трафик:

POST /_snapshot/my_backup_repo/snapshot_2024_06_27/_restore
{
  "indices": "products",
  "rename_pattern": "(.+)",
  "rename_replacement": "restored_$1"
}

Индекс products появится в кластере как restored_products. Оригинал продолжает работать без перебоев, пока вы проверяете восстановленную копию.

Проверь себя
Вам нужно восстановить индекс `orders` из снапшота, но в кластере уже есть открытый `orders`. ES выдаст ошибку. Как восстановить данные без остановки production-трафика?

Автоматизация через SLM

Создавать снапшоты вручную каждый день — ненадёжно. В ES 8 встроен SLM (Snapshot Lifecycle Management) — планировщик, который создаёт снапшоты по расписанию и удаляет устаревшие автоматически.

PUT /_slm/policy/daily_backups
{
  "schedule": "0 30 1 * * ?",
  "name": "<daily-snapshot-{now/d}>",
  "repository": "my_backup_repo",
  "config": {
    "indices": ["*"],
    "include_global_state": true
  },
  "retention": {
    "expire_after": "30d",
    "min_count": 5,
    "max_count": 50
  }
}

Расписание — формат Quartz cron (UTC). Политика выше создаёт снапшот каждый день в 01:30 UTC и хранит их не дольше 30 дней, но не меньше 5 штук и не больше 50. Запустить политику вручную (удобно для первого теста):

POST /_slm/policy/daily_backups/_execute

На что обратить внимание

  • Снапшот копирует данные с первичных шардов. Если primary-шард недоступен, снапшот для этого индекса провалится (если не указан "partial": true).
  • Снапшот IN_PROGRESS не блокирует индексирование и поиск, но создаёт небольшую нагрузку на кластер.
  • Восстановить снапшот на более старую версию ES нельзя. Снапшот с ES 7.x совместим с 8.x, но не наоборот.
  • Никогда не редактируйте содержимое репозитория вручную: удаление одного файла может повредить сразу несколько снапшотов без каких-либо предупреждений.
  • Конфигурационные файлы (elasticsearch.yml, сертификаты) снапшоты не включают — резервируйте директорию $ES_PATH_CONF отдельно внешними инструментами.

Быстрое повторение
Можно ли восстановить индекс из снапшота поверх открытого индекса с тем же именем?
Быстрое повторение
Как заставить запрос создания снапшота дождаться завершения вместо немедленного возврата?
Быстрое повторение
Почему нельзя просто скопировать файлы данных Elasticsearch для бэкапа?

См. также

Источники

  1. Snapshot and restore | Elasticsearch Guide 8.19
  2. Register a snapshot repository | Elasticsearch Guide 8.19
  3. Create snapshot API | Elasticsearch Guide 8.19
  4. Restore snapshot API | Elasticsearch Guide 8.19
  5. Take a snapshot | Elasticsearch Guide 8.19