Exportaciones múltiples y grandes descargas
1) Cuando se necesitan exportaciones «grandes» y lo que es importante
Escenarios: informes financieros, descarga de actividad de usuario, auditorías/reguladores, descargas BI, directorios de afiliados, copias de seguridad. Requisitos clave:- Consistencia de datos (snapshot/punto en el tiempo).
- Permeabilidad por volumen (escritura/lectura paralela, serialización en streaming).
- Renovabilidad (resumable) y entrega parcial.
- Integridad (checksum) y verificabilidad (manifiesto).
- Seguridad/PII (enmascaramiento, cifrado, control de acceso).
- Gestión de costos (compresión, tiempos de espera, CDN, TTL).
2) Formatos de datos: pros/contras
CSV - compacto, rápido para escribir/leer; contras: blindaje, tipos perdidos. Bueno para los informes tabulares.
JSON Lines (JSONL) - en línea por objeto, conveniente para streaming y muestreo parcial; contras: volumen.
Parquet/Avro: formatos de columna/esquema, compresión y predicate pushdown; ideal para análisis y big data.
Mixed: JSONL para descargas API → conversiones offline a Parquet.
Compresión: 'gzip '/' zstd' (mejor). Para volúmenes muy grandes - archivos divididos (~ 128-512 MB por pieza).
3) Coherencia: cómo obtener una «instantánea»
DB: aislamiento transaccional READ/SNAPSHOT REPEATABLE; para hilos: ranuras lógicas de replicación o marca 'watermark' (max. 'updated _ at '/versión).
Event sourcing: exportar por offset de registro.
Cortes: exportación «completa» + «delta» (subsiguientes descargas de cambios desde 'watermark').
4) Partición en piezas (multipart/chunking)
4. 1 Especies «multipart»
Upload (a nosotros): multipart/form-data (archivos pequeños), S3 Multipart Upload (MPU )/GCS Resumable (grandes).
Descargar (de nosotros): Rango HTTP ('bytes = start-end'),' multipart/byteranges '(múltiples rangos en una sola respuesta),' zip of parts', directorios en el sitor de objetos.
4. 2 Estrategias de partición
Por tamaño (por ejemplo, 256 MB por pieza).
Por clave/fecha (charding por 'tenant _ id', 'YYYY/MM/DD').
Por tabla/entidad (ficheros individuales por tipo).
Balance: las partes de 64-512 MB se descargan bien en paralelo y no sobrecalientan la memoria.
5) Arquitectura API de exportación (modelo asíncrono)
Pasos:1. 'POST/exports' → trabajo en cola (metadatos: formato, filtros, cifrado, vida útil).
2. Los trabajadores construyen snapshot, redimensionan los datos y escriben partes en el almacén de objetos.
3. Generan un manifiesto (JSON) con una lista de partes, tamaños, checksum, una versión del esquema.
4. 'GET/exports/{ id}' devuelve el estado y la referencia (s) a las partes/URL pre-señalizadas.
5. `GET /exports/{id}/manifest. json '- máquina de la verdad para la verificación/dosificación.
Ejemplo de manifiesto: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) Descargas renovables (resumable)
Rango HTTP: el cliente carga la «cola» del archivo: 'Range: bytes = 241172480-'.
Varios rangos: 'Range: bytes = 0-999,2000-2999' → la respuesta 'Content-Type: multipart/byteranges'.
Estrategia del cliente: «workers» paralelos por pieza, verificación de 'sha256' de cada uno, retrés con backoff exponencial.
CDN: soporte para Range, amortiguación desactivada de grandes respuestas.
7) Grandes descargas a nosotros (upload resumable)
S3 Multipart Upload: los clientes cargan partes (5-5000), el servidor recopila 'CompleteMultipartUpload'.
GCS Resumable: una sesión, desplazamientos - el cliente puede continuar con 'Content-Range'.
TUS (protocolo) es un apload renovable independiente sobre HTTP.
Patrón B2B: damos la URL pre-señalizada para las piezas apload directamente en el sistema, y los metadatos en nuestra API.
8) Compresión, cifrado, integridad
Compresión: 'zstd' es preferible (mejor ratio/velocidad). Comprimir cada pieza por separado (es más conveniente reanudar/almacenar en caché).
Cifrado:- En el cable: TLS 1. 2+.
- En reposo: server-side KMS (SSE-KMS) o client-side (AES-256-GCM) con envoltura de clave (key wrapping).
- Nunca ponga la llave «cruda» en el manifiesto.
- Checksum: mínimo de SHA-256 por pieza + total para todo el conjunto. Compruebe en el cliente antes de ack.
9) Integración perimetral: NGINX/CDN
NGINX (Range + temporizadores grandes + desactivar búfer):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;
}
}
Encabezados de respuesta:
- `Content-Disposition: attachment; filename="export_2025-10-31_part-00000. parquet. zst"`
- 'ETag '/' If-Range' para una correcta dosificación.
- 'Cache-Control' (por ejemplo, 'private, max-age = 3600') para descargas personales.
10) Seguridad y cumplimiento
Autenticación/autorización: emisión de exportaciones sólo al propietario/roles; enlaces de tiempo (pre-signed) con TTL corto.
PII: enmascaramiento/seudonimización; Sólo los campos técnicos están en el manifiesto.
GDPR/reguladores locales: eliminación de exportaciones por TTL, auditoría de descargas, prohibición de emisión regional cruzada sin fundamento.
Rate limiting & quotas: limitar el número de exportaciones simultáneas y el volumen total por día/mes (per-tenant).
Anti-scraping: filtros SAR/bot en la emisión de enlaces, limitación de rangos (máx. partes paralelas).
11) Observabilidad y explotación
Métricas:- `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`
- Quién creó la exportación, filtros, watermark, lista de descargas (IP/UA/hora).
- Hashes de las piezas y la conciliación en el lado del cliente (confirmación).
- Dormir en etapas: snapshot → serialize → upload part → finalize.
12) Rendimiento y costo
Paralelismo: genera varias partes al mismo tiempo (N workers), pero limita I/O.
Memoria: serialización en streaming (iteradores, cursores DB, chancas de 4-16 MB).
Dedoop: para las exportaciones a menudo repetidas, cache inteligente de partes por filtros/hash.
CDN: beneficioso para los conjuntos públicos «compartidos»; para personal - precaución (seguridad/PII).
13) Ejemplos de interfaces
13. 1 Creación de una exportación
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"}
}
Respuesta:
json
{
"id":"exp_2025_10_31_001",
"status":"queued",
"estimated_parts": 12,
"manifest_url": "/exports/exp_2025_10_31_001/manifest. json"
}
13. 2 Entrega de piezas con Range
http
GET /exports/exp_.../part-00003. parquet. zst
Range: bytes=1048576-
13. 3 Pseudocódigo del worker
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) Patrones de exportación delta
Exportación completa una vez a la N (día/semana) + delta cada hora por 'updated _ at> watermark'.
En el lado del consumidor: aplicar delta en orden verificando 'version '/' seq'.
Guarda el último watermark en el consumidor y en el manifiesto.
15) Anti-patrones
Generación de exportaciones en una consulta (sincronizada): tiempos de espera y OOM.
Un archivo gigante sin partición es la imposibilidad de reiniciar/inyectar en paralelo.
La ausencia de un checksum y un manifiesto - no se puede probar la integridad.
Emisión de enlaces públicos permanentes a datos personales.
Amortiguación de SSE/CDN o Range desconectado: rompe el «dosificación».
Exportación de datos «sucios» (sin snapshot/aislamiento).
16) Lista de verificación de implementación
- Formato y compresión: CSV/JSONL/Parquet + 'zstd/gzip'.
- Consistencia: snapshot transaccional o watermark/offset.
- Partición: partes de 64-512 MB, generación y descarga paralelas.
- Manifiesto: lista de partes, dimensiones, SHA-256, versión del esquema, watermark.
- Reanudación: Range HTTP, soporte para 'multipart/byteranges', retrés de clientes.
- Seguridad: URLs presignados, TTL, cifrado (KMS/AEAD), enmascaramiento PII.
- Límites/cuotas: per-tenant, volúmenes diarios, número de job activos.
- Observabilidad: métricas job/partes, auditorías de descargas, alertas en checksum-fail.
- Costo: CDN para kits públicos, TTL y auto-cleanup en el setor.
- Runbooks/Game Days: acantilados de la red, inaccesibilidad del sor, sobrecalentamiento de la DB, fallo de KMS.
17) Game Days (playbucks)
Interrupción de la red al descargar: el cliente debe continuar con 'Range'.
Falla al cargar una parte: retira la parte sin volver a crear toda la exportación.
La caída del worker: el joba se reanuda con el último chunk no confirmado.
KMS no está disponible: degradación segura (pausa de generación, no liberar sin cifrar).
Crecimiento de los datos × 2: comprobar el tiempo de generación, redistribuir el paralelismo, no matar la DB.
18) Resultados
Las descargas grandes confiables son arquitectura asíncrona + partición + reanudación + integridad verificable. Haga snapshot, escriba partes en paralelo, publique un manifiesto con checksum, mantenga el rango HTTP y enlaces de vida corta. Piense en la seguridad, los límites y la observabilidad - y las exportaciones gigabytes dejarán de ser una pesadilla nocturna para los equipos y los usuarios.