Tema representativo de entrevista

Entrevista de Backend: Diseñar una API de Carga Multiparte Reanudable con Verificaciones de Integridad

BackendDifícil
Equipo editorial de Offer.ccPublicado Actualizado

Pregunta

Diseña una API para cargas reanudables de archivos grandes. Los clientes pueden perder la conectividad, cargar una parte dos veces o enviar solicitudes de forma concurrente; el sistema debe verificar la integridad, evitar partes huérfanas y devolver una versión de objeto estable después de la finalización.

Planteamiento y contexto

Un cliente necesita cargar un archivo de varios gigabytes a través de una red inestable. Un cliente móvil puede reintentar o enviar de manera concurrente la misma parte. El servicio debe exponer el progreso, permitir el reintento de partes faltantes y demostrar la integridad del contenido antes y después de la finalización. La entrevista se centra en el estado del protocolo, la idempotencia, las sumas de verificación, el ciclo de vida y la visibilidad del objeto.

Lo que el entrevistador está evaluando

El entrevistador quiere ver una solicitud grande descompuesta en una sesión recuperable. Google Cloud define las cargas reanudables como solicitudes múltiples que pueden continuar después de un fallo de comunicación; la carga multiparte de Amazon S3 requiere primero las partes y una llamada explícita de finalización antes de ensamblar un objeto, y recomienda la limpieza del ciclo de vida para cargas incompletas. Una respuesta sólida también cubre la autorización, los límites de tasa (rate limits) y la semántica de finalización duplicada.

Preguntas de clarificación para hacer primero

Aclara el tamaño del objeto, el tamaño de las partes y los límites de concurrencia; si el cliente puede retener una URL de sesión; si los objetos pueden sobrescribirse o tener versiones; si el cliente proporciona un resumen (digest) del archivo completo o el servicio calcula uno; y las políticas de retención de sesión, cancelación, abuso y cuota de inquilinos (tenant). Una URL prefirmada no conlleva automáticamente la autorización del negocio.

Un marco de respuesta de 30 segundos

Di: “Expondría operaciones de creación de sesión, carga de partes, estado, finalización y cancelación. La sesión vincula el inquilino, la clave del objeto, el tamaño, las reglas de partes, la expiración y la política de sumas de verificación. Cada parte es idempotente mediante (uploadId, partNumber, checksum). La finalización verifica las partes consecutivas y el resumen del objeto completo, y luego publica atómicamente una versión del objeto. Un worker limpia las sesiones expiradas; la autorización, la cuota y los límites de tasa se verifican en la creación y en cada solicitud de parte”.

Análisis profundo paso a paso

1. Crear y autorizar la sesión de carga

POST /uploads verifica la cuota del inquilino, el tamaño del objeto, el tipo de contenido y el permiso de destino, y luego devuelve un uploadId aleatorio, el tamaño de parte, la expiración y credenciales de carga de alcance limitado. La sesión registra el tamaño esperado, la clave del objeto, la política de versiones y el algoritmo de suma de verificación; el cliente no puede elegir una ruta de almacenamiento arbitraria.

2. Diseñar partes idempotentes y estado

PUT /uploads/{id}/parts/{n} incluye la longitud de la parte y la suma de verificación. El servicio almacena los metadatos válidos más recientes para uploadId + partNumber; un duplicado con el mismo resumen devuelve éxito, mientras que un resumen diferente devuelve conflicto y solicita al cliente actualizar el estado. GET /uploads/{id} devuelve las partes confirmadas, el tamaño y la siguiente acción sin exponer los datos de otro inquilino.

3. Verificar la integridad de los datos

Valida la longitud y la suma de verificación de la parte en cada carga, luego valida los números de parte consecutivos, la longitud total y el resumen del objeto completo al finalizar. Amazon S3 documenta sumas de verificación de partes o compuestas; una discrepancia debe impedir la publicación. Almacena el algoritmo y la codificación en la sesión para que el cliente y el servicio no interpreten el resumen de manera diferente.

4. Completar y controlar la visibilidad

POST /uploads/{id}/complete incluye una lista ordenada de partes y un resumen opcional del archivo completo. La finalización es idempotente: la misma lista devuelve la misma versión del objeto, mientras que una lista en conflicto es rechazada. Solo después de que el almacenamiento ensambla y verifica el objeto, el registro de la base de datos pasa de UPLOADING a READY; las lecturas nunca exponen un objeto parcial.

