KeyDB como [potencial] alternativa a Redis

No se encontraron reseñas en Habr sobre "una alternativa más rápida a Redis" — KeyDB. Tras obtener una experiencia reciente en su uso, quería llenar este vacío.

KeyDB como [potencial] alternativa a Redis

La historia es bastante común: una vez, con un gran aumento en el tráfico, se registró una significativa degradación en el rendimiento de la aplicación (específicamente, en el tiempo de respuesta). En ese momento, desafortunadamente, no pudimos realizar un diagnóstico adecuado de lo que sucedía, por lo que posteriormente planeamos una serie de pruebas de carga. Después de realizarlas, pudimos identificar el cuello de botella, que resultó ser la caché de la base de datos en Redis. Como suele suceder, el problema no se podía resolver de inmediato y de la manera correcta — por medio de los desarrolladores (cambiando la lógica de funcionamiento). Por lo tanto, la curiosidad y el deseo de superar la situación de manera alterna se activaron. Así nació este artículo.

Problemática

Sobre Redis en general

Como muchos saben, Redis es una base de datos de un solo hilo. Para ser más precisos, lo es en el contexto de trabajar con datos de usuario. De hecho, desde la cuarta versión, las operaciones internas y de servicio de Redis se han trasladado a la ejecución paralela. Sin embargo, este cambio solo afectó a una pequeña parte de la carga, ya que la mayor parte del trabajo recae en los datos de usuario.

Sobre este tema se han roto innumerables copas, pero los desarrolladores de Redis se niegan obstinadamente a implementar una verdadera paralelización, mencionando cuánto complicaría la aplicación y aumentaría los costos generales, así como también añadiría más errores. Su posición es la siguiente: si te enfrentas al problema de un solo núcleo, tienes problemas con la arquitectura de la aplicación y necesitas cambiar algo en ella. Sin embargo, entre los usuarios hay un "otro campo" — entre aquellos que se han topado con un solo núcleo y afirman que Redis se crea a sí mismo cuellos de botella. En caso de cargas realmente grandes — tarde o temprano — inevitablemente se enfrentará a este problema, lo que impone limitaciones significativas en la arquitectura y/o complicaciones forzadas en ella.

No voy a juzgar ninguna opinión. En su lugar, compartiré nuestro caso específico y cómo lo resolvimos.

Nuestro caso

En uno de los proyectos, nos encontramos con que el equipo de desarrollo configuró un caché de datos de base de datos (PostgreSQL) a través de Redis de manera extremadamente agresiva. Este era el único camino que durante picos repentinos de tráfico salvaba a PostgreSQL de caer y, como consecuencia, a la aplicación.

Después de una serie de pruebas de carga, realizamos un análisis de la situación y descubrimos que Redis estaba limitado a un solo núcleo (lo que se llama 'en el soporte'); a partir de ahí, la degradación de la aplicación era bastante rápida. El 'estrangulamiento' seguía una progresión geométrica: una vez alcanzado el límite de rendimiento de Redis, todo dejaba de funcionar.

Se veía más o menos así:

KeyDB como [potencial] alternativa a Redis

Desde el lado de New Relic, el problema fue claramente identificado:

KeyDB como [potencial] alternativa a Redis

Y aquí está la estadística sobre la operación get en Redis:

KeyDB como [potencial] alternativa a Redis

Después de que el problema se comunicara en todos sus detalles al equipo de desarrollo, se aclaró que 'en este momento no se puede resolver el problema'. Así comenzaron las búsquedas de solución por parte del equipo de operaciones, y la respuesta fue la ya mencionada KeyDB.

Sin embargo, antes de comenzar su revisión, es importante mencionar que en el proyecto se utiliza Redis independiente, ya que la solución de clúster basada en Sentinel presenta latencias significativamente mayores. Una de las soluciones evidentes era crear varias réplicas de caché: ¡y que la aplicación acceda por todas partes con balanceo! Sin embargo, tras consultar con los desarrolladores, nos vimos obligados a descartar esta opción debido al mecanismo activo y complejo de invalidación de caché de la aplicación. El mismo problema se aplicaba al sharding del caché.

Revisión rápida de KeyDB

En la búsqueda de una posible solución al problema, descubrimos una aplicación llamada KeyDB. Este es un fork de Redis, desarrollado por una empresa canadiense y distribuido bajo una licencia BSD gratuita. El proyecto es bastante joven: existe desde principios de 2019. La historia es tal que los autores también se encontraron en su momento con las limitaciones de Redis... y decidieron hacer su propio fork. Además, no solo resolvió los problemas conocidos, sino que también recibió funcionalidades adicionales que están disponibles solo en la versión enterprise de Redis.

Para quienes deseen conocer más sobre KeyDB, hay un buen artículo introductorio en Medium, que presenta la base de datos y breves benchmarks que la comparan con su 'padre': Redis.

Ante todo, lo que nos atrajo de KeyDB fue su potencial para resolver nuestros problemas, además de algunas características adicionales interesantes. El uso de KeyDB prometía las siguientes ventajas:

  • obtención de multihilo completo;
  • compatibilidad total y absoluta con Redis (para nosotros esto era especialmente importante, ya que no era posible realizar cambios desde la aplicación), lo que también prometía una migración sin problemas;
  • mecanismo de respaldo integrado en el almacenamiento S3;
  • replicación activa de fácil implementación;
  • clusterización y particionamiento sencillos sin Sentinel ni otro software auxiliar.

