GH GambleHub

Multipart-экспорты и большие выгрузки

1) Когда нужны «большие» экспорты и что важно

Сценарии: финансовые отчеты, выгрузка активности пользователей, аудит/регуляторы, BI-выгрузки, партнерские каталоги, резервные копии. Ключевые требования:
  • Согласованность данных (snapshot/точка во времени).
  • Проходимость по объему (параллельная запись/чтение, потоковая сериализация).
  • Возобновляемость (resumable) и частичная доставка.
  • Целостность (checksum) и верифицируемость (манифест).
  • Безопасность/PII (маскирование, шифрование, контроль доступа).
  • Управление стоимостью (компрессия, тайм-ауты, CDN, TTL).

2) Форматы данных: плюсы/минусы

CSV — компактно, быстро писать/читать; минусы: экранирование, типы теряются. Хорошо для табличных отчетов.
JSON Lines (JSONL) — по строке на объект, удобен для стриминга и частичной выборки; минусы: объем.
Parquet/Avro — колоночные/схемные форматы, сжатие и predicate pushdown; идеальны для аналитики и больших данных.
Mixed: JSONL для API-загрузки → оффлайн-конверсия в Parquet.

Компрессия: `gzip`/`zstd` (лучше). Для очень больших объемов — сплит-архивы (по ~128–512 МБ на часть).

3) Согласованность: как получить «снимок»

БД: транзакционная изоляция REPEATABLE READ/SNAPSHOT; для потоков — логические слоты репликации или отметка `watermark` (макс. `updated_at`/версия).
Event sourcing: экспорт по offset журнала.
Срезы: «полный» экспорт + «дельты» (последующие выгрузки изменений с момента `watermark`).

4) Разбиение на части (multipart/chunking)

4.1 Виды «multipart»

Upload (к нам): multipart/form-data (мелкие файлы), S3 Multipart Upload (MPU) / GCS Resumable (крупные).
Download (от нас): HTTP Range (`bytes=start-end`), `multipart/byteranges` (несколько диапазонов в одном ответе), «zip of parts», каталоги в объектном сторе.

4.2 Стратегии разбиения

По размеру (например, 256 МБ на часть).
По ключу/дате (шардирование по `tenant_id`, `YYYY/MM/DD`).
По таблице/сущности (отдельные файлы на типы).

Баланс: части 64–512 МБ хорошо скачиваются параллельно и не перегревают память.

5) API-архитектура экспорта (асинхронная модель)

Шаги:

1. `POST /exports` → задание в очереди (метаданные: формат, фильтры, шифрование, срок жизни).

2. Воркеры строят snapshot, стримят данные и пишут части в объектное хранилище.

3. Генерируют манифест (JSON) с перечнем частей, размерами, checksum, версией схемы.

4. `GET /exports/{id}` возвращает статус и ссылку(и) на части / pre-signed URL.

5. `GET /exports/{id}/manifest.json` — машина правды для верификации/дозагрузки.

Пример манифеста:
json
{
"export_id": "exp_2025_10_31_001",
"created_at": "2025-10-31T14:23:00Z",
"schema": "orders_v3",
"format": "parquet+zstd",
"parts": [
{"name":"part-00000. parquet. zst","size":268435456,"sha256":"...","url":"...","range":"bytes=0-268435455"},
{"name":"part-00001. parquet. zst","size":241172480,"sha256":"...","url":"..."}
],
"total_bytes": 509607936,
"encryption": {"type":"AES-256-GCM","key_id":"kms/keys/exp"},
"watermark": {"type":"updated_at","value":"2025-10-31T00:00:00Z"}
}

6) Возобновляемые выгрузки (resumable)

HTTP Range: клиент догружает «хвост» файла: `Range: bytes=241172480-`.
Несколько диапазонов: `Range: bytes=0-999,2000-2999` → ответ `Content-Type: multipart/byteranges`.
Клиентская стратегия: параллельные «воркеры» на части, верификация `sha256` каждой, ретраи с экспоненциальным backoff.
CDN: поддержка Range, выключенная буферизация больших ответов.

