MLOps Path

6.3.3 · блок 6

Ограничения Spark и когда не использовать

Ограничения Spark и когда не использовать

Зачем это нужно

Spark мощный, но не универсальный. Команды иногда «тащат Spark везде» — и получают медленный inference, дорогой кластер и сложный ops. MLOps-инженер должен уметь сказать: «здесь Spark — да, здесь — pandas/DuckDB/Kafka Streams/GPU job».

Этот урок — про границы применимости и типичные ошибки, чтобы вы не строили архитектуру против инструмента.

Основные идеи

Spark силён когда:

Spark слаб / избыточен когда:

| Сценарий | Лучшая альтернатива | Почему |

|----------|---------------------|--------|

| 1 GB CSV для учебного проекта | pandas, polars, DuckDB | Overhead cluster > benefit |

| p99 latency 50 ms online scoring | Dedicated inference server (Triton, MLServer) | Spark latency + JVM warmup |

| Deep learning train на GPU | PyTorch/JAX native, Horovod | Spark MLlib DL limited |

| Complex event processing ms-level | Flink, Kafka Streams | Spark micro-batch seconds+ |

| Ad-hoc SQL аналитика | Trino, ClickHouse | Interactive faster |

Latency floor. Structured Streaming micro-batch — обычно секунды, не миллисекунды. Для sub-second features — Flink или custom consumer.

Operational cost. Spark cluster = driver + N executors + shuffle storage + monitoring. На маленьких данных один fat Pod с polars часто дешевле и проще в K8s.

Python UDF penalty. Row-at-a-time Python UDF ломает vectorization Catalyst — медленно. Prefer Spark SQL functions, pandas UDF (vectorized), или pre-process outside Spark.

Small file problem. Spark пишет много part-000xx.parquet. Чтение миллионов files убивает performance. Нужен periodic compaction job (coalesce / repartition before write).

Skew и stragglers. Hot key в groupBy → один task обрабатывает 80% data. Salting, adaptive skew join (Spark 3.x) — но debugging сложный для новичков.

State in Spark Streaming. Stateful aggregations (windows) требуют checkpoint на durable storage. Потеря checkpoint = tricky recovery. Ops burden выше, чем у stateless batch.

ML model format friction. Spark MLlib Pipeline ≠ sklearn ≠ ONNX. Конвертация — extra step. Многие команды: Spark только до train export; serving — другой stack (модуль 7).

Decision matrix (упрощённая).


Размер данных < 10 GB и команда маленькая?  → pandas/polars
Нужен online REST inference?                 → KServe/Triton, не Spark
Batch scoring 100M rows nightly?             → Spark или SQL warehouse + export
Streaming features < 1s?                     → Flink/Kafka consumer
Streaming features 10s–1min OK?              → Spark Structured Streaming

Когда Spark + ML всё же правильный выбор. Единая платформа data engineering уже на Spark; feature jobs 500M+ rows; batch scoring в DWH integration; команда имеет Spark SRE expertise.

Как это выглядит на практике

Case study A — ошибка. Команда сделала REST API поверх Spark job, который collect() score для одного user — cold start 30s, p95 8s. Fix: precomputed features in Redis + LightGBM in MLServer.

Case study B — правильно. Nightly 80M users batch churn scores → Spark writes to scores_daily table → CRM reads via SQL. Latency не критична; Spark parallelizes predict UDF (still watch UDF cost).

Case study C — компромисс. Spark готовит features; train на sampled 5M rows на GPU node; serving ONNX on Triton. Каждый инструмент — на своём этапе.

ADR trigger (см. 6.4.3). Если спор «нужен ли Spark для feature job» — фиксируйте: data volume, SLA, team skills, existing infra.

Что сделать после занятия

Официальные материалы

Открыть интерактивную версию