Cómo utilizar Redis para aplicaciones de medición en tiempo real

Roshan Kumar es gerente senior de producto en Redis Labs .

La medición no es solo un simple problema de conteo. La medición a menudo se confunde con la medición, pero generalmente es más que eso. La medición implica la medición, pero como un proceso continuo, generalmente con el objetivo de regular el uso o flujo de un recurso a lo largo del tiempo. Las aplicaciones modernas incorporan la medición de muchas formas diferentes, desde contar personas, objetos o eventos hasta regular el uso, controlar el acceso y asignar capacidad.

Las soluciones de medición generalmente deben procesar grandes volúmenes de datos y cumplir con los estrictos requisitos de rendimiento. Según la escala de la solución, el recuento y la medición pueden implicar miles, si no millones, de actualizaciones de una base de datos cada segundo. Los requisitos principales de una base de datos para admitir una solución de este tipo son un alto rendimiento para las operaciones de escritura y una latencia baja (submilisegundo) para las respuestas.

Redis, la plataforma de base de datos en memoria de código abierto, ofrece estos dos beneficios y, al mismo tiempo, es rentable en términos de uso de recursos de hardware mínimos. En este artículo, examinaremos ciertas características de Redis que lo convierten en una buena opción para las soluciones de medición y cómo podemos usar Redis para ese propósito. Pero primero, veamos algunos de los usos más comunes de la medición.

Aplicaciones de medición comunes

La medición es necesaria en cualquier aplicación que deba medir el uso de un recurso a lo largo del tiempo. Aquí hay cuatro escenarios comunes:

  1. Modelos de precios basados ​​en el consumo . A diferencia de los modelos de pago únicos o basados ​​en suscripción, los modelos de precios basados ​​en el consumo permiten a los consumidores pagar solo por el uso real. Los consumidores disfrutan de una mayor flexibilidad, libertad y ahorro de costos, mientras que los proveedores obtienen una mayor retención de consumidores.

    Implementar tales modelos puede resultar complicado. A veces, el sistema de medición tiene que rastrear muchos elementos de uso y muchas métricas en un solo plan. Por ejemplo, un proveedor de nube puede establecer diferentes niveles de precios para los ciclos de la CPU, el almacenamiento, el rendimiento, la cantidad de nodos o el tiempo que se usa un servicio. Una empresa de telecomunicaciones puede establecer diferentes niveles de consumo permitido para minutos, datos o texto. La solución de medición debe imponer límites, cobrar o extender los servicios según el tipo de precio basado en el consumo.

  2. Restricción de la utilización de recursos . Se puede abusar de todos los servicios de Internet mediante un uso excesivo, a menos que el servicio tenga una tarifa limitada. Los servicios populares como la API de Google AdWords y la API de Twitter Stream incorporan límites de tasa por este motivo. Algunos casos extremos de abuso conducen a la denegación de servicio (DoS). Para evitar abusos, los servicios y las soluciones a los que se puede acceder en Internet deben diseñarse con reglas de limitación de velocidad adecuadas. Incluso las páginas simples de autenticación e inicio de sesión deben limitar el número de reintentos durante un intervalo de tiempo determinado.

    Otro ejemplo en el que se hace necesario restringir la utilización de recursos es cuando los requisitos comerciales cambiantes suponen una carga mayor en los sistemas heredados de la que pueden soportar. La limitación de la tasa de llamadas a los sistemas heredados permite a las empresas adaptarse a la creciente demanda sin necesidad de reemplazar sus sistemas heredados.

    Además de prevenir el abuso y reducir la carga, una buena limitación de velocidad también ayuda con la gestión de escenarios de tráfico con ráfagas. Por ejemplo, una API que aplique un método de limitación de velocidad de fuerza bruta puede permitir 1000 llamadas cada hora. Sin una política de configuración del tráfico, un cliente puede llamar a la API 1000 veces en los primeros segundos de cada hora, quizás excediendo lo que la infraestructura puede soportar. Los algoritmos populares de limitación de velocidad, como Token Bucket y Leaky Bucket, evitan las ráfagas no solo limitando las llamadas, sino también distribuyéndolas a lo largo del tiempo.

  3. Distribución de recursos . La congestión y los retrasos son escenarios comunes en las aplicaciones que se ocupan del enrutamiento de paquetes, la gestión de trabajos, la congestión del tráfico, el control de multitudes, la mensajería de redes sociales, la recopilación de datos, etc. Los modelos de colas ofrecen varias opciones para administrar el tamaño de la cola según la tasa de llegada y salida, pero implementar estos modelos a gran escala no es fácil.

    El atasco y la congestión son preocupaciones constantes cuando se trata de flujos de datos rápidos. Los diseñadores inteligentes deben definir límites de longitud de cola aceptables, al tiempo que incorporan tanto la supervisión del rendimiento de las colas como el enrutamiento dinámico según el tamaño de las colas.

  4. Contando a escala para la toma de decisiones en tiempo real . Los sitios de comercio electrónico, las aplicaciones de juegos, las redes sociales y las aplicaciones móviles atraen a millones de usuarios diarios. Debido a que más ojos generan mayores ingresos, contar a los visitantes y sus acciones con precisión es fundamental para los negocios. El recuento es igualmente útil para casos de uso como reintentos de errores, escalado de problemas, prevención de ataques DDoS, creación de perfiles de tráfico, asignación de recursos bajo demanda y mitigación de fraudes.

