Решения

Interruptible‑инстансы: чекпоинты и устойчивость

Задача страницы. Практический гид, как безопасно и эффективно работать на interruptible‑инстансах (прерываемых узлах): чекпоинты и автосейвы, идемпотентные пайплайны, «чанкование» задач, lease/heartbeat‑механики, быстрый рестарт с NVMe‑кэша и расчёт экономики. Подходит для офлайн‑батчей (ETL/RAPIDS, рендер, ASR‑обработка, обучение/пересчёт моделей, симуляции), а также для «полуонлайна» с допусками по SLA.

TL;DR

  • Разделяйте пулы: On‑Demand (жёсткое SLA) vs Interruptible (массовые батчи/офлайн). См. https://cloudcompute.ru/solutions/throughput-vs-latency/
  • Чанк ≤ 120 с + идемпотентность: каждый чанк перерабатывается без побочных эффектов; финализация — атомарная.
  • Два уровня чекпоинтов: быстрый локальный (NVMe) каждые N секунд/шагов, и «надёжный» — в объектное хранилище (реже).
  • Lease + heartbeat: «кто держит чанк» с TTL; по таймауту работа автоматически переотдаётся другому воркеру.
  • WAL/манифест: журнал прогресса и manifest.json с версионированием моделей/данных/порогов.
  • Грациозное завершение: ловим сигнал остановки, за ≤ 5–30 с пишем быстрый чекпоинт и отдаём lease.
  • Экономика: выгодно, если Discount_interruptible > Overhead(checkpoint + потери); расчёт — ниже.
  • Наблюдаемость: checkpoint_age, resume_count, lost_work_sec, chunk_fail_rate, commit_lag, HBM/NVMe.

Сценарии (когда это нужно)

Архитектуры/пайплайны (паттерны)

A) Map‑Reduce с идемпотентной финализацией

				
					Jobs manifest (chunks.json)
  └─> Scheduler (lease TTL, backoff)
       └─> Worker:
            ├─ 1) Pull chunk → local NVMe
            ├─ 2) Compute (≤120 s)
            ├─ 3) Write WAL + local checkpoint
            ├─ 4) Commit atomically → object storage
            └─ 5) Ack lease → done
                  ↳ On failure: lease timeout → reassign
				
			

Ключи: атомарная финализация через «временный путь → rename/commit‑маркер», read‑after‑write валидация, повторный запуск безопасен.

B) Потоковая обработка с быстрым автосейвом

				
					Stream → Micro-batch (5–30 s) → GPU stage → WAL + partial state (NVMe) → Flush/commit (перекат окна)


				
			

Ключи: фиксированные «водяные знаки» времени, запрет «вечных» трансакций, компенсационные записи для отмены.

C) Обучение/инференс (elastic)

				
					Data shards → Trainer/Inferencer (elastic world size)
  ├─ Periodic checkpoints:
  │    - fast: weights/optimizer to NVMe (часто)
  │    - durable: to object store (реже)
  └─ Resume:
       - manifest.yaml (step/seed/versions)
       - deterministic dataloader (reseed)
				
			

См. распределёнку: https://cloudcompute.ru/solutions/multi-gpu/

Профили и ориентиры (инженерные)

Оценка устойчивости и параметров чекпоинтинга по профилям GPU. Цифры — ориентиры для «средних» задач (обработка батчей/рендер/инференс), NVMe‑кэш, U≈0.7.

Профиль

Память

Реком‑интервал fast‑чекпоинта

Типичный объём fast‑ckpt

Параллельных чанков/GPU*

24 ГБ (Compact)

24 ГБ

30–60 с

50–300 МБ

2–4

48 ГБ (Balanced)

48 ГБ

30–90 с

100–600 МБ

4–8

80 ГБ (HQ)

80 ГБ

60–120 с

200–1200 МБ

8–16

* «Параллельных чанков» — микробатчей/потоков в пределах VRAM/I/O. Тюнинг — https://cloudcompute.ru/solutions/performance-tuning/

