17°
Portada del artículo: Dragonfly 2.0 contra Redis 8 y Valkey 9: con 2 CPU gana por mucho, con 4 depende de cómo configures a los otros
DragonflyRedisValkeyBenchmarksBases de datos

Dragonfly 2.0 contra Redis 8 y Valkey 9: con 2 CPU gana por mucho, con 4 depende de cómo configures a los otros

Medí Dragonfly 2.0, Redis 8.10 y Valkey 9.1 en contenedores con 2 y 4 CPU. Con io-threads activados, Redis y Valkey alcanzan a Dragonfly sin pipeline y lo superan con pipeline 16; con 2 CPU y sin pipeline, Dragonfly gana entre 59 % y 99 % sobre Redis por defecto. Usa 8 a 15 % menos memoria por clave.

Efrain Garay 19 de septiembre de 2026

Reproduciendo el resumen

El 18 de septiembre, heise anunciaba Dragonfly 2.0 con el titular “Redis und Valkey im Visier”. No encontré ninguna mención de esa versión en Hacker News ni en los foros que reviso. Las notas de la release v2.0.0, del 16 de septiembre, dicen que no trae funciones mayores nuevas y que marca un hito de madurez. Así que no había novedad que probar: había una promesa vieja que verificar.

La promesa es que un almacén en memoria con un hilo por núcleo rinde mucho más que Redis. Redis 8 y Valkey 9 ya tienen hilos de E/S, así que la pregunta correcta es con el mismo presupuesto de CPU: ¿cuánto le saca Dragonfly a Redis y a Valkey cuando ellos también usan los núcleos que les das?

Con 4 CPU y sin pipeline los tres superan las 480.000 operaciones por segundo y el banco no los ordena. Con pipeline 16, Redis y Valkey con io-threads ganan (4,21 y 4,04 millones contra 2,73). Con 2 CPU y sin pipeline, Dragonfly gana entre 59 % y 99 % sobre Redis por defecto. Y en memoria ahorra entre 8 y 15 % por clave.

En 76 segundos y narrado: Dragonfly 2.0, Redis 8 y Valkey 9 con el mismo presupuesto de CPU. Con 2 CPU y sin pipeline Dragonfly gana sobre Redis por defecto (342.601 contra 172.081 operaciones por segundo con io_uring) y usa entre 8 y 15 % menos memoria por clave, pero con 4 CPU y sin pipeline el banco no ordena a los tres, y con pipeline 16 ganan Redis y Valkey con io-threads (4,21 y 4,04 millones contra 2,73). Es una sola carga medida, con un banco de lazo cerrado. Sin sonido por defecto: actívalo en los controles.Verlo en el visualizador de reels →

Qué es Dragonfly

Es un almacén en memoria compatible con el protocolo de Redis y de Memcached, escrito en C++ y con licencia BSL 1.1 que pasa a Apache 2.0 el 1 de noviembre de 2030. Lo que lo distingue es la arquitectura: un hilo por núcleo, cada uno dueño de una parte de las claves, sin compartir estado. Redis atiende los comandos en un solo hilo y desde la versión 6 puede repartir la lectura y escritura de sockets en hilos de E/S. Valkey, la bifurcación de Redis, hizo lo mismo.

Medí tres servidores, cada uno solo dentro de su contenedor: Dragonfly v2.0.0, Redis 8.10.1 y Valkey 9.1.2. Redis 8.10.2 salió el 17 de septiembre, pero la imagen redis:8 de Docker todavía traía la 8.10.1 cuando medí, y no existía la etiqueta 8.10.2.

