Сравнить reserved vs spot vs on-demand для ML-инфраструктуры

ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Сравнить reserved vs spot vs on-demand для ML-инфраструктуры

1. Цель задачи

Научиться анализировать реальные затраты на облачные вычислительные ресурсы (GPU/CPU) за трёхмесячный период и выбирать оптимальное сочетание моделей покупки (reserved instances, spot instances, on-demand) для ML-ворклоудов. Задача имитирует реальный процесс оптимизации cost-efficiency в production ML-системе. В результате вы получите документ с расчётами и рекомендацией по соотношению типов инстансов, минимизирующему общую стоимость при заданных ограничениях по availability и SLA.

Ключевой результат Таблица с тремя сценариями (консервативный, сбалансированный, агрессивный) и обоснованной рекомендацией, а также Python-скрипт для повторного расчёта при изменении входных данных.


2. Исходные данные

Перед началом необходимо иметь:

Что нужноОткуда взять
Детальный отчёт о расходе compute-ресурсов за 3 месяца (часы работы, тип инстанса, регион, цена)AWS Cost and Usage Report (CUR) / Azure Cost Management / GCP Billing export, или симуляция
Прайс-лист на on-demand, reserved (1yr/3yr, предоплата), spot для используемых типов инстансовОфициальные страницы провайдера или API ценообразования
Характеристики ворклоуда (непрерывные vs пакетные задачи, критичность, допустимое время простоя)Из проектной документации или опроса команды
Метрики использования (средняя загрузка GPU, пики, время суток/weekend)CloudWatch / Stackdriver / Azure Monitor + Grafana

Если нет реального датасета — симулируем:

  1. Сгенерируйте синтетический лог использования за 3 месяца (примерно 500-1000 записей) с помощью Python:
    • Типы инстансов: p3.2xlarge (GPU), c5.xlarge (CPU), p4d.24xlarge (GPU) и др.
    • Распределение: 60% on-demand, 30% spot, 10% reserved (чтобы была исходная точка)
    • Часы работы: по будням с 9 до 18 — пиковая нагрузка, в остальное — batch jobs
    • Случайные сбои spot-инстансов (10-20% прерываний)
    • Регион: us-east-1 (для простоты)
  2. Сохраните в CSV с колонками: timestamp, instance_type, region, usage_hours, pricing_model, cost_per_hour

Пример генерации (сохранить как simulate_usage.py):

import pandas as pd
import numpy as np
from datetime import datetime, timedelta

np.random.seed(42)
dates = pd.date_range(start='2025-01-01', end='2025-03-31', freq='H')
instances = ['p3.2xlarge', 'c5.xlarge', 'p4d.24xlarge']
regions = ['us-east-1']
models = ['on_demand', 'spot', 'reserved']

data = []
for t in dates:
    for inst in instances:
        # 60% on_demand, 30% spot, 10% reserved
        model = np.random.choice(models, p=[0.6, 0.3, 0.1])
        # пиковые часы (9-18) больше on_demand
        if 9 <= t.hour < 18 and model == 'on_demand':
            hours = np.random.uniform(0.8, 1.0)
        else:
            hours = np.random.uniform(0.2, 0.6)
        cost = {'p3.2xlarge': 3.06, 'c5.xlarge': 0.34, 'p4d.24xlarge': 32.77}[inst]
        data.append([t, inst, regions[0], round(hours,2), model, round(cost*hours,4)])

df = pd.DataFrame(data, columns=['timestamp','instance_type','region','usage_hours','pricing_model','cost'])
df.to_csv('simulated_usage.csv', index=False)
  1. Скачайте актуальные цены AWS для us-east-1 (или используйте статическую таблицу из приложения).

3. Технологический стек

КомпонентИнструментыНазначение
Анализ данныхPython 3.11+, pandas, numpyОбработка логов, статистика, симуляция
Визуализацияmatplotlib, seabornГрафики загрузки, распределение cost
Облачный провайдер (пример)AWSПровайдер для примеров цен
API ценообразованияboto3 (AWS Price List API) / опциональноАвтоматический сбор цен
Хранение результатаMarkdown, CSVФинальный отчёт и таблицы

4. Этапы выполнения

Этап 1: Сбор и очистка данных (30-40 минут)

