Jitter
Qué es
Jitter es la variación deliberada del momento de ejecución para distribuir trabajo que, de otro modo, ocurriría simultáneamente. En una política de retry, introduce variación en la espera entre intentos. Aquí no designa la fluctuación involuntaria de latencia de una red.
Las responsabilidades se separan: Retry decide si corresponde repetir; backoff determina cómo evoluciona una espera base; Jitter distribuye los momentos efectivos. Esa combinación es frecuente, pero no constituye una receta universal: agregar azar no vuelve seguro un intento ni hace recuperable un fallo permanente.
Qué problema resuelve
Un incidente puede correlacionar clientes que normalmente operan de manera independiente. Si una dependencia deja de responder y todos esperan un segundo antes de repetir, recibe otra oleada un segundo después. Si duplican la espera de forma determinista, las oleadas siguientes siguen coincidiendo. Un reinicio masivo o una tarea programada común puede producir el mismo efecto.
La separación temporal de Backoff reduce la frecuencia individual, pero conserva esa sincronización. Jitter rompe parte de la correlación: dos clientes con la misma política eligen esperas diferentes. No elimina toda coincidencia, ni garantiza que la capacidad alcance para el volumen total.
El análisis de AWS sobre exponential backoff y jitter muestra agrupamientos persistentes con backoff determinista y una distribución más uniforme al introducir variación. Sus resultados comparan algoritmos en una simulación de contención; no establecen un ganador universal para cualquier servicio.
Cómo funciona
La política define una ventana temporal y selecciona una demora dentro de ella. La ventana puede crecer con los fallos consecutivos, alcanzar un máximo y reiniciarse después de un éxito. El significado de cada límite debe ser explícito: limitar la espera no equivale a limitar los intentos.
Tres familias frecuentes ilustran decisiones distintas:
| Variante | Idea conceptual | Consecuencia relevante |
|---|---|---|
| Full jitter | Seleccionar una espera entre cero y el límite calculado por Backoff. | Dispersa sobre toda la ventana, pero permite esperas muy cortas. |
| Equal jitter | Conservar una parte fija de la espera y variar el resto. | Introduce un piso de demora y utiliza una ventana más estrecha. |
| Decorrelated jitter | Hacer depender la siguiente ventana también de la espera seleccionada anteriormente. | La trayectoria incorpora historia aleatoria, además del número de intentos. |
Estos nombres no sustituyen la especificación de una implementación. Un SDK puede utilizar otro intervalo o combinar reglas de modo diferente. Antes de configurar una biblioteca hay que revisar sus límites, su distribución y cuándo reinicia el estado.
Full jitter sobre una ventana uniforme de 800 ms tiene una espera media de 400 ms. Cambiar una espera determinista de 800 ms por esa distribución modifica también el ritmo promedio de intentos. Comparar solamente el máximo oculta esa diferencia: la dispersión puede mejorar mientras aumenta la frecuencia individual.
Ejemplo: relay de mensajes
Varios procesos que publican registros de un transactional-outbox encuentran una caída del broker. Todos comienzan su recuperación casi al mismo tiempo. Con esperas deterministas de uno, dos y cuatro segundos, sus intentos se agrupan aproximadamente a uno, tres y siete segundos del fallo inicial.
Una política con ventanas crecientes y muestras independientes distribuye los intentos dentro de esas ventanas. Algunos procesos prueban antes y otros después; al volver el broker no recibe necesariamente toda la población en un mismo instante.
La variación no cambia la identidad del evento. El relay conserva la intención original, y la posibilidad de publicar otra vez sigue exigiendo un consumidor con idempotency o una protección equivalente. Tampoco se considera entregado un registro porque haya transcurrido su espera.
Presupuesto y restricciones externas
La espera elegida y el siguiente intento deben caber en el presupuesto de deadline. Si ya no hay tiempo útil, introducir azar no justifica un intento adicional. Ajustar todas las esperas al mismo instante límite puede volver a concentrar clientes precisamente al final del presupuesto.
Cuando un protocolo o un servidor impone una espera mínima, la política debe respetarla. Puede distribuir intentos después de ese mínimo; elegir antes contradice la señal. Si el caller no dispone de ese tiempo, debe terminar o delegar conforme al contrato de la operación, sin inventar un presupuesto nuevo.
La variación de probes de un circuit-breaker también puede reducir coincidencias entre instancias, pero no debe alterar qué tráfico está autorizado ni cuántas pruebas se admiten. Espaciar y admitir son decisiones diferentes.
Failure scenarios
- Aleatoriedad correlacionada: procesos con la misma secuencia de muestras pueden seguir intentando juntos. La independencia entre clientes importa más que la apariencia irregular de una secuencia individual.
- Ventana insignificante: distribuir miles de clientes sobre un intervalo diminuto puede conservar una ráfaga superior a la capacidad disponible.
- Resolución del temporizador: demoras distintas pueden terminar en el mismo intervalo efectivo cuando el runtime agrupa activaciones.
- Recorte después del sorteo: llevar muchos valores al mismo máximo puede concentrar probabilidad en ese punto. El orden de las operaciones forma parte de la distribución real.
- Intentos ilimitados: clientes dispersos todavía pueden mantener una sobrecarga prolongada. Jitter no reemplaza límites por operación ni presupuestos agregados de Retry.
- Fallos no recuperables: distribuir consultas inválidas o efectos inseguros solamente distribuye el daño.
La observabilidad debe distinguir la espera planificada de la efectiva. Bloqueos del proceso, colas locales y saturación del scheduler pueden alterar la distribución que finalmente ve la dependencia.
Cuándo usarlo y trade-offs
Es útil cuando existe una población de clientes susceptible de sincronizarse y el trabajo admite una demora variable. thundering-herd incluye activaciones por eventos compartidos, como expiración de cache o recuperación, y no requiere retries; Jitter puede distribuir algunas de ellas sin eliminar su costo total. La selección de la ventana depende de la capacidad, la tolerancia a latencia y el tiempo disponible; no de una constante trasladada sin contexto desde otro sistema.
El costo es variabilidad: algunas operaciones esperan más que otras y la reproducibilidad de un incidente requiere registrar las decisiones temporales. Una ventana grande dispersa mejor, pero puede retrasar recuperación útil. Una pequeña responde rápido, pero puede dejar concentración suficiente para prolongar el fallo.
No conviene agregar Jitter indiscriminadamente a pasos que no generan tráfico correlacionado o cuyo presupuesto ya es mínimo. Tampoco resuelve ordenamiento, exclusión mutua o seguridad de efectos. Para recorrer esas decisiones junto con las de espera y admisión, usar resilience-patterns.