Tema representativo de entrevista

Entrevista de diseño de sistemas: ¿cómo diseñarías un limitador de tasa de API multiinquilino?

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

Pregunta

Diseña un limitador de tasa para una plataforma de API multiinquilino: los inquilinos gratuitos obtienen 100 solicitudes por minuto, los de pago obtienen 10,000, y la plataforma se ejecuta en múltiples instancias de aplicación y regiones. Compara algoritmos y explica el estado compartido, las respuestas 429, la degradación ante fallas y la verificación.

Consigna y contexto aplicable

Diseña un limitador de tasa para una plataforma de API multiinquilino: los inquilinos gratuitos obtienen 100 solicitudes por minuto, los de pago obtienen 10,000, y la plataforma se ejecuta en múltiples instancias de aplicación y regiones. Compara algoritmos y explica el estado compartido, las respuestas 429, la degradación ante fallas y la verificación.

Esto encaja en entrevistas de backend, plataforma y diseño de sistemas. Un registro público de entrevistas presenta un problema de codificación de token bucket por usuario con recargas basadas en tiempo; el material de diseño de sistemas trata la limitación de tasa como una discusión estándar de API multiinquilino. La habilidad principal radica en el estado compartido, la política de inquilinos y la protección del tráfico, no en memorizar las configuraciones de un proveedor de nube.

Qué evalúa el entrevistador

  • Si separas la tasa promedio, la capacidad de ráfaga, la equidad entre inquilinos y la protección global.
  • Si puedes explicar los límites y costos de token bucket, ventana fija y ventana deslizante.
  • Si el estado compartido se actualiza atómicamente entre instancias mientras se abordan hot keys, particiones y relojes.
  • Si las respuestas 429, las sugerencias de reintento, la degradación y la telemetría evitan que el limitador se convierta en un punto único de falla.

Preguntas aclaratorias antes de responder

  • ¿El sujeto es una API key, un inquilino, un usuario, una IP o una combinación? ¿Cómo se agrupan las solicitudes anónimas?
  • ¿La política es una tasa promedio, una ventana deslizante estricta o ráfagas controladas? ¿Existe también una cuota diaria?
  • ¿El entorno multirregión requiere una aplicación global exacta, o un breve exceso puede comprar disponibilidad?
  • ¿Las solicitudes rechazadas deben recibir un 429 inmediato o entrar en una cola acotada? ¿Puede la dependencia tolerar ráfagas en absoluto?

Estructura de respuesta de 30 segundos

Pondría una protección básica por IP y no autenticada en el gateway, y luego aplicaría la política consciente de inquilinos en la capa de aplicación. Si la API tolera ráfagas cortas, comenzaría con un token bucket. El bucket de cada inquilino almacena tokens y la última hora de recarga en un estado compartido atómicamente. Las solicitudes que exceden el límite reciben un 429 con una sugerencia de reintento computable. Si no se requiere un conteo global exacto, las cuotas regionales y el monitoreo de excesos globales intercambian un poco de precisión por latencia; las fallas de almacenamiento utilizan una política explícita de fail-open o fail-closed con alertas.

Análisis detallado paso a paso

Definir el presupuesto y la equidad

Cien solicitudes por minuto es el presupuesto a largo plazo del inquilino gratuito, y 10,000 es el del de pago. Ambos también necesitan una capacidad de ráfaga independiente; un solo contador global no puede expresar ninguna de las dos políticas. Una protección global debería limitar el RPS agregado para que un inquilino grande no pueda agotar las conexiones a la base de datos. Una clave de política debe incluir el ID del inquilino, la acción de la API y la versión de la política para que los endpoints no relacionados no compartan asignaciones accidentalmente.

Elegir el algoritmo

AlgoritmoSemántica principalCosto y riesgoBuen ajuste
Token bucketTasa promedio acotada con ráfagas controladasDos valores de estado; la recarga y el consumo deben ser atómicosAPIs de cara al usuario que toleran ráfagas cortas
Fixed windowCuenta solicitudes en periodos fijosUn límite de ventana puede acercarse al doble de la tasa configuradaReglas simples donde la aproximación es aceptable
Sliding window logConteo exacto en la ventana activaAlmacena marcas de tiempo; la memoria y la limpieza son costosasPoblaciones pequeñas que necesitan precisión estricta
Sliding window counterEstimación ponderada de ventanas adyacentesAproximado pero eficiente en memoria; el error debe declararseLímites de equidad a gran escala

AWS API Gateway documenta la regulación (throttling) por token bucket: la tasa de tokens expresa el tráfico en estado estable y la ráfaga expresa la capacidad del bucket. Puede devolver 429, pero los límites son objetivos de mejor esfuerzo más que un techo matemático absoluto. Mantén la intención de la política separada de la garantía de una plataforma.

Invariante del Token-Bucket

El conteo de tokens siempre permanece en [0, capacity]. Al llegar una solicitud, se recarga según el tiempo transcurrido multiplicado por la tasa de recarga, se limita a la capacidad máxima y luego se verifica si hay al menos un token; una solicitud permitida consume uno. Este orden significa que un periodo de inactividad solo se acumula hasta el límite de ráfaga en lugar de crear crédito ilimitado después de un tiempo de inactividad.

~~~text allow(key, now): state = atomicRead(key) elapsed = max(0, now - state.lastRefill) refilled = min(capacity, state.tokens + elapsed * rate) if refilled < 1: atomicWrite(key, refilled, now) return reject(429) atomicWrite(key, refilled - 1, now) return allow ~~~

En producción, el pseudocódigo debe ejecutarse como un solo script de Lua, una transacción o una operación compare-and-swap equivalente. Dos llamadas independientes de lectura y escritura pueden sobrevender tokens bajo concurrencia. Las marcas de tiempo deben provenir de una fuente monotónica confiable; los clientes no deben enviarlas.