Más de 3,000 estrellas y numerosos colaboradores en GitHub también se veían prometedores. La aplicación se desarrolla y se mantiene de manera bastante activa, lo cual es evidente por los commits, la interacción en issues y los PR cerrados (aceptados). La respuesta por parte del mantenedor principal siempre es amable y rápida. En general, había suficientes argumentos.

Migración y resultados

A pesar de que el proyecto de migración fue una especie de aventura (dada la novedad de KeyDB), no había mucho que perder. De hecho, revertir los cambios es bastante rápido y sencillo, ya que toda la infraestructura está desplegada en Kubernetes, y los mecanismos integrados Rolling Update resuelven muy bien esos problemas.

En general, preparamos plantillas de Helm, cambiamos la aplicación en el entorno de prueba a la nueva base de datos y lanzamos todo esto, entregándolo al departamento de QA del cliente.

Comenzó la prueba, que duró alrededor de una semana y en la que no nos adentramos en detalles. Solo sabemos que el cliente verificó las funciones estándar de trabajo con Redis usando el controlador PHP phpredis, así como realizó pruebas de QA en la interfaz de usuario. Después de esto, nos dieron luz verde: no se descubrieron efectos secundarios en el uso del nuevo software. Es decir, desde el punto de vista de la aplicación, no ha cambiado nada en absoluto..

Cabe destacar que tampoco cambiamos nada en la configuración: literalmente, solo reemplazamos la imagen utilizada. Lo mismo se aplica al monitoreo y la exportación de métricas a Prometheus: el más común de ellos funciona perfectamente con KeyDB y sin ninguna modificación. Por lo tanto, se puede afirmar con confianza que, desde el punto de vista operativo, esta fue una mudanza ideal.

Gracias a todo esto, después de cambiar la aplicación a una nueva base de datos, se puede no hacer ningún cambio, y como medida de "estabilización", dejarla en ese estado para trabajar en producción durante un tiempo. Sin embargo, si desea ver un aumento en el rendimiento (o al menos algún cambio), no debe olvidar que por defecto el parámetro KeyDB, responsable de la multithread (server-threads), es igual a uno, es decir, la base de datos funciona exactamente igual que Redis.

Después de cambiar, probar y vivir un tiempo con la nueva aplicación (con KeyDB), decidimos repetir las pruebas de carga con los mismos parámetros que se utilizaron para Redis. ¿Cuáles fueron sus resultados?..

En el gráfico de consumo de CPU, se notó de inmediato la eliminación de los problemas con el "techo" en un núcleo: el proceso comenzó a utilizar los recursos disponibles:

KeyDB como [potencial] alternativa a Redis

Y posteriormente intenté presionar bastante la aplicación y vi un consumo de hasta tres núcleos...

Según las métricas de New Relic, la aplicación web, en general, con la misma carga, comenzó a comportarse de manera notablemente más adecuada. Se observó cierta degradación del rendimiento, sin embargo, comparando con el gráfico anterior, puede evaluar por sí mismo el progreso significativo:

KeyDB como [potencial] alternativa a Redis

El indicador de latencia de la nueva base de datos (KeyDB) también empeoró, pero se mantuvo dentro de los valores aceptables:

KeyDB como [potencial] alternativa a Redis

En el siguiente gráfico se puede ver claramente que el número de solicitudes a KeyDB es similar:

KeyDB como [potencial] alternativa a Redis

En resumen de estas pruebas sintéticas, se puede decir que tanto Redis como KeyDB muestran una degradación significativa del rendimiento en latencia (40 ms+) con un aumento considerable en el número de conexiones paralelas (1000+). En nuestro caso, la aplicación web logró "reducir" la latencia de Redis incluso con un número más bajo de conexiones (400+), aunque para KeyDB esa carga seguía siendo aceptable.

Conclusiones

En este ejemplo, se puede apreciar la fuerza de la comunidad de código abierto en el desarrollo de proyectos en los que está interesada. En internet encontré una excelente frase que se resumía a lo siguiente: 'Una gran empresa crea un producto interesante, hace que algunas de sus funciones sean abiertas, pero deja la parte más importante de pago. La comunidad lo utiliza durante un tiempo y luego alguien se desanima y hace un fork, implementando esas funciones de pago y abriéndolas a todos'. Así es KeyDB, un caso como este.

Al hablar sobre la migración en sí, que resultó sorprendentemente sencilla, no obtuvimos tanto un aumento significativo en el rendimiento que podría esperarse mirando los gráficos de los autores de KeyDB… Sin embargo, este es solo nuestro caso particular, en el que puede haber muchas desviaciones, incluyendo la famosa arquitectura de la aplicación (por ejemplo, una gran cantidad de comandos get en Redis en lugar de la opción más eficiente de consultas agregadas mget…). Sin embargo, logramos obtener resultados positivos, junto con múltiples funciones útiles que aún estamos por implementar en el corto plazo.

En general, KeyDB se ve prometedor: a medida que obtengamos experiencia práctica trabajando con este SGBD (¡la cual aún está por venir!) y el desarrollo del propio proyecto, consideraremos su aplicación en otras situaciones.

Sin embargo, no debe considerarse este artículo como una guía (y mucho menos como un llamado) a abandonar Redis en favor de KeyDB de manera generalizada. A pesar de nuestra experiencia positiva, es evidente que no es una solución mágica. El caso fue bastante específico: para resolver un problema inmediato en una situación donde necesitábamos hacerlo rápidamente y con costos mínimos, esta solución fue justificada. ¿Será útil KeyDB en su caso? Al menos, ahora sabe que existe esa posible opción.

P.D.

También puedes leer en nuestro blog:

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster