Tema representativo de entrevista

Entrevista de diseño de sistemas: ¿Cómo aislar la concurrencia de dependencias para evitar la sobrecarga en cascada?

Diseño de sistemasDifícil
Equipo editorial de Offer.ccPublicado Actualizado

Pregunta

Un servicio normalmente tarda 10 ms por llamada downstream, pero una dependencia de repente tarda 1 segundo, agotando thread pools, connection pools y colas. Diseña el aislamiento de concurrencia a nivel de dependencia y explica cuotas duras/blandas, timeouts, rechazo, degradación, recuperación y validación.

Planteamiento y contexto

Un servicio llama a una base de datos, un proveedor de pagos y un sistema de recomendaciones. Las recomendaciones se ralentizan de 10 ms a 1 segundo. Las solicitudes en vuelo crecen hasta que se consumen los subprocesos y las conexiones, y las API que no necesitan recomendaciones también fallan. Diseña bulkheads para que la dependencia lenta afecte únicamente a la funcionalidad relacionada.

La AWS Builders’ Library describe esto como sobrecarga de concurrencia impulsada por latencia: un timeout no es un límite de concurrencia. Los recursos deben aislarse alrededor de cada dependencia o cliente, protegiendo tanto el servicio como los sistemas downstream.

Qué evalúa el entrevistador

  • Explicas la intuición de la Ley de Little de que un mayor tiempo de servicio aumenta el trabajo en vuelo con la misma tasa de llegada.
  • Asignas concurrencia por dependencia, API, tenant o grupo de recursos para que una dependencia lenta no pueda consumir la capacidad global.
  • Comparas cuotas duras, blandas y dinámicas junto con sus compensaciones de equidad y utilización.
  • Diseñas rechazo rápido, degradación, deadlines, comportamiento de circuitos, recuperación y observabilidad.
  • Demuestras que las API no relacionadas se mantienen saludables sin colas ilimitadas ni inanición de recursos.

Preguntas para aclarar primero

  • ¿Qué API llaman a recomendaciones y cuáles son críticas? ¿Puede alguna ruta degradarse?
  • ¿Cuáles son los límites de subprocesos, conexiones, memoria y colas, y la distribución actual de concurrencia?
  • ¿La dependencia admite cancelación, idempotencia, procesamiento por lotes o almacenamiento en caché? ¿Cómo se propaga el deadline del llamador?
  • ¿El presupuesto está aislado por API, dependencia, tenant o Availability Zone? ¿Se requiere préstamo de capacidad?
  • ¿Qué experiencia de usuario, contrato de error y objetivo de recuperación aplican durante una falla?

Una respuesta de 30 segundos

“Creo un bulkhead de concurrencia delimitado y una cola por dependencia, con pools separados para API críticas y degradables. Las solicitudes llevan un deadline; el trabajo que excede el presupuesto falla rápido o sirve caché en lugar de esperar indefinidamente. Utilizo cuotas blandas para la utilización, pero límites globales y por clase estrictos, con préstamos delimitados. Las métricas cubren trabajo en vuelo, rechazos, espera, timeout, degradación y recuperación por dependencia y API. Una prueba de dependencia lenta debe dejar intactas las API no relacionadas.”

Solución paso a paso

Paso 1: Cuantificar la concurrencia impulsada por la latencia

Mide la tasa de llegada, el tiempo de servicio, las solicitudes en vuelo y los timeouts por dependencia. Si el tiempo de servicio aumenta de 10 ms a 1 s, el trabajo en vuelo puede crecer aproximadamente 100 veces con la misma tasa de llegada. Encuentra los recursos restringidos antes de dimensionar los bulkheads.

Paso 2: Particionar los pools de recursos

Otorga a cada dependencia su propio connection pool, semáforo y cola delimitada; divide las API críticas y degradables para la misma dependencia. Verifica que el aislamiento sea real: los subprocesos, las conexiones y el estado no deben permanecer compartidos detrás de contadores separados.

Paso 3: Elegir cuotas duras, blandas y dinámicas

Las cuotas duras protegen una API pero desperdician capacidad ante desequilibrios de carga. Las cuotas blandas toman prestada capacidad ociosa bajo un límite global. Las cuotas dinámicas se adaptan a la carga pero requieren garantías mínimas, límites máximos y una tasa de cambio segura. Agrega particiones por tenant cuando la equidad sea importante.

text
global_limit = 500
payments = hard 150
recommendations = soft 200, borrow <= 100
other_apis = reserved 50

