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"
  }
}
Check yourself
Представьте: у вас два кластера 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 не трогает сегменты, на которые ссылаются другие снапшоты — дедупликация встроена на уровне файлов.

Check yourself
Снапшоты 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. Оригинал продолжает работать без перебоев, пока вы проверяете восстановленную копию.

Check yourself
Вам нужно восстановить индекс `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 отдельно внешними инструментами.

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

См. также