Desafíos de diseño de medición

Los arquitectos de soluciones deben considerar muchos parámetros al crear una aplicación de medición, comenzando con estos cuatro:

  1. Complejidad del diseño. Contar, rastrear y regular volúmenes de datos, especialmente cuando llegan a gran velocidad, es una tarea abrumadora. Los arquitectos de soluciones pueden manejar la medición en la capa de aplicación mediante el uso de estructuras de lenguaje de programación. Sin embargo, dicho diseño no es resistente a fallas o pérdida de datos. Las bases de datos tradicionales basadas en disco son sólidas y prometen un alto grado de durabilidad de los datos durante fallas. Pero no solo no brindan el rendimiento requerido, sino que también aumentan la complejidad sin las estructuras de datos y las herramientas adecuadas para implementar la medición.
  2. Latencia. La medición generalmente implica numerosas actualizaciones constantes de los recuentos. La latencia de lectura / escritura de la red y del disco se suma cuando se trata de grandes números. Esto podría convertirse en una bola de nieve y generar una gran acumulación de datos que provocarían más retrasos. La otra fuente de latencia es un diseño de programa que carga los datos de medición de una base de datos a la memoria principal del programa y los escribe en la base de datos cuando termina de actualizar el contador.
  3. Simultaneidad y coherencia. La arquitectura de una solución para contar millones y miles de millones de elementos puede volverse compleja cuando los eventos se capturan en diferentes regiones y todos deben converger en un solo lugar. La coherencia de los datos se convierte en un problema si muchos procesos o subprocesos actualizan el mismo recuento al mismo tiempo. Las técnicas de bloqueo evitan problemas de coherencia y ofrecen coherencia a nivel transaccional, pero ralentizan la solución.
  4. Durabilidad. La medición afecta las cifras de ingresos, lo que implica que las bases de datos efímeras no son ideales en términos de durabilidad. Un almacén de datos en memoria con opciones de durabilidad es una elección perfecta.

Usar Redis para aplicaciones de medición

En las siguientes secciones, examinaremos cómo usar Redis para contar y medir soluciones. Redis tiene estructuras de datos integradas, comandos atómicos y capacidades de tiempo de vida (TTL) que se pueden usar para potenciar los casos de uso de medición. Redis se ejecuta en un solo hilo. Por lo tanto, todas las actualizaciones de la base de datos se serializan, lo que permite que Redis funcione como un almacén de datos sin bloqueos. Esto simplifica el diseño de la aplicación, ya que los desarrolladores no necesitan hacer ningún esfuerzo para sincronizar los hilos o implementar mecanismos de bloqueo para la coherencia de los datos.  