El banco: un cliente, un servidor a la vez, el mismo presupuesto de CPUCada servidor corre solo en un contenedor con límites de pod. El cliente tiene sus propios núcleos. La cgroup dice cuántos núcleos se usaron de verdad.
El banco: un cliente, un servidor a la vez, el mismo presupuesto de CPUcontenedor servidor · 4 o 2 CPU · 2 GB · sin persistenciamemtier 2.5.1200 conexionesnúcleos 4-7 + SMTRedis 8.10.1io-threads 1, o uno por CPUValkey 9.1.2io-threads 1, o uno por CPUDragonfly 2.0.0un proactor por CPUepoll o io_uringcgroup del servidorcpu.statmemory.peakred bridge de DockerEl banco: un cliente, un servidor a la vez, el mismo presupuesto de CPUmemtier 2.5.1200 conexionesnúcleos 4-7 + SMTservidor · 4 o 2 CPU · 2 GBRedis 8.10.1io-threads 1 o NValkey 9.1.2io-threads 1 o NDragonfly 2.0.0epoll o io_uringcgroup del servidorcpu.stat · memory.peakred bridge de Docker

Mismo cliente, mismo espacio de claves (1 M de claves), mismos límites. Lo que cambia es el motor, su ajuste de hilos y, en Dragonfly, el backend de E/S.

El banco y sus tropiezos

Todo corrió en fedora, con un Ryzen 7 7800X3D. Cada servidor va en un contenedor con --cpuset-cpus y --cpus iguales (4 o 2 núcleos), 2 GB y sin persistencia. El cliente es memtier_benchmark 2.5.1, en otro contenedor con sus propios núcleos, por una red bridge. Un millón de claves, valores de 256 bytes, claves al azar, 20 segundos por corrida y 5 corridas por celda. En cada configuración de Redis y Valkey medí dos variantes: por defecto (un hilo) y con --io-threads igual al número de CPU.

Cuatro cosas que salieron mal o que conviene saber:

  • Dragonfly cayó a epoll sin que yo lo pidiera. El perfil seccomp por defecto de Docker bloquea io_uring. El log lo dice: “Check if io_uring is disabled via /proc/sys/kernel/io_uring_disabled. Switching to epoll.” El sysctl del host estaba en 0, y con seccomp=unconfined el mismo binario abrió el anillo de io_uring. Medí las dos variantes: dragonfly-epoll en un Docker normal y dragonfly-uring con --security-opt seccomp=unconfined solo en ese contenedor.
  • La imagen de Redis 8 trae módulos cargados (ReJSON y búsqueda). Es lo que descarga quien hace docker run redis:8, y no los desactivé.
  • Mi primera carga de 4 KiB era inválida. Un millón de valores de 4 KiB son 4 GB y el contenedor tiene 2. El cliente se cayó con Redis y Valkey, y con Dragonfly salió un número sobre un conjunto incompleto. Aparté esas corridas y repetí con 200.000 claves.
  • La primera medida de snapshot de Dragonfly no existió. Lo arranqué con el nombre de archivo vacío y respondió ERR filename is not specified, así que mi guion midió un guardado que nunca ocurrió. Lo rehice con el archivo configurado y con 2 millones de claves.

El host tenía solo unos 5 GB de RAM libres y swap en uso por otro proceso ajeno al banco, y el governor de CPU estaba en powersave. Ninguno de los tres servidores se acercó a esos límites, pero lo digo porque son condiciones de la medida.

Con 4 CPU: sin pipeline hay un techo, con pipeline no

Lecturas y escrituras 10 a 1, 200 conexiones (4 hilos de 50), sin pipeline. Redis y Valkey por defecto, con un hilo, rindieron unas 170.000 operaciones por segundo. Con --io-threads 4, Redis 490.555 y Valkey 481.269. Dragonfly, 491.375 con epoll y 489.604 con io_uring. La latencia p99 de los tres con hilos fue de 0,6 ms, contra 2,3 ms de los servidores de un solo hilo.

Con pipeline 16 el orden cambia: Redis con io-threads llegó a 4.214.020 operaciones por segundo, Valkey a 4.037.297 y Dragonfly a 2.727.721 con epoll y 2.738.973 con io_uring. Es decir, en esa carga Redis fue 1,54 veces más rápido que Dragonfly.