Конфиги и скелеты кода

Docker Compose: воркер с autosave/lease/WAL

				
					version: "3.9"

x-env: &env
  CHUNK_MAX_SEC: "120"
  CHECKPOINT_LOCAL: "/nvme/ckpt"
  CHECKPOINT_REMOTE: "/obj/ckpt"
  WAL_DIR: "/nvme/wal"
  LEASE_DIR: "/obj/leases"
  JOBS_MANIFEST: "/obj/jobs/chunks.json"
  AUTOSAVE_SEC: "45"
  GRACEFUL_TIMEOUT_SEC: "20"
  PRECISION: "fp16"  # bf16|fp16|fp32

services:
  intr-worker:
    image: cloudcompute/interruptible-worker:latest
    environment: *env
    deploy:
      resources:
        reservations:
          devices: [{capabilities: ["gpu"]}]
    volumes:
      - /nvme/cache:/nvme
      - /mnt/object:/obj
    command: ["python","worker.py","--manifest","/obj/jobs/chunks.json"]


				
			

Kubernetes: preStop + увеличение grace‑тайма

				
					apiVersion: apps/v1
kind: Deployment
metadata: { name: intr-worker }
spec:
  replicas: 3
  selector: { matchLabels: { app: intr-worker } }
  template:
    metadata: { labels: { app: intr-worker } }
    spec:
      terminationGracePeriodSeconds: 30
      containers:
        - name: worker
          image: cloudcompute/interruptible-worker:latest
          resources: { limits: { nvidia.com/gpu: 1, cpu: "4", memory: "24Gi" } }
          lifecycle:
            preStop:
              exec: { command: ["/bin/sh","-c","kill -TERM 1; sleep 5"] }
          env:
            - { name: AUTOSAVE_SEC, value: "45" }
            - { name: CHUNK_MAX_SEC, value: "120" }


				
			

YAML: манифест джобы и записей WAL

				
					job:
  id: "job_2025_08_29T12_00Z"
  dataset: "s3://bucket/ds/v1/"   # или /obj/...
  chunks:
    - { id: "000001", from_s: 0, to_s: 120, status: "todo" }
    - { id: "000002", from_s: 120, to_s: 240, status: "todo" }
  policy:
    retry_max: 3
    backoff_sec: [10, 30, 60]
    lease_ttl_sec: 180
    atomic_commit: true
wal_record:
  job: "job_2025_08_29T12_00Z"
  chunk: "000001"
  step:  "compute"
  ts: "2025-08-29T12:03:00Z"
  meta: { gpu_mem_peak_mb: 16384, out_bytes: 104857600 }


				
			

Python: воркер с lease/heartbeat и атомарным commit

				
					import os, json, time, signal, uuid, shutil, tempfile, pathlib
LEASE_TTL = 180
GRACE = int(os.getenv("GRACEFUL_TIMEOUT_SEC", "20"))

_should_exit = False
def _graceful(*_):  # ловим SIGTERM/SIGINT
    global _should_exit; _should_exit = True

for s in (signal.SIGTERM, signal.SIGINT): signal.signal(s, _graceful)

def lease_take(lease_dir, chunk_id, holder):
    p = pathlib.Path(lease_dir, f"{chunk_id}.json")
    now = time.time()
    try:
        if p.exists():
            lease = json.loads(p.read_text())
            if now - lease["ts"] < LEASE_TTL: return False
        p.write_text(json.dumps({"holder": holder, "ts": now}))
        return True
    except Exception:
        return False

def lease_heartbeat(lease_dir, chunk_id, holder):
    p = pathlib.Path(lease_dir, f"{chunk_id}.json")
    p.write_text(json.dumps({"holder": holder, "ts": time.time()}))

