La tentación de utilizar KV para limitar la velocidad es comprensible. Ya tienes el KV en el enlace, es global y la limitación de velocidad parece simple: incrementa un contador por clave IP y recházalo cuando pase el límite. El problema es que esta implementación no funciona y la falla no es lo suficientemente sutil como para aparecer en las pruebas.
KV no tiene operaciones atómicas. No hay comparación e intercambio, no hay incremento atómico. Cuando dos trabajadores se ejecutan simultáneamente para la misma IP, ambos ganan get del contador (obteniendo, por ejemplo, el valor 5), ambos ganan put con el valor 6 y uno de los incrementos se pierde. Con tráfico real, la tasa de pérdida incremental crece con la competencia. El limitador de velocidad cuenta menos de lo que debería y las solicitudes que deberían bloquearse pasan.
Este no es un error de implementación que se solucione reintentando. Es la consecuencia directa de la ausencia de primitivas de sincronización en KV. La arquitectura fue diseñada para otro tipo de carga de trabajo.
Por qué la limitación de velocidad necesita atomicidad
Un contador limitador de velocidad debe garantizar que la secuencia de lectura-incremento-escritura sea atómica. Si dos procesos ejecutan esta secuencia simultáneamente sobre el mismo contador, el resultado correcto es el valor original más dos. Sin atomicidad, el resultado suele ser el valor original más uno.
Cloudflare tiene dos soluciones a este problema. La primera es la funcionalidad nativa de Rate Limiting, configurable mediante reglas en el panel de control o mediante Rulesets API, que opera por debajo del nivel de Trabajador y utiliza infraestructura interna con las correctas garantías de sincronización. El segundo es Durable Objects, que ofrece un aislamiento con estado persistente y acceso serializado: puede implementar un contador exacto porque solo se ejecuta un trabajador a la vez dentro del Durable Object para esa clave.
KV no forma parte de la solución para la limitación exacta de la velocidad. Los intentos de implementar una limitación de velocidad con KV terminan en sistemas que rechazan menos tráfico del que deberían, exactamente en las horas pico donde la limitación de velocidad es más importante.
Indicadores de funciones con KV: qué funciona y qué no
Los indicadores de funciones son el caso de uso más citado de KV y funcionan bien dentro de los límites correctos. El modelo básico es simple: escribes un objeto JSON en una clave con todos los indicadores del sistema y cada trabajador lee esta clave para decidir el comportamiento.
// escrita (admin) await env.FLAGS.put('feature-flags', JSON.stringify({ newCheckout: true, betaSearch: false, darkMode: true })); // leitura (worker) const flags = await env.FLAGS.get('feature-flags', { type: 'json' }); if (flags.newCheckout) { /* ... */ }
El modelo funciona porque la carga de trabajo es de lectura intensa y rara vez se escribe. Una bandera cambia algunas veces a la semana. Es leído por cada solicitud de cada Trabajador en cada PoP. La relación lectura-escritura es excelente para KV.
La verdadera limitación es la propagación de 60 segundos. Habilitar una bandera no la activa para todos los usuarios simultáneamente: hay una ventana donde parte de los PoP muestran el comportamiento anterior y parte presentan el nuevo. Para la mayoría de los indicadores de funciones, esto es tolerable. Para una implementación crítica para la seguridad en la que se necesita una bandera para llegar a todos los usuarios al mismo tiempo, es una limitación operativa real.
Donde el modelo falla es en la evaluación dinámica de indicadores por usuario. Si necesita evaluar indicadores en función de los atributos del usuario (plan de suscripción, grupo de prueba A/B, región, entidad específica), el JSON de indicadores globales no lleva esa lógica. Necesita una búsqueda por usuario, lo que normalmente significa una llamada a D1 o a un servicio externo. El KV permanece como un caché de configuración global, no como un sistema de banderas completo.
Para implementaciones graduales por porcentaje de usuarios (10 % consulte la función), la implementación con KV requiere que codifique la lógica de muestreo en Worker y use KV solo para almacenar el porcentaje objetivo. El muestreo en sí no tiene estado (se realiza en el Worker según el hash de ID de usuario), por lo que KV se usa correctamente como almacén de configuración.
Configuración distribuida: el mejor caso de uso para KV
Si los indicadores de funciones son un buen caso de uso, la configuración distribuida es el caso de uso ideal. La diferencia es de granularidad y frecuencia de cambio.
Cambios en la configuración de la aplicación mediante una acción operativa deliberada: actualización del punto final del servicio externo, ajuste del tiempo de espera, lista de IP permitidas, parámetros comerciales. Estos cambios ocurren con muy poca frecuencia (horas o días entre actualizaciones) y deben leerse para cada solicitud.
En este caso, el patrón de almacenamiento en caché a nivel de módulo extrae el máximo de KV. Las variables en el alcance del módulo de un trabajador persisten mientras el aislamiento esté activo, potencialmente para miles de solicitudes:
let config = null; export default { async fetch(request, env, ctx) { config = config ?? await env.CONFIG.get('app-settings', { type: 'json' }); // config está disponível para todos os requests // sem read do KV após o primeiro const timeout = config.upstreamTimeoutMs; // ... } };
La primera solicitud para cada aislado lee el KV. Todas las solicitudes posteriores del mismo aislamiento utilizan el valor en memoria: latencia de KV cero, operaciones de lectura cero cargadas. Una actualización de configuración se propaga a nuevos aislamientos a medida que el tiempo de ejecución expulsa los aislados existentes.
El tiempo de propagación efectivo ya no son los 60 segundos de propagación global de KV, sino 60 segundos más la vida útil de los aislados activos. Los aislados de larga vida pueden conservar la configuración anterior durante más tiempo. Para la mayoría de los cambios operativos, esto es aceptable. Para situaciones de emergencia que requieren propagación inmediata, puede forzar el reinicio de los trabajadores a través de API.
El costo de operación en cada escenario.
Para los tres casos de uso, el modelo de costos KV crea diferentes presiones. La limitación de la tasa sería la escritura por solicitud, algo inviable para cualquier volumen. Los indicadores de funciones tienen un costo mínimo de escritura y lectura que depende de cuántos trabajadores están leyendo la clave y cuántos PoP por segundo. Con el almacenamiento en caché a nivel de módulo, incluso los indicadores de funciones leídos por millones de solicitudes pueden consumir sorprendentemente pocas operaciones de lectura: un aislado que atiende 10 000 solicitudes lee el KV una vez.
La configuración distribuida con almacenamiento en caché a nivel de módulo es el escenario de costo operativo más bajo posible en KV. Una escritura por cambio de configuración, una lectura por aislamiento por reinicio: el costo mensual de las operaciones KV para este patrón es insignificante incluso en aplicaciones de alto tráfico.
¿Qué revelan estos tres casos sobre KV?
El análisis de la limitación de velocidad, los indicadores de características y la configuración distribuida deja en claro la frontera de KV: datos que rara vez se escriben y se leen con frecuencia, donde una ventana de inconsistencia de hasta 60 segundos es tolerable y donde no se necesita atomicidad.
Cuando no se cumple cualquiera de estas tres condiciones, KV producirá errores silenciosos (sin atomicidad), inconsistencias inaceptables (ventana de propagación) o costos prohibitivos (alta frecuencia de escritura). Reconocer este límite antes de la implementación ahorra la sesión de depuración, que suele ser la forma más costosa de saber dónde no se aplica una herramienta.
Lea también
- Cloudflare KV: ¿Qué significa distribuido globalmente cuando necesitas escribir?
- Invalidación de caché en KV: el problema que nadie soluciona elegantemente
- KV en producción: los patrones que funcionan y los que engañan al principio
- WAF + Limitación de velocidad + Gestión de bots: la trifecta de protección edge
- Lo que solo hacen los Trabajadores, lo que solo hacen los Pajes y donde se encuentran los dos
- KV vs R2 vs Cache API: cuándo usar cada nivel de almacenamiento de Cloudflare
