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.
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.
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.
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
Aún no hay comentarios.