Paso 4: Rechazar y degradar deliberadamente

Si no hay permisos disponibles, devuelve un error explícito o el resultado de caché en lugar de entrar en una cola ilimitada. Respeta el deadline del llamador y cancela el trabajo que pueda cancelarse. Los reintentos necesitan un presupuesto, backoff e idempotencia; las escrituras críticas no deben degradarse silenciosamente.

Paso 5: Recuperar sin oscilaciones

Tras la recuperación, aumenta los permisos gradualmente y utiliza sondeos semiabiertos para evitar ráfagas. Conserva series temporales de rechazos, timeouts y marcas de nivel de cola, segmentadas por dependencia, API, tenant y celda. Versiona la configuración y mantén mecanismos de reversión.

Paso 6: Verificar el límite de aislamiento

Inyecta latencia, errores y agotamiento de conexiones en una dependencia. Observa los rechazos de recomendaciones, el éxito de pagos, el uso global de subprocesos/conexiones y la latencia de cola. Prueba ráfagas, asimetría de tenants, cambios de configuración y fallas de celdas; los SLO de las API no relacionadas y los límites de las colas son criterios de aceptación.

Una respuesta de ejemplo sólida

“Utilizo la tasa de llegada, el tiempo de servicio y el trabajo en vuelo para mostrar por qué una dependencia de recomendación lenta multiplica la concurrencia. Cada dependencia tiene su propio semáforo, pool y cola delimitada; las API críticas y degradables están separadas. Los pagos reciben una reserva estricta; las recomendaciones usan una cuota blanda con préstamo delimitado. Cada llamada propaga un deadline y falla rápido o devuelve la caché cuando los permisos se agotan.”

“La recuperación utiliza sondeos semiabiertos e incrementos graduales de permisos. Las métricas incluyen trabajo en vuelo, rechazos, espera, timeouts, impactos de degradación, errores downstream y tiempo de recuperación. Un simulacro ralentiza solo las recomendaciones y comprueba que las colas de latencia, pools y subprocesos de pagos y API no relacionadas permanezcan dentro de los límites.”

Errores comunes

  • Solo aumentar los timeouts → el trabajo en vuelo crece → establece límites de concurrencia a nivel de dependencia.
  • Compartir un solo pool de subprocesos y conexiones → una dependencia lenta derriba el servicio → particiona por dependencia y criticidad.
  • Usar una cola ilimitada → la memoria y la latencia se disparan → delimítala y rechaza rápido.
  • Cuotas duras estáticas en todas partes → el desequilibrio de tráfico deja capacidad ociosa → permite préstamos blandos delimitados.
  • Reintentar sin presupuesto → la sobrecarga downstream se amplifica → propaga deadlines, limita los intentos y exige idempotencia.
  • Probar solo la dependencia fallida → el aislamiento queda sin demostrar → verifica simultáneamente los SLO de las API no relacionadas.

Preguntas de seguimiento y respuestas

¿Por qué un timeout no es un límite de concurrencia?

Delimita una sola espera, pero la solicitud en espera sigue ocupando un subproceso, una conexión y memoria. Una mayor latencia en la dependencia coloca más solicitudes en vuelo, por lo que los permisos deben estar delimitados.

¿Cómo evita el préstamo blando que una sola API consuma todo?

Usa un tope global, reserva mínima por API, préstamo máximo y tasa de recuperación de recursos. Una vez que quien pide prestado alcanza su límite, falla rápido en lugar de crecer indefinidamente.

¿Cuándo es seguro devolver datos en caché?

Para lecturas donde una obsolescencia delimitada es aceptable, devuelve un valor en caché con marca de tiempo. Los resultados de pagos, autorizaciones y escrituras no pueden reemplazarse silenciosamente por datos obsoletos.

¿Cómo demuestras que el aislamiento funciona?

Inyecta lentitud y errores en una dependencia, luego inspecciona el trabajo en vuelo, las colas de latencia, el uso de subprocesos/conexiones y el éxito de las API no relacionadas. La degradación sincrónica significa que aún existe un recurso compartido o un límite de cola no aislado.

Fuentes públicas

Preguntas relacionadas

Herramienta de entrevista relacionada

Usa Resolver para una respuesta de diseño de sistemas

Aclara primero los requisitos y luego avanza a través de la escala, la arquitectura, la elección de componentes y las compensaciones (trade-offs).

Ver la herramienta