Действия

  1. Загрузка синтетического датасета (или реального CUR)

    import pandas as pd
    df = pd.read_csv('simulated_usage.csv', parse_dates=['timestamp'])
    print(df.head(), df.info())
    
  2. Проверка целостности:

    • Нет пропусков по времени (если почасовые данные — все часы)
    • Корректные типы инстансов
    • Цены неотрицательные
  3. Агрегация по дням и типам инстансов:

    daily = df.groupby([df['timestamp'].dt.date, 'instance_type', 'pricing_model']).agg(
        total_hours=('usage_hours','sum'),
        total_cost=('cost','sum')
    ).reset_index()
    
  4. Вычисление базовых метрик:

    • Среднее количество часов в день на один инстанс
    • Пиковая нагрузка (99-й перцентиль часов в день)
    • Доля spot-прерываний (если есть флаг)

Ожидаемый результат этапа DataFrame daily и статистика использования в виде таблицы (среднее, медиана, P90, P99).


Этап 2: Расчёт стоимости для каждой модели покупки (1-1.5 часа)

Действия

  1. Получить цены для on-demand (известны из датасета или актуальные):

    • p3.2xlarge: $3.06/h
    • c5.xlarge: $0.34/h
    • p4d.24xlarge: $32.77/h
  2. Рассчитать reserved instances (1 год, частичная предоплата):

    • Взять коэфициенты: ~40% экономии для 1yr all upfront, ~30% для partial upfront.
    • Формула: effective_reserved_cost = (upfront_fee / 8760 + hourly_fee_reserved) * hours_used
    • Использовать данные AWS: например, для p3.2xlarge reserved 1yr partial upfront = $1.84/h (vs on-demand $3.06)
    • Важно reserved оплачивается полностью, даже если инстанс не используется. Нужно учесть минимальную закупку.
  3. Рассчитать spot:

    • Средняя цена spot для p3.2xlarge в us-east-1 около $0.92 (30% от on-demand, но может колебаться)
    • Учесть прерывания: добавить штраф в 10% времени (перезапуск, потеря прогресса)
    • Spot_price = on_demand_price * 0.3 * (1 + interruption_overhead)
  4. Для каждого типа инстанса построить три колонки: стоимость, если все часы on_demand; если все reserved; если все spot (с учётом прерываний).

  5. Сравнить с фактическими затратами из датасета (смешанная модель).

Ожидаемый результат этапа Таблица цен для каждого типа инстанса по трём моделям (on-demand, reserved, spot). Пример:

Instance typeOn-demand ($/h)Reserved 1yr ($/h)Spot ($/h, avg)Interruption overhead
p3.2xlarge3.061.840.9210%
c5.xlarge0.340.200.105%
p4d.24xlarge32.7719.669.8315%

Этап 3: Оптимизация комбинации (1.5-2 часа)

Действия

  1. Определить ограничения

    • Критический ворклоуд (training) не должен прерываться → min 70% reserved.
    • Non-critical batch jobs → до 100% spot.
    • Dev/test → on-demand или spot.
  2. Построить три сценария

    • Консервативный: 70% reserved, 20% on-demand, 10% spot.
    • Сбалансированный: 40% reserved, 30% on-demand, 30% spot.
    • Агрессивный: 20% reserved, 10% on-demand, 70% spot.
  3. Для каждого сценария рассчитать общую стоимость за 3 месяца:

    • Использовать почасовой лог: для каждого часа и типа инстанса распределить часы между моделями пропорционально сценарию.
    • Например, для часа с p3.2xlarge и 0.9 часа использования: 0.9 * (0.7reserved_price + 0.2on_demand_price + 0.1*spot_price).
    • Учесть, что reserved часы оплачиваются полностью 24/7, поэтому фиксированная часть = резервирование * 24 * 90 дней.
  4. Вычислить метрики

    • Total cost
    • Savings vs 100% on-demand
    • Risk score (вероятность прерывания для критических задач)
  5. Визуализация: столбчатая диаграмма сравнения сценариев, круговая диаграмма распределения моделей.

Ожидаемый результат этапа Числовые значения cost для трёх сценариев, таблица метрик, графики.


Этап 4: Рекомендация и отчёт (30-60 минут)

Действия

  1. Выбрать оптимальный сценарий (например, сбалансированный, если он даёт 40% экономии при приемлемом риске).
  2. Написать отчёт в формате Markdown, включив:
    • Executive summary
    • Методология
    • Таблица сравнения
    • Рекомендуемое соотношение
    • План миграции
  3. Подготовить Python-скрипт cost_optimizer.py, который принимает на вход CSV с использованием и выдаёт рекомендацию.

Ожидаемый результат этапа Файл report.md и cost_optimizer.py.


Этап 5: Защита решения (опционально, 15 минут)