Comandos de Atomic Redis para contar

Redis proporciona comandos para incrementar valores sin el requisito de leerlos en la memoria principal de la aplicación.

Mando Descripción
INCR llave Incrementar el valor entero de una clave en uno
INCRBY incremento de clave Incrementar el valor entero de una clave por el número dado
INCRBYFLOAT incremento de clave Incrementar el valor flotante de una clave en la cantidad dada
DECR llave Disminuir el valor entero de una clave en uno
DECRBY decremento clave Disminuir el valor entero de una clave en el número dado
HINCRBY incremento de campo clave Incrementar el valor entero de un campo hash por el número dado
HINCRBYFLOAT incremento de campo clave Incrementar el valor flotante de un campo hash en la cantidad dada

Redis almacena enteros como un entero de 64 bits con signo en base 10. Por lo tanto, el límite máximo para un número entero es un número muy grande: 263 - 1 = 9.223.372.036.854.775.807.

Tiempo de vida integrado (TTL) en las teclas Redis

Uno de los casos de uso común en la medición es realizar un seguimiento del uso en función del tiempo y limitar los recursos una vez que se agota el tiempo. En Redis, se puede establecer un valor de tiempo de vida para las claves. Redis desactivará automáticamente las claves después de un tiempo de espera establecido. La siguiente tabla enumera varios métodos para caducar claves.

Mando Descripción
EXPIRE segundos clave Establece el tiempo de vida de una llave en segundos
EXPIREAT marca de tiempo clave Establecer el vencimiento de una clave como marca de tiempo de Unix
PEXPIRE milisegundos clave Establezca el tiempo de vida de una clave en milisegundos
PEXPIREAT marca de tiempo clave Establecer el vencimiento de una clave como marca de tiempo de UNIX en milisegundos
SET valor clave [EX segundos] [PX milisegundos] Establezca el valor de la cadena en una clave junto con el tiempo de vida opcional

Los mensajes a continuación le dan el tiempo de vida de las teclas en términos de segundos y milisegundos.

Mando Descripción
TTL llave Obtenga tiempo para vivir por una llave
PTTL llave Obtenga el tiempo para vivir por una clave en milisegundos

Estructuras de datos y comandos de Redis para un conteo eficiente

Redis es amado por sus estructuras de datos como Listas, Conjuntos, Conjuntos ordenados, Hashes e Hyperloglogs. Se pueden agregar muchos más a través de la API de módulos de Redis.

Laboratorios Redis

Las estructuras de datos de Redis vienen con comandos integrados que están optimizados para ejecutarse con la máxima eficiencia en la memoria (justo donde se almacenan los datos). Algunas estructuras de datos lo ayudan a lograr mucho más que el conteo de objetos. Por ejemplo, la estructura de datos Set garantiza la unicidad de todos los elementos.

El conjunto ordenado va un paso más allá al garantizar que solo se agreguen elementos únicos al conjunto y le permite ordenar los elementos en función de una puntuación. Ordenar sus elementos por tiempo en una estructura de datos de conjunto ordenado, por ejemplo, le ofrecerá una base de datos de series de tiempo. Con la ayuda de los comandos de Redis, puede obtener sus elementos en un orden determinado o eliminar elementos que ya no necesita.

Hyperloglog es otra estructura de datos especial que estima el recuento de millones de elementos únicos sin necesidad de almacenar los objetos en sí ni de afectar la memoria.

Estructura de datos Mando Descripción
Lista LLEN llave Obtenga la longitud de una lista
Conjunto SCARD llave Obtener el número de miembros en un conjunto (cardinalidad)
Conjunto ordenado ZCARD llave Obtenga la cantidad de miembros en un conjunto ordenado
Conjunto ordenado ZLEXCOUNT clave min max Cuente el número de miembros en un conjunto ordenado entre un rango lexicográfico dado
Picadillo HLEN llave Obtenga la cantidad de campos en un hash
Hyperloglog PFCOUNT llave Obtenga la cardinalidad aproximada del conjunto observado por la estructura de datos de Hyperloglog
Mapa de bits BITCOUNT clave [inicio fin] Cuenta los bits establecidos en una cadena