def atomic_commit(tmp_dir, final_dir):
    os.makedirs(final_dir, exist_ok=True)
    staging = tempfile.mkdtemp(prefix="commit_", dir=final_dir)
    for name in os.listdir(tmp_dir):
        shutil.move(os.path.join(tmp_dir, name), staging)
    os.replace(staging, os.path.join(final_dir, pathlib.Path(staging).name))
    pathlib.Path(final_dir, "DONE").touch()

def process_chunk(chunk, ckpt_dir) -> bool:
    # 1) compute → периодический autosave в ckpt_dir
    # 2) собрать результаты в tmp_out, затем atomic_commit
    return True

def main(manifest, lease_dir, ckpt_local, out_remote):
    holder = f"{uuid.uuid4()}"
    chunks = json.loads(open(manifest).read())["chunks"]
    for ch in chunks:
        if not lease_take(lease_dir, ch["id"], holder): continue
        start = time.time()
        last_hb = start
        while not _should_exit:
            ok = process_chunk(ch, ckpt_local)
            if not ok: break
            if time.time() - last_hb > 10:
                lease_heartbeat(lease_dir, ch["id"], holder); last_hb = time.time()
            break
        if _should_exit:
            # быстрый чекпоинт перед выходом
            pathlib.Path(ckpt_local, "quick.ckpt").touch()
            break
        # COMMIT
        atomic_commit(tmp_dir=os.path.join(ckpt_local, "out", ch["id"]),
                      final_dir=os.path.join(out_remote, ch["id"]))


				
			

Наблюдаемость/метрики/алерты

Perf/Latency:

  • chunk_time_seconds (p50/p95), lost_work_seconds (оценка потерянной работы при прерывании).
  • resume_time_seconds, checkpoint_write_seconds, checkpoint_size_bytes.
  • queue_wait_seconds, throughput_chunks_per_min, gpu_utilization, gpu_mem_peak_bytes, nvme_{read,write}_mb_s.

Reliability:

  • lease_expired_total, resume_count_total, retry_total{reason=oom|preempt|io|data}, chunk_fail_rate.
  • checkpoint_age_seconds, manifest_drift (версионные несовпадения моделей/данных).

Data/Commit:

  • commit_lag_seconds, exactly_once_conflicts_total, wal_gap_total.

Алерты (примеры):

  • chunk_time_p95 > SLO — уменьшить размер чанка/батча, оптимизировать I/O, распараллелить.
  • lost_work_seconds_per_hour > budget — чаще fast‑чекпоинт, T_opt↓ (см. Экономика), увеличить lease_ttl.
  • resume_count ↑ — частые прерывания/нестабильность; проверить кворум узлов, перенести часть джоб в On‑Demand.
  • exactly_once_conflicts_total > 0 — усилить атомарность коммита, уникальные ключи, дедуп‑правила.

Детали мониторинга:
https://cloudcompute.ru/solutions/monitoring-logging/https://cloudcompute.ru/solutions/llm-inference/observability/

Экономика и формулы

Обозначения: c_gpu — цена/час, U — целевая загрузка; λ — интенсивность прерываний (1/час); C — время записи fast‑чекпоинта; T — интервал между fast‑чекпоинтами; t_base — чистое время вычислений.

  • Потери из‑за прерываний (ожид.):
    При равномерном распределении моментов прерываний средняя потеря работы на один обрыв ≈ T/2.
    Тогда Overhead_interrupt ≈ λ × (T/2).
  • Оверхед на чекпоинты: Overhead_ckpt ≈ C / T (доля времени).
  • Оптимальный интервал fast‑чекпоинта (оценка):
    Минимизируя Overhead_total = C/T + λT/2, получаем T_opt ≈ sqrt(2C/λ).
  • Итоговое время:
    T_total ≈ t_base × (1 + Overhead_ckpt + Overhead_interrupt).
  • Стоимость:
    Cost_total ≈ c_gpu × T_total / U.
  • Брейк‑ивен interruptible vs on‑demand:
    Пусть Discount = (Cost_on_demand — Cost_interruptible) / Cost_on_demand.
    Использовать interruptible выгодно, если Discount > Overhead_total.