7) Большие загрузки к нам (resumable upload)

S3 Multipart Upload: клиенты загружают части (5–5000), сервер собирает `CompleteMultipartUpload`.
GCS Resumable: один сеанс, смещения — клиент может продолжать с `Content-Range`.
TUS (протокол) — независимый возобновляемый аплоад поверх HTTP.

Паттерн B2B: отдаем pre-signed URL для аплоада частей напрямую в стор, а метаданные — в наш API.

8) Компрессия, шифрование, целостность

Компрессия: `zstd` предпочтителен (лучше ratio/скорость). Сжимайте каждую часть отдельно (удобнее возобновлять/кэшировать).

Шифрование:
  • На проводе: TLS 1.2+.
  • В покое: server-side KMS (SSE-KMS) или client-side (AES-256-GCM) с оберткой ключа (key wrapping).
  • Никогда не кладите «сырой» ключ в манифест.
  • Checksum: минимум SHA-256 на часть + общий для всего набора. Проверяйте на клиенте перед ack.

9) Интеграция с периметром: NGINX/CDN

NGINX (Range + большие таймауты + отключить буферизацию):
nginx server {
listen 443 ssl http2;
server_name downloads. example. com;

location /exports/ {
proxy_buffering off;
proxy_request_buffering off;
proxy_read_timeout 3600s;
add_header Accept-Ranges bytes;
proxy_pass http://export-backend;
}
}
Заголовки ответов:
  • `Content-Disposition: attachment; filename="export_2025-10-31_part-00000.parquet.zst"`
  • `ETag`/`If-Range` для корректной догрузки.
  • `Cache-Control` (например, `private, max-age=3600`) для персональных выгрузок.

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

Аутентификация/авторизация: выдача экспортов только владельцу/ролям; временные ссылки (pre-signed) с коротким TTL.
PII: маскирование/псевдонимизация; в манифесте — только технические поля.
GDPR/локальные регуляторы: удаление экспортов по TTL, аудит скачиваний, запрет кросс-региональной выдачи без основания.
Rate limiting & quotas: ограничить количество одновременных экспортов и общий объем в сутки/месяц (per-tenant).
Анти-скрапинг: CAP/бот-фильтры на выдачу ссылок, ограничение диапазонов (макс. параллельных частей).

11) Наблюдаемость и эксплуатация

Метрики:
  • `export_jobs_total{status}` (queued/running/succeeded/failed/expired)
  • `export_bytes_total`, `export_part_duration_ms{p50,p95,p99}`
  • `download_range_requests_total`, `resumes_total`, `checksum_fail_total`
  • `storage_cost_estimate` и `egress_bytes_cdn`
Логи/аудит:
  • Кто создал экспорт, фильтры, watermark, список скачиваний (IP/UA/время).
  • Хеши частей и сверка на стороне клиента (подтверждения).
Трейсинг:
  • Спаны на этапы: snapshot → serialize → upload part → finalize.

12) Производительность и стоимость

Параллельность: генерируйте несколько частей одновременно (N воркеров), но лимитируйте I/O.
Память: потоковая сериализация (итераторы, курсоры БД, чанки по 4–16 МБ).
Дедуп: для часто повторяющихся экспортов умный cache of parts по фильтрам/хешу.
CDN: выгодно для «общих» публичных наборов; для персональных — осторожно (безопасность/PII).

13) Примеры интерфейсов

13.1 Создание экспорта (REST)

http
POST /exports
Content-Type: application/json
Authorization: Bearer <token>