Persistencia de Redis y replicación en memoria

Los casos de uso de medición, como los pagos, implican almacenar y actualizar información que es fundamental para las empresas. La pérdida de datos tiene un impacto directo en los ingresos. También puede destruir los registros de facturación, que a menudo son un requisito de cumplimiento o de gobierno.

Puede ajustar la coherencia y la durabilidad en Redis según sus requisitos de datos. Si necesita una prueba de registro permanente para sus datos de medición, puede lograr durabilidad a través de las capacidades de persistencia de Redis. Redis admite AOF (archivo de solo anexión), que copia los comandos de escritura en el disco a medida que ocurren, y la creación de instantáneas, que toma los datos tal como existen en un momento determinado y los escribe en el disco.

Arquitectura Redis sin bloqueo integrada

El procesamiento de Redis es de un solo subproceso; esto asegura la integridad de los datos, ya que todos los comandos de escritura se serializan automáticamente. Esta arquitectura alivia a los desarrolladores y arquitectos de la carga de sincronizar subprocesos en un entorno multiproceso.

En el caso de una aplicación móvil de consumo popular, miles y, a veces, millones de usuarios pueden estar accediendo a la aplicación simultáneamente. Digamos que la aplicación mide el tiempo utilizado y dos o más usuarios pueden compartir minutos al mismo tiempo. Los subprocesos paralelos pueden actualizar el mismo objeto sin imponer la carga adicional de garantizar la integridad de los datos. Esto reduce la complejidad del diseño de la aplicación al tiempo que garantiza velocidad y eficiencia.

Implementaciones de muestra de medición de Redis

Echemos un vistazo al código de muestra. Varios de los escenarios a continuación requerirían implementaciones muy complejas si la base de datos utilizada no fuera Redis.

Bloquear varios intentos de inicio de sesión

Para evitar el acceso no autorizado a las cuentas, los sitios web a veces impiden que los usuarios realicen varios intentos de inicio de sesión dentro de un período de tiempo estipulado. En este ejemplo, restringimos que los usuarios realicen más de tres intentos de inicio de sesión en una hora utilizando una funcionalidad clave simple de tiempo de vida.

La clave para contener el número de intentos de inicio de sesión:

user_login_attempts:

Pasos:

Obtenga el número actual de intentos:

OBTENER user_login_attempts:

Si es nulo, configure la clave con el tiempo de vencimiento en segundos (1 hora = 3600 segundos):

SET user_login_attempts: 1 3600

Si no es nulo y si el recuento es mayor que 3, arroja un error:

Si no es nulo, y si el recuento es menor o igual a 3, incremente el recuento:

INCR user_login_attempts:

Tras un intento de inicio de sesión exitoso, la clave se puede eliminar de la siguiente manera:

DEL user_login_attempts:

Paga sobre la marcha

La estructura de datos de Redis Hash proporciona comandos sencillos para realizar un seguimiento del uso y la facturación. En este ejemplo, supongamos que cada cliente tiene sus datos de facturación almacenados en un Hash, como se muestra a continuación:

facturación_cliente:

     uso

     costo

     .

     .

Suponga que cada unidad cuesta dos centavos y el usuario consume 20 unidades. Los comandos para actualizar el uso y la facturación son:

cliente de hincrby: uso 20

cliente de hincrbyfloat: costo .40

Como habrá notado, su aplicación puede actualizar la información en la base de datos sin necesidad de que cargue los datos de la base de datos en su propia memoria. Además, puede modificar un campo individual de un objeto Hash sin leer el objeto completo.

Tenga en cuenta: El propósito de este ejemplo es mostrar cómo usar los comandos hincrbyy hincrbyfloat. Con un buen diseño, evita almacenar información redundante, como el uso y el costo.