5. Cancelar, expirar y limpiar partes huérfanas

El cliente puede cancelar explícitamente. Un worker escanea las sesiones expiradas, llama a la operación de anulación del almacenamiento y elimina las partes cargadas. La limpieza es en sí misma idempotente y reintentable, registrando el último error y las métricas de costo. S3 señala que las partes incompletas generan cargos de almacenamiento, por lo que una regla de ciclo de vida es una red de seguridad final, no un reemplazo del estado de la aplicación.

6. Agregar seguridad, cuotas y observabilidad

Cada operación verifica el inquilino, el permiso del objeto, el estado de la sesión y el rango de la parte. Las credenciales están limitadas a la sesión actual y expiran rápidamente. Limita las sesiones activas, los bytes totales y el tamaño de parte por inquilino. Monitorea el éxito de la sesión, los reintentos, los fallos de suma de verificación, el retraso de limpieza y los bytes huérfanos, con alertas aisladas por inquilino.

Respuesta de muestra de alta calidad

“Crearía una sesión con POST /uploads, validaría la cuota del inquilino y el tamaño del objeto, y emitiría un uploadId aleatorio, un tamaño de parte fijo, el algoritmo de suma de verificación y una expiración de 24 horas. Cada parte incluye su número, longitud y resumen; (uploadId, partNumber) es la clave de idempotencia. Un duplicado con el mismo resumen devuelve el resultado existente, mientras que un resumen diferente es rechazado. El cliente utiliza el endpoint de estado para encontrar las partes faltantes. La finalización proporciona una lista ordenada y el resumen del archivo completo; el servicio verifica la numeración, la longitud total y las sumas de verificación de las partes, y luego llama a la operación de finalización del almacenamiento de objetos. Solo después de que el ensamblaje tiene éxito, marca el objeto como READY. La finalización repetida devuelve la misma versión; una lista en conflicto no cambia nada. Los workers de cancelación y expiración anulan las cargas incompletas con reintentos, evitando cargos por almacenamiento huérfano. Las credenciales están delimitadas por inquilino y sesión, y las rutas de creación, partes y finalización aplican cuota, autorización, límites de tasa y auditoría”.

Errores comunes y mejoras

  • Hacer de la carga una sola solicitud larga: Usa una sesión y partes para que un fallo de red solo afecte los datos faltantes.
  • Rastrear únicamente los bytes cargados: Rastrea el número de parte, el resumen y la versión para evitar reemplazos duplicados o fuera de orden.
  • Marcar éxito antes de la finalización: Ensambla y verifica primero en el almacenamiento, luego publica el objeto READY.
  • Ignorar el costo de las partes expiradas: Proporciona cancelación, anulación en segundo plano y limpieza del ciclo de vida del almacenamiento de manera conjunta.

Preguntas de seguimiento y respuestas

¿Qué sucede si el cliente carga la misma parte de forma concurrente?

Serializa las actualizaciones de metadatos por sesión y número de parte o utiliza una escritura condicional. Los duplicados con el mismo resumen devuelven un éxito idempotente; los resúmenes diferentes devuelven conflicto, y el cliente actualiza el estado antes de reintentar.

¿Qué sucede si la finalización agota el tiempo de espera (timeout) después de que el almacenamiento realmente terminó?

Persiste una clave de idempotencia de finalización y la versión de destino. En el reintento, consulta primero el almacenamiento y el estado local. Si la lista coincide con una versión completada, devuelve esa versión; si hay incertidumbre, mantén COMPLETING y deja que un worker reconcilie en lugar de ensamblar a ciegas.

¿Cómo evitas que un cliente abusivo llene el almacenamiento?

Reserva cuota al crear la sesión y limita las sesiones activas, los bytes totales de partes, la concurrencia y la expiración por inquilino. Vincula las credenciales de partes a la sesión y al rango, anula las sesiones expiradas con prontitud y genera alertas sobre tasas de reintento anormales.

¿Deberían ser sobrescribibles los objetos con la misma clave?

Establece por defecto una nueva versión o una escritura condicional. Si se requiere sobrescribir, acepta una versión de destino o una condición If-Match y actualiza la referencia de forma atómica tras la finalización, para que una carga lenta no pueda sobrescribir un objeto más nuevo.

Fuentes públicas

Preguntas relacionadas