Cuánto tarda cada servidor en atender un millón de peticionesMediana de 5 corridas de 20 s, lecturas y escrituras 10 a 1, valores de 256 bytes (4 KiB en el último escenario), 200 conexiones (204 en los escenarios de 2 CPU).
Redis por defecto5,774 s
Valkey por defecto6,013 s
Redis con io-threads 42,039 s
Valkey con io-threads 42,078 s
Dragonfly, epoll2,035 s
Dragonfly, io_uring2,042 s

Tiempo real. Los tres con hilos llegan juntos: es el techo del banco, más abajo se explica.

Redis por defecto0,817 s
Valkey por defecto0,832 s
Redis con io-threads 40,237 s
Valkey con io-threads 40,248 s
Dragonfly, epoll0,367 s
Dragonfly, io_uring0,365 s

A cuatro veces el tiempo real. Redis y Valkey con hilos ganan.

Redis por defecto5,811 s
Valkey por defecto5,841 s
Redis con io-threads 25,741 s
Valkey con io-threads 25,894 s
Dragonfly, epoll3,662 s
Dragonfly, io_uring2,919 s

Tiempo real. Aquí Dragonfly se separa, sobre todo con io_uring.

Redis por defecto0,822 s
Valkey por defecto0,828 s
Redis con io-threads 20,678 s
Valkey con io-threads 20,693 s
Dragonfly, epoll0,685 s
Dragonfly, io_uring0,684 s

A cuatro veces el tiempo real. Los tres con hilos empatan.

Redis por defecto8,633 s
Valkey por defecto8,744 s
Redis con io-threads 42,909 s
Valkey con io-threads 42,981 s
Dragonfly, epoll2,94 s
Dragonfly, io_uring2,481 s

Tiempo real, 200.000 claves, sin pipeline.

Cada carril se llena en el tiempo que tardó ese servidor en atender un millón de peticiones con la mediana de sus 5 corridas. Cambia de escenario con los botones.

El límite del banco: cuatro servidores, la misma cifra

Que Redis, Valkey y Dragonfly den casi lo mismo sin pipeline con 4 CPU me hizo sospechar del banco antes que de los servidores. memtier mantiene 200 peticiones en vuelo: la siguiente sale cuando llega una respuesta. En un banco así, las operaciones por segundo son las peticiones en vuelo divididas por la latencia media. No son dos medidas: es la misma vista desde dos lados.

Con 200 peticiones en vuelo, la cifra la fija la latencia4 CPU, sin pipeline. El cociente sale de los números medidos, no de un ajuste.
  1. Redis por defecto
    200 en vuelo ÷ 1,154 ms = 173.310/smemtier reporta 173.194/s
  2. Valkey por defecto
    200 en vuelo ÷ 1,202 ms = 166.389/smemtier reporta 166.312/s
  3. Redis con io-threads 4
    200 en vuelo ÷ 0,407 ms = 491.400/smemtier reporta 490.555/s
  4. Valkey con io-threads 4
    200 en vuelo ÷ 0,415 ms = 481.928/smemtier reporta 481.269/s
  5. Dragonfly, epoll
    200 en vuelo ÷ 0,407 ms = 491.400/smemtier reporta 491.375/s
  6. Dragonfly, io_uring
    200 en vuelo ÷ 0,408 ms = 490.196/smemtier reporta 489.604/s

Los cuatro servidores con hilos se quedan en 0,41 ms de latencia media. El cliente usó unos 3 núcleos, con un 70 % de su tiempo en el kernel, y los servidores entre 2,4 y 3,0 de 4 (medido en una repetición de 3 corridas, con la cgroup). Ningún componente que yo mida estaba saturado, así que lo que limita es la latencia del camino completo (cliente, red bridge de Docker y servidor), que no puedo separar.

