Algoritmos de ventana deslizante
El desborde en el límite de la ventana fija viene de dividir el tiempo en bloques. Una solicitud cae en un bloque u otro, y un tramo del reloj que cruza la unión puede acarrear el doble del límite.
Si dejas de usar bloques, el problema desaparece. Ambos algoritmos de esta sección miden contra una ventana que termina en la solicitud que se está evaluando, y solo se diferencian en cuánto recuerdan.
Registro de ventana deslizante
Guarda una marca de tiempo por cada solicitud aceptada. Cuando llega una nueva, mira hacia atrás la duración de una ventana, cuenta lo que hay ahí y decide.
La ventana se calcula de nuevo cada vez, así que se desliza detrás de cada solicitud. Mismo estacionamiento, ventana de treinta segundos, límite de cinco:
| Tiempo | Llegan | La ventana mira hasta | Cantidad en la ventana | Resultado |
|---|---|---|---|---|
| 0s | 1 | 0s | 0 | Aceptada |
| 5s | 2 | 0s | 1 | Ambas aceptadas, el contador ahora es 3 |
| 15s | 2 | 0s | 3 | Ambas aceptadas, el contador ahora es 5 |
| 25s | 1 | 0s | 5 | Rechazada, en el límite |
| 35s | 1 | 5s | 4 | Aceptada, la solicitud de 0s ya venció |
| 40s | 3 | 10s | 3 | Dos aceptadas, la tercera rechazada |
A los 35 segundos la ventana empieza en 5, así que la solicitud de 0 queda fuera de ella y ya no cuenta. Ese vencimiento es todo el mecanismo: la capacidad vuelve gradualmente conforme las solicitudes viejas salen, en lugar de recuperarse toda de golpe con un reinicio.
Ningún tramo de treinta segundos contiene jamás más de cinco solicitudes. Esa es la garantía que una ventana fija no puede ofrecer.
Aquí el borde queda detrás de la solicitud que se está evaluando, así que se mueve cada vez. Nadie recibe un reinicio, y tampoco nadie tiene que esperar uno.
Contador de ventana deslizante
El costo del registro es la lista de marcas de tiempo. El contador logra casi la misma precisión con solo dos enteros.
Vuelve a las ventanas fijas, mantén un conteo para la ventana actual y otro para la anterior, y luego pondera el conteo anterior según cuánto de él todavía cae dentro de una mirada hacia atrás deslizante:
x = qué tan avanzados estamos en la ventana actual, como fracción
ponderado = (1 - x) * conteoAnterior + conteoActual
aceptar si ponderado + 1 <= límiteCon una ventana de treinta segundos, un límite de 5, y una ventana anterior que se llenó por completo:
| Tiempo | Dentro de la ventana | 1 - x | Ponderado | Más esta solicitud | Resultado |
|---|---|---|---|---|---|
| 35s | 5s, o sea 1/6 | 5/6 | 5/6 × 5 + 0 = 4.17 | 5.17 | Rechazada, supera 5 |
| 40s | 10s, o sea 1/3 | 2/3 | 2/3 × 5 + 0 = 3.33 | 4.33 | Aceptada |
| 40s de nuevo | 10s, o sea 1/3 | 2/3 | 2/3 × 5 + 1 = 4.33 | 5.33 | Rechazada |
El término (1 - x) * conteoAnterior es la estimación: conforme la ventana actual se llena, queda menos de la anterior a la vista, así que su contribución se va desvaneciendo de forma suave.
Dos contadores por cliente, y ninguna marca de tiempo.
En lugar de revisar qué solicitudes específicas siguen dentro del rango, asume que se repartieron parejo y toma una fracción. Más barato, y casi exacto.
Dónde discrepan
El contador asume que las solicitudes de la ventana anterior se repartieron parejo. Rara vez es así, y qué algoritmo resulta más permisivo depende de dónde se agruparon realmente.
Solicitudes cerca del inicio de la ventana anterior. El registro mira hacia atrás treinta segundos reales, ve que esas solicitudes tempranas quedan fuera de ese rango, y permite más. El contador igual les cobra una fracción, así que rechaza.
Aquí el registro es más permisivo, porque el contador está tratando la capacidad como más restringida de lo que en realidad es.
Solicitudes cerca del final de la ventana anterior. Ahora el registro todavía las tiene a la vista y rechaza, mientras que el contador ya desvaneció casi todo el conteo anterior. Aquí el contador es más permisivo, porque subestima qué tan reciente fue ese tráfico.
Así que el error va en ambas direcciones, y eso es lo que lo hace aceptable. No es un sesgo sistemático a favor de los clientes ni del servidor.
A veces esa suposición es generosa y a veces es estricta, y eso depende por completo de cuándo llegaron realmente las solicitudes.
Ponlo a prueba
Una ventana de treinta segundos, un límite de 5, y una ventana anterior que aceptó 5 solicitudes. Todavía no hay solicitudes en la ventana actual.
- Usando el contador, ¿se acepta una solicitud a los 33 segundos?
- ¿En qué punto de la ventana actual se vuelve aceptable la primera solicitud?
- Mismo tráfico, pero las 5 solicitudes de la ventana anterior llegaron todas en su primer segundo. ¿Qué algoritmo permite la solicitud a los 33 segundos, y por qué?
Compara tus respuestas
1. Rechazada. A los 33 segundos estás 3 segundos dentro de una ventana de 30 segundos, así que x es 1/10. El conteo ponderado es 0.9 × 5 + 0 = 4.5, y al sumar esta solicitud da 5.5, por encima del límite de 5.
2. A los 36 segundos. Necesitas que (1 - x) × 5 + 1 <= 5, así que (1 - x) × 5 <= 4, así que 1 - x <= 0.8 y x >= 0.2. Un quinto de una ventana de treinta segundos son 6 segundos, lo que ubica la primera solicitud aceptable a los 36 segundos.
3. El registro la permite; el contador todavía la rechaza. El registro mira hacia atrás hasta los 3 segundos. Las cinco solicitudes anteriores llegaron antes de eso, así que ya vencieron y el conteo es 0.
El contador no tiene idea de cuándo llegaron, asume una distribución pareja, y aun así les cobra 4.5 en contra. Ese es el costo concreto de la aproximación: el cliente no envió absolutamente nada en los últimos treinta segundos y de todos modos es rechazado.
Hacia dónde va esto
Ambos algoritmos hacen cumplir un promedio, y ambos tratan una ráfaga como algo que hay que prevenir. Sin embargo, mucho tráfico es legítimamente irregular: una página que carga seis recursos a la vez no es abuso.
Token bucket toma la postura opuesta: permite una ráfaga a propósito y luego hace que el cliente espere para ganarse otra.

