Volver al inicio

Errores 429 con Límite de RPS: Poisson y Sharding

El artículo analiza las causas de errores 429 constantes en el limitador de RPS cuando el tráfico promedio está por debajo del límite. Usando distribución Poisson, se calculan la probabilidad de ráfagas y la expectativa condicional. Considerando sharding en 6 pods y reintentos de clientes se explican los 7 rechazos de RPS observados.

¿Por qué 7 RPS 429 en Límite de 150: Poisson + Sharding
Advertisement 728x90

Modelización de Errores 429 en un Limitador de RPS Distribuido con Flujo de Poisson

Con un tráfico promedio de 129 solicitudes exitosas por segundo y 7 errores 429 con un límite de 150 RPS, surge la pregunta: ¿por qué se activa el limitador de manera constante? Un gráfico de 40 minutos muestra un nivel constante de errores en intervalos de 15 segundos. La distribución de Poisson del volumen de solicitudes explica el fenómeno: con λ = 136,28, la probabilidad de superar 150 solicitudes en 1 segundo es del 11,27%.

Código para calcular la probabilidad:

def get_prob_at_least(border, lmbd):
    sum = 1
    mult = 1
    for i in range(1, border):
        mult = mult * lmbd / i
        sum += mult
    return 1 - sum * math.exp(-lmbd)

get_prob_at_least(151, 129.01 + 7.27)
# 0.1127

Este valor >1 en un intervalo de 15 segundos corresponde al gráfico observado.

Google AdInline article slot

Expectativa Condicional de Errores

Un cálculo simple del número esperado de solicitudes al superar el límite da 156,4, y los errores—solo 0,6 RPS. La diferencia con 7,27 RPS requiere aclaración.

Código para la expectativa condicional:

def get_expectation_via_conditional_at_least(border, lmbd):
    sum_prob = 0
    exp_sum = 0
    mult = 1
    for i in range(1, 10000):
        mult = mult * lmbd / i
        if (i >= border):
            exp_sum += i * mult
            sum_prob += mult
    return exp_sum / sum_prob

def get_expected_errors_num(events, border):
    return (get_expectation_via_conditional_at_least(border, events) - border) * get_prob_at_least(border, events)

Ajustes del Modelo: Reintentos y Fragmentación

Considerando 1 reintento por error (tráfico original 132,64 RPS) aumenta los errores a 0,72 RPS—aún insuficiente.

Google AdInline article slot

Factor clave: un servicio de 6 pods (2 pods por 3 DCs). Con fragmentación, cada limitador divide 150/6 = 25 RPS, límite = 26.

Cálculo para un limitador:

limiters_num = 6
retry_num = 2
rps_one_limiter=(129.01 + 7.27 / 2)/limiters_num
border_one_limiter=int(150/limiters_num) + 1

one_limiter_erros = get_expected_errors_num(rps_one_limiter, border_one_limiter)
limited_num = one_limiter_erros * limiters_num * retry_num
# limited_num ≈ 6.85

El modelo explica 6,85 RPS de errores versus 7,27 observados. El limitador opera sin sincronización de permisos, con intercambio periódico de vecinos y reinicio de contadores.

Google AdInline article slot

Características de Implementación de un Limitador Distribuido

Posibles opciones:

  • Cubo con Fugas: fuga constante de tokens.
  • Reinicio al inicio de un segundo: período fijo, vulnerable a picos.
  • División dinámica: intercambio de latidos para cálculo de cuotas.

En un escenario fragmentado sin sincronización, cada pod decide independientemente el límite, aumentando los fallos totales linealmente con el número de fragmentos.

Conclusiones Clave

  • La distribución de Poisson modela con precisión el tráfico de consumidores sin bots (un caso límite de usuarios infinitos).
  • La fragmentación de limitadores de RPS sin sincronización aumenta los errores proporcionalmente a los pods.
  • Los reintentos del cliente agravan el problema, requiriendo ajustes en los modelos.
  • La expectativa condicional (E[X | X ≥ límite]) es crucial para predecir fallos.
  • Una probabilidad del 11% de un pico explica los 429 estables en gráficos agregados.

— Editorial Team

Advertisement 728x90

Leer después