6.3.3 · блок 6
Ограничения Spark и когда не использовать
Ограничения Spark и когда не использовать
Зачем это нужно
Spark мощный, но не универсальный. Команды иногда «тащат Spark везде» — и получают медленный inference, дорогой кластер и сложный ops. MLOps-инженер должен уметь сказать: «здесь Spark — да, здесь — pandas/DuckDB/Kafka Streams/GPU job».
Этот урок — про границы применимости и типичные ошибки, чтобы вы не строили архитектуру против инструмента.
Основные идеи
Spark силён когда:
- Data не помещается в RAM одной машины (десятки GB – PB).
- Нужны распределённые joins/aggregations на кластере.
- Batch pipeline уже на JVM/Hadoop ecosystem.
- Единый код batch + streaming (Structured Streaming).
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.
Что сделать после занятия
- [ ] Для учебного проекта (< 1 GB data) обоснуйте, почему Spark не нужен.
- [ ] Придумайте сценарий, где batch Spark scoring уместен (3 предложения).
- [ ] Заполните decision matrix для вашего capstone: какой объём, какой latency?