Ubicación y estado compartido

El gateway bloquea inundaciones obvias de IP y volumen no autenticado; la capa de aplicación aplica la política de inquilino, usuario o endpoint. Si cada instancia cuenta solo en memoria local, el balanceo de carga permite que un inquilino distribuya llamadas entre instancias y reciba múltiples asignaciones. Un Redis compartido, un almacén clave-valor atómico o una base de datos con escrituras condicionales pueden mantener el estado; la elección depende de la latencia, la precisión y el modelo de fallas.

Las opciones multirregión son explícitas: un almacén global brinda una asignación más exacta con latencia interregional; los buckets regionales independientes son rápidos pero pueden sobrepasarse brevemente; las asignaciones regionales más una protección global se sitúan entre ambos. Pregunta si la precisión importa más que la disponibilidad antes de afirmar un límite estricto global.

Rechazo, degradación y telemetría

Devuelve 429 con encabezados Retry-After o de cuota restante. Los clientes deben utilizar un retroceso acotado (bounded backoff) en lugar de reintentar de inmediato en un bucle de retroalimentación. Si el almacenamiento del limitador falla, las escrituras de alto riesgo comúnmente aplican fail-closed o entran en una cola acotada; las lecturas de bajo riesgo pueden aplicar fail-open brevemente, pero necesitan un disyuntor (circuit breaker) local, expiración y un límite agregado. Monitorea las tasas de solicitudes permitidas y rechazadas, los accesos a cuotas por inquilino, la latencia de almacenamiento, las hot keys, los errores de script y la carga downstream real por separado.

Respuesta de muestra de alta calidad

Utilizaría dos capas: el gateway protege contra inundaciones de IP y no autenticadas, mientras que la aplicación aplica la política de inquilinos y endpoints. Los inquilinos gratuitos y de pago tienen valores de tasa y ráfaga separados. Por defecto usaría un token bucket porque una API generalmente puede tolerar una ráfaga corta mientras sigue aplicando un promedio a largo plazo. Cada bucket almacena tokens y su última hora de recarga, y un script atómico realiza la recarga, verificación y consumo en el almacenamiento compartido.

Si las regiones no requieren un resultado global exacto para cada solicitud, asignaría cuotas regionales y utilizaría telemetría global para detectar excesos inusuales. Si el cobro o la liquidación de cuotas debe ser estricta, usaría un punto de decisión de mayor consistencia y aceptaría la latencia. Las solicitudes que superan el límite reciben un 429 y orientación para reintentos; una falla de almacenamiento elige fail-closed, fail-open breve o una cola acotada según el riesgo del endpoint. Luego realizaría pruebas de carga para la capacidad de ráfaga, los límites de ventana, la equidad entre inquilinos, la recuperación de fallas y la carga downstream, no solo la cantidad de 429s.

Errores comunes

  • “Usar contadores de Redis” → sin semántica de políticas ni atomicidad → especifica el estado del bucket, los límites del script y el comportamiento ante fallas.
  • Una sola cuota para todos los inquilinos → un inquilino grande desabastece a los pequeños → particiona la política por inquilino y endpoint, luego agrega una protección global.
  • Tratar una ventana fija como un techo estricto por minuto → el tráfico en los límites de ventana puede acercarse al doble de la tasa → declara el error y elige ventana deslizante o token bucket cuando sea necesario.
  • Abrir las compuertas cuando falla el almacenamiento del limitador → la dependencia colapsa primero → elige una degradación acotada según el riesgo comercial y genera alertas sobre ella.
  • Decirles a los clientes que reintenten el 429 de inmediato → el tráfico rechazado se convierte en más carga → proporciona orientación de reintento, fluctuación (jitter) y un límite máximo.

Preguntas de seguimiento y respuestas

¿Cómo evitas que un inquilino multiplique su asignación en 20 instancias?

Coloca el estado del bucket en un almacenamiento compartido visible para cada instancia y actualízalo atómicamente bajo la clave de política del inquilino. Si solo hay contadores locales disponibles, califica el resultado como aproximado y agrega un límite a nivel de gateway; no afirmes precisión global.

¿Qué pasa si 100 solicitudes por minuto deben aplicarse estrictamente en todas las regiones?

Utiliza un punto de decisión global de consistencia más fuerte o serializa la deducción a través de la región de origen del inquilino. El costo es la latencia interregional y una menor disponibilidad durante una falla regional. Si un breve exceso es aceptable, utiliza cuotas regionales más reconciliación y documenta el margen de error en el SLO.

¿Cómo evitas que un limitador lento ralentice la API?

Establece tiempos de espera (timeouts) estrictos y un disyuntor alrededor de la llamada al limitador. Mantén un límite de seguridad local para interrupciones del almacenamiento y degrada según el riesgo del endpoint. Rastrea la latencia del limitador, los timeouts y las fallas de scripts de forma independiente de la tasa de éxito del negocio.

¿Cuándo deberías encolar en lugar de devolver 429?

Encola solo cuando el trabajo sea asíncrono, el tiempo de espera se ajuste al presupuesto del usuario y la dependencia necesite suavizado de carga. La cola debe estar acotada y rechazar solicitudes cuando esté llena. Las lecturas interactivas o las esperas no acotadas generalmente deberían devolver 429 con honestidad.

¿Cómo pruebas el defecto del límite de ventana fija?

Envía una ráfaga justo antes de que termine la ventana y otra justo después de que comience, luego cuenta las solicitudes en cada intervalo móvil. Repite con la recarga por inactividad de token-bucket, una ráfaga de bucket lleno y consumo concurrente utilizando un reloj controlado.

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