Por eso trato los 490.000 como “al menos” y no como igualdad de capacidad. Lo único que dice la medida es que, con 4 CPU y sin pipeline, los tres pasan de 480.000 y el banco no llega más arriba.

Con esto en mente, el resultado con pipeline 16 sí separa: ahí Redis y Valkey con hilos hicieron unos 4 millones y Dragonfly 2,7, así que el banco tenía margen para ver la diferencia.

Con 2 CPU: aquí Dragonfly sí gana

Para quitarle protagonismo al cliente reduje el servidor a 2 núcleos y le di 6 al cliente (6 hilos de 34 conexiones: 204). Sin pipeline:

  • Redis por defecto, 172.081 operaciones por segundo. Con --io-threads 2, 174.196 (+1,2 %).
  • Valkey por defecto, 171.208. Con --io-threads 2, 169.653 (−0,9 %).
  • Dragonfly con epoll, 273.104 (+58,7 % sobre Redis por defecto). Con io_uring, 342.601 (+99,1 %).

Las io-threads con 2 CPU no movieron el throughput sin pipeline, aunque sí el consumo: Valkey pasó de 0,66 a 1,64 núcleos usados para dar lo mismo. Con pipeline 16 los tres servidores multihilo empataron: 1.475.365 con Redis, 1.443.686 con Valkey y 1.459.164 con Dragonfly, alrededor de 20 % más que los servidores de un hilo (1,21 millones). Ese empate no lo sé explicar con la CPU: los servidores usaron entre 0,93 y 1,6 de 2 núcleos.

Valores de 4 KiB

Con valores de 4 KiB, 200.000 claves y 4 CPU, sin pipeline: Redis con io-threads 343.776, Valkey 335.449, Dragonfly con epoll 340.113 y con io_uring 403.036. Es la única carga donde Dragonfly con io_uring se separa de los otros dos con hilos: unos 17 % por encima de Redis. Con epoll se queda igual que ellos.

Memoria

Con 1 millón de claves de 256 bytes, la cgroup del contenedor creció 326,5 bytes por clave con Dragonfly, contra 378,2 con Redis por defecto y 384,1 con Valkey. Con 2 millones de claves, cargados, Dragonfly ocupó 635 a 667 MiB y Redis y Valkey 727 a 738 MiB (tres cargas por servidor; la de 667 MiB fue de Dragonfly con epoll). Es un ahorro de 8 a 15 % según el tamaño del conjunto. Con 1 millón de claves fue una sola carga por servidor: lo tomo como orden de magnitud, no como cifra exacta.

Memoria por clave, 1 millón de claves de 256 bytesbytes por clave, según la cgroup · menos es mejor
  1. Dragonfly 2.0.0326 BIgual con epoll y con io_uring.
  2. Redis 8.10.1378 B383 B con io-threads 4.
  3. Valkey 9.1.2384 B384 B con io-threads 4.

Crecimiento de memory.current del contenedor tras cargar las claves. Una carga por servidor.

Snapshot bajo carga

Con 2 millones de claves y carga 1 a 1, lancé BGSAVE a los 12 s de una corrida de 40 s y comparé contra la misma corrida sin snapshot. Tres repeticiones por servidor, 4 CPU.

Redis y Valkey por defecto no cambiaron nada: su p99.9 ya estaba en 2,4 a 2,5 ms sin snapshot y siguió igual con él. Con --io-threads 4 sí se nota. El p99.9 de Redis subió de 0,97 a 2,11 ms (2,2 veces) y el de Valkey de 1,20 a 3,49 ms (2,9 veces). Dragonfly pasó de 0,81 a 1,00 ms con epoll y de 0,84 a 1,06 con io_uring.

La memoria cuenta lo mismo. Sobre lo que ocupaba el conjunto cargado, el pico del contenedor fue de +33 a +83 MiB en Redis con hilos y de +91 a +125 MiB en Valkey con hilos. En Dragonfly, como máximo +13 a +26 MiB: el pico de la cgroup es un máximo acumulado y no separa el guardado de las escrituras de la carga. Redis guarda con fork y su propio INFO reporta la copia en escritura (current_cow_size); en Dragonfly no vi ese costo y no verifiqué por qué.