Планирование бюджета: https://cloudcompute.ru/solutions/cost-planner/ • компромиссы: https://cloudcompute.ru/solutions/throughput-vs-latency/

Безопасность и политики

  • PII/секреты: только через секрет‑хранилища/переменные окружения; шифрование «в канале/на диске».
  • WAL/манифесты: подписывать хэшем/версией; хранить в объектном хранилище с версионированием.
  • Idempotency by design: финальные объекты — неперезаписываемые; только «append + commit‑маркер».
  • Разделение доступов: разные бакеты/префиксы на «сырьё», промежуточные и финальные артефакты.

Подробнее: https://cloudcompute.ru/solutions/security/https://cloudcompute.ru/solutions/storage-data/

Траблшутинг

Симптом

Возможная причина

Решение

Повторная обработка одних и тех же чанков

Нет атомарной финализации/уникальных ключей

«tmp → rename + DONE», дедуп по job_id+chunk_id+hash

Потеря прогресса при остановке

Нет быстрого чекпоинта/ловли сигналов

Обработчики SIGTERM/SIGINT, fast‑ckpt ≤ 5–20 с, WAL на NVMe

OOM/разбухание VRAM

Большой батч/слишком много параллелизма

FP16/BF16, уменьшить батч/параллелизм, spill на NVMe

«Залипшие» лизы

Некорректный TTL/часовой дрейф

heartbeat каждые 10–20 с, TTL с запасом, синхронизация времени

Конфликт версий артефактов

Миграция модели/схемы без манифеста

Версионирование (model_v, schema_v), миграционные скрипты

Commit медленный

Много мелких файлов/узкое NVMe

Паковать в шард ≥ 128 МБ, параллельный аплоад, уменьшить файловую фрагментацию

Частые ретраи из‑за данных

«Грязные» записи/сломанные партиции

Предвалидация входа, quarantine‑папка, отчёты по браку

Низкая утилизация GPU

Узкое CPU/I/O, слабая конвейеризация

Параллельная подготовка чанков, prefetch, закрепление потоков

См. также: https://cloudcompute.ru/solutions/performance-tuning/https://cloudcompute.ru/solutions/monitoring-logging/

Как запустить в cloudcompute.ru

  1. Откройте Шаблоны запусков: https://cloudcompute.ru/solutions/templates/ — выберите Interruptible Worker или профильный темплейт (RAPIDS/рендер/ASR/инференс).
  2. Разделите нагрузки: On‑Demand (интерактив/стриминг) и Interruptible (батчи/обучение).
  3. Смонтируйте диски: /nvme (кэш/ckpt/WAL) и /mnt/object (надёжные артефакты).
  4. Задайте параметры: CHUNK_MAX_SEC, AUTOSAVE_SEC, LEASE_TTL, атомарный коммит, backoff‑политики.
  5. В продакшне: дашборды (checkpoint/lease/resume/throughput/HBM/NVMe), алерты, канареечные обновления воркеров и схем, тесты на перезапуск.

Чек‑лист перед продом

  • Чанки ≤ 120 с, идемпотентность, атомарная финализация.
  • Быстрый локальный чекпоинт (NVMe) и периодический durable‑чекпоинт (объектное хранилище).
  • Lease/heartbeat с TTL; корректный graceful‑шутдаун (SIGTERM→fast‑ckpt).
  • WAL/manifest с версиями данных/моделей; детерминированные сиды.
  • Дашборды/алерты: lost_work, resume_count, checkpoint_age, chunk_fail_rate, HBM/NVMe.
  • Рассчитан T_opt ≈ sqrt(2C/λ) и бюджет оверхедов; подтверждён брейк‑ивен по стоимости.
  • Пулы On‑Demand/Interruptible разведены; политика ретраев/кворум/автоскейл настроены.
  • Нагрузочный прогон ≥ 30 мин с искусственными прерываниями.

Навигация