{
"format": "parquet+zstd",
"filters": {"date_from":"2025-10-01","date_to":"2025-10-31","tenant":"acme"},
"split_size_mb": 256,
"encryption": {"mode":"server-side-kms","key_id":"kms/keys/exp"}
}
Ответ:
json
{
"id":"exp_2025_10_31_001",
"status":"queued",
"estimated_parts": 12,
"manifest_url": "/exports/exp_2025_10_31_001/manifest. json"
}

13.2 Выдача части с Range

http
GET /exports/exp_.../part-00003. parquet. zst
Range: bytes=1048576-

13.3 Псевдокод воркера

pseudo snapshot = db. begin_snapshot()
for shard in plan_shards(snapshot):
part_stream = encode_stream(shard. rows, format="parquet", compress="zstd")
url = object_store. upload_stream(part_stream, part_name, encryption=KMS)
manifest. add(part_name, size, sha256, url)
write_manifest(manifest)

14) Паттерны дельта-экспортов

Полный экспорт раз в N (день/неделя) + дельты каждый час по `updated_at > watermark`.
На стороне потребителя: применить дельты по порядку, верифицируя `version`/`seq`.
Храните последний watermark в потребителе и в манифесте.

15) Анти-паттерны

Генерация экспорта в запросе (синхронно) — таймауты и OOM.
Один гигантский файл без разбиения — невозможность возобновления/параллельной закачки.
Отсутствие checksum и манифеста — нельзя доказать целостность.
Выдача постоянных публичных ссылок на персональные данные.
Буферизация SSE/CDN или отключенные Range — ломает «дозагрузку».
Экспорт «грязных» данных (без snapshot/изоляции).

16) Чек-лист внедрения

  • Формат и компрессия: CSV/JSONL/Parquet + `zstd/gzip`.
  • Согласованность: транзакционный snapshot или watermark/offset.
  • Разбиение: части 64–512 МБ, параллельная генерация и скачивание.
  • Манифест: список частей, размеры, SHA-256, версия схемы, watermark.
  • Возобновление: HTTP Range, поддержка `multipart/byteranges`, клиентские ретраи.
  • Безопасность: pre-signed URLs, TTL, шифрование (KMS/AEAD), маскирование PII.
  • Лимиты/квоты: per-tenant, суточные объемы, число активных джоб.
  • Наблюдаемость: метрики джоб/частей, аудит скачиваний, алерты на checksum-fail.
  • Стоимость: CDN для публичных наборов, TTL и авто-cleanup в сторе.
  • Runbooks/Game Days: обрывы сети, недоступность стора, перегрев БД, сбой KMS.

17) Game Days (плейбуки)

Обрыв сети при скачивании: клиент должен продолжить с `Range`.
Сбой загрузки одной части: ретрай части без пересоздания всего экспорта.
Падение воркера: джоба возобновляется с последнего неподтвержденного чанка.
Недоступен KMS: безопасная деградация (пауза генерации, не выпускать незашифровано).
Рост данных ×2: проверить время генерации, перераспределить параллелизм, не убить БД.

18) Итоги

Надежные большие выгрузки — это асинхронная архитектура + разбиение на части + возобновление + проверяемая целостность. Делайте snapshot, пишите части параллельно, публикуйте манифест с checksum, поддерживайте HTTP Range и короткоживущие ссылки. Продумайте безопасность, лимиты и наблюдаемость — и гигабайтные экспорты перестанут быть ночным кошмаром для команд и пользователей.

Contact

Свяжитесь с нами

Обращайтесь по любым вопросам или за поддержкой.Мы всегда готовы помочь!

Telegram
@Gamble_GC
Начать интеграцию

Email — обязателен. Telegram или WhatsApp — по желанию.

Ваше имя необязательно
Email необязательно
Тема необязательно
Сообщение необязательно
Telegram необязательно
@
Если укажете Telegram — мы ответим и там, в дополнение к Email.
WhatsApp необязательно
Формат: +код страны и номер (например, +380XXXXXXXXX).

Нажимая кнопку, вы соглашаетесь на обработку данных.