Latencia p99.9 mientras se guarda el snapshotmilisegundos, mediana de 3 corridas, 4 CPU · menos es mejor
  1. Dragonfly, epoll1,00 msSin snapshot, 0,81 ms.
  2. Dragonfly, io_uring1,06 msSin snapshot, 0,84 ms.
  3. Redis con io-threads 42,11 msSin snapshot, 0,97 ms.
  4. Valkey con io-threads 43,49 msSin snapshot, 1,20 ms.

2 millones de claves, lecturas y escrituras 1 a 1, BGSAVE a los 12 s de una corrida de 40 s. Sin snapshot: 0,97 Redis, 1,20 Valkey, 0,81 y 0,84 Dragonfly.

Lo que tarda el guardado bajo carga es parecido en todos: de 2,5 a 10 s. En reposo, con los mismos 2 millones de claves, Dragonfly con epoll tardó 16 y 17 s, y con io_uring 2 y 3 s (dos corridas de cada uno, según su propio last_success_save_duration_sec). No sé por qué en reposo con epoll es unas cuatro veces más lento que bajo carga y unas seis más que con io_uring.

Lo que no puedo afirmar

  • Que Redis por defecto esté limitado por su único hilo. Usó 0,65 núcleos de los que tenía. Dragonfly rindió 2,8 veces más que Redis por defecto con 4 CPU, pero mis datos no muestran por qué el servidor de un hilo se queda en 173.000, solo que se queda.
  • Cuál es más rápido con 4 CPU y sin pipeline. Ahí manda el techo del banco.
  • Los números de latencia como latencia de producción. El banco es de lazo cerrado: cada latencia es la de un servidor sometido a 200 peticiones concurrentes.
  • Que io_uring sea siempre mejor. Aportó mucho con 2 CPU y con valores de 4 KiB, y nada con 4 CPU, 256 bytes y sin pipeline.
  • Nada sobre persistencia, clúster, réplicas ni comandos que no sean GET y SET. Medí un caso.

Es el mismo cuidado con el que medí Wild contra mold y CUDA en Rust. En el segundo, el 3,2 % a favor de Rust dejó de valer al comprobar que los dos programas no calculaban lo mismo.

Mi opinión

Me sorprendió que la ventaja “varias veces más rápido” de Dragonfly sea en buena parte la diferencia entre un servidor con un hilo y uno con varios. Con las io-threads activadas, Redis 8 y Valkey 9 se acercan mucho, y en pipeline 16 con 4 CPU ganan. Si ya tienes Redis o Valkey, activar --io-threads y medir con tu carga vale más que migrar.

Donde Dragonfly gana con claridad en mis medidas es con pocos núcleos, sin pipeline y con io_uring, y en memoria por clave. Si tu servidor tiene 2 vCPU y tu tráfico es de peticiones sueltas, es una razón concreta. Y el snapshot le costó poco: 0,2 ms de p99.9, contra 1,1 a 2,3 ms de Redis y Valkey con hilos.

Cuándo lo usaría

  • Sí: un servidor chico, de 2 a 4 CPU, con muchas conexiones y peticiones sueltas; datos que ocupan mucha memoria y donde 8 a 15 % por clave cuentan.
  • Sí, con cuidado: si vas a usar io_uring en Docker. Hay que abrir seccomp para ese contenedor y decidir si lo aceptas.
  • Todavía no: si dependes de comandos o módulos que no probé, o si tu carga es de pipeline grande sobre 4 o más núcleos: ahí Redis y Valkey con io-threads dieron más.

Fuentes

Comentarios

Todavía no hay comentarios. El primero es tuyo.

Se revisa antes de publicarse. El correo no se guarda ni aparece en ninguna parte.