Действия

  1. Подготовить 3 слайда (можно в Markdown):
    • Исходные данные и текущие затраты
    • Сравнение трёх сценариев
    • Рекомендация и обоснование
  2. Ответить на вопросы: почему не 100% spot? как учесть будущий рост?

Ожидаемый результат этапа Готовность к презентации.


5. Критерии приемки (Definition of Done)

  • Сгенерирован синтетический датасет (или использован реальный) с колонками timestamp, instance_type, usage_hours, pricing_model, cost.
  • Для каждого типа инстанса получены цены on-demand, reserved, spot (можно из статической таблицы).
  • Построены и рассчитаны три сценария комбинации моделей.
  • Создана таблица сравнения сценариев с total cost и savings.
  • Написан Python-скрипт, воспроизводящий расчёт при новых данных.
  • Оформлен Markdown-отчёт с executive summary и рекомендацией.
  • Код скрипта закомментирован и содержит docstrings.
  • Все графики (хотя бы один) сохранены в PNG в папке figures/.

6. Ожидаемый результат

Основной артефакт — файл report.md следующего содержания:

# Cost Optimization Report for ML Infrastructure

## Executive Summary
Рекомендуется сценарий "сбалансированный": 40% reserved, 30% on-demand, 30% spot.
Экономия относительно 100% on-demand: 38%.

## Исходные данные
- Период: 3 месяца
- Средняя загрузка: 45%
- Основные типы инстансов: p3.2xlarge, c5.xlarge, p4d.24xlarge

## Сценарии
| Сценарий       | Reserved | On-demand | Spot  | Total cost | Savings |
|----------------|----------|-----------|-------|------------|---------|
| Conservative   | 70%      | 20%       | 10%   | $XX,XXX    | 25%     |
| Balanced       | 40%      | 30%       | 30%   | $XX,XXX    | 38%     |
| Aggressive     | 20%      | 10%       | 70%   | $XX,XXX    | 45% (risk) |

## Рекомендация
- Закупить reserved на 40% от baseline (по типу p3.2xlarge и p4d.24xlarge)
- Остальное: on-demand для critical jobs, spot для batch
- План миграции: в течение 2 недель

## Приложение: Код расчёта
Ссылка на `cost_optimizer.py`

Дополнительно:

  • cost_optimizer.py — скрипт с функцией optimize(usage_csv, pricing_dict).
  • figures/ — папка с графиками.

7. Возможные сложности и их решение

СложностьРешение
Нет реальных данных по прерываниям spotЗаложить фиксированный overhead (10-15%) на основе документации AWS
Разные регионы с разными ценамиОграничиться одним регионом (us-east-1) для упрощения
Reserved предполагает предоплату, сложно учесть NPVИспользовать упрощённую модель: амортизировать upfront на срок (1 год / 8760 часов)
Сложность в распределении часов по сценариямИспользовать подход Monte Carlo: для каждого часа случайно выбрать модель согласно весам, повторить N раз
Отсутствие информации о критичности ворклоудаВвести параметр critical_fraction (по умолчанию 0.3)

8. Бюджет времени (оценка)

ЭтапВремя
1: Сбор и очистка данных0.5 ч
2: Расчёт стоимости моделей1.5 ч
3: Оптимизация комбинации2 ч
4: Рекомендация и отчёт1 ч
5: Защита (опционально)0.25 ч
Итого (рабочее)5.25 ч

Примечание для первого раза Добавьте 1 час на развертывание окружения и понимание AWS Pricing. Итого ~6.5 ч.


9. Связанные вопросы из базы знаний

ВопросТема
Q42Основы cost engineering в облаке
Q58Reserved Instances vs Savings Plans
Q73Spot instance best practices для ML
Q104Мониторинг затрат в AWS
Q127TCO калькулятор для GPU
Q161Практика: анализ billing-отчёта
Q203Оптимизация cost для batch jobs
Q288Риски spot-прерываний и mitigation
Q314Использование AWS Price List API
Q401Построение дашборда cost в Grafana

10. Чек-лист самопроверки

  • Я корректно сгенерировал синтетический датасет и проверил его на аномалии.
  • Я взял актуальные цены для выбранного региона (или использовал статическую таблицу из задания).
  • Я рассчитал стоимость reserved с учётом амортизации upfront.
  • Я учёл overhead spot-прерываний при расчёте общей стоимости.
  • Я построил как минимум один график, демонстрирующий сравнение сценариев.
  • Мой Python-скрипт корректно принимает новый CSV и выдаёт рекомендацию.
  • Отчёт report.md содержит все обязательные разделы и читаем без дополнительных пояснений.