Solucionando Comandos Lentos en Redis: Una Lista de Verificación de Rendimiento
Una lista de verificación práctica para encontrar comandos lentos en Redis con SLOWLOG, MONITOR, herramientas de latencia, complejidad de comandos y soluciones más seguras.
Solucionando Comandos Lentos en Redis: Una Lista de Verificación de Rendimiento
Los comandos lentos en Redis suelen comenzar como comandos normales que superan sus suposiciones. Una llamada SMEMBERS era inofensiva cuando el conjunto tenía 200 miembros. Una consulta de panel de control estaba bien cuando cargaba 50 claves. Un script Lua era rápido hasta que un cliente creó una forma de datos mucho más grande que todos los demás.
La pregunta útil no es solo "¿qué comando es lento?" Es "¿qué forma de datos hizo que este comando fuera lento, y por qué la aplicación le pide a Redis que haga tanto trabajo de una sola vez?"
Comprendiendo el Rendimiento de Redis
El rendimiento de Redis es generalmente excepcional debido a su naturaleza en memoria. Sin embargo, varios factores pueden contribuir a la latencia de los comandos:
- Complejidad del Comando: Ciertos comandos son inherentemente más intensivos en recursos que otros (por ejemplo,
KEYSen un conjunto grande de datos vs.GET). - Tamaño y Estructura de los Datos: Listas grandes, conjuntos o conjuntos ordenados, o estructuras de datos complejas, pueden afectar el rendimiento de los comandos que operan sobre ellos.
- Latencia de Red: Aunque no es directamente un problema del comando, una alta latencia de red entre el cliente y el servidor puede hacer que los comandos parezcan lentos.
- Carga del Servidor: Un alto uso de CPU, memoria insuficiente u otros procesos en el servidor Redis pueden degradar el rendimiento.
- Comandos Bloqueantes: Ciertas operaciones pueden bloquear el bucle de eventos de Redis, afectando a todos los comandos subsiguientes.
Identificando Comandos Lentos con SLOWLOG
El comando SLOWLOG es el mecanismo integrado de Redis para registrar comandos que exceden un tiempo de ejecución especificado. Esta es tu herramienta principal para identificar proactivamente comandos problemáticos.
Cómo Funciona SLOWLOG
Redis mantiene un búfer circular que almacena información sobre comandos que tardaron más que el umbral configurado slowlog-log-slower-than (en microsegundos). El umbral predeterminado suele ser de 10 milisegundos (10000 microsegundos). Cuando este búfer se llena, las entradas más antiguas se descartan.
Subcomandos Clave de SLOWLOG
SLOWLOG GET [count]: Recupera las últimascountentradas del registro lento. Si se omitecount, recupera todas las entradas.SLOWLOG LEN: Devuelve la longitud actual del registro lento (número de entradas).SLOWLOG RESET: Limpia las entradas del registro lento. Usa este comando con precaución, ya que elimina permanentemente los datos registrados.
Ejemplo de Uso de SLOWLOG
Supongamos que sospechas que algunos comandos están tardando demasiado. Puedes verificar el registro lento de la siguiente manera:
# Conéctate a tu instancia de Redis
redis-cli
# Obtén los últimos 5 comandos lentos
127.0.0.1:6379> SLOWLOG GET 5
La salida se verá algo así:
1) 1) (integer) 18
2) (integer) 1678886400
3) (integer) 15000
4) 1) "KEYS"
2) "*"
2) 1) (integer) 17
2) (integer) 1678886390
3) (integer) 12000
4) 1) "SMEMBERS"
2) "my_large_set"
...
Explicación de la salida:
- ID de Entrada: Un identificador único para la entrada del registro lento.
- Marca de Tiempo: La marca de tiempo Unix cuando se ejecutó el comando.
- Tiempo de Ejecución: La duración (en microsegundos) que tomó ejecutar el comando.
- Comando y Argumentos: El comando en sí y sus argumentos.
En el ejemplo anterior, KEYS * tomó 15000 microsegundos (15ms) y SMEMBERS my_large_set tomó 12000 microsegundos (12ms). Estos se considerarían lentos si tu slowlog-log-slower-than está configurado en 10000 microsegundos.
Configurando slowlog-log-slower-than
Puedes cambiar dinámicamente el umbral slowlog-log-slower-than usando el comando CONFIG SET:
127.0.0.1:6379> CONFIG SET slowlog-log-slower-than 50000 # Registrar comandos más lentos que 50ms
Para hacer que este cambio sea persistente tras reinicios de Redis, necesitarías modificar el archivo redis.conf y reiniciar el servidor Redis, o usar CONFIG REWRITE para guardar los cambios en el archivo de configuración.
Monitoreo de Comandos en Tiempo Real con MONITOR
Mientras que SLOWLOG proporciona una vista histórica, MONITOR ofrece un flujo en tiempo real de todos los comandos que está ejecutando el servidor Redis. Esto es invaluable para depurar durante un período específico de rendimiento lento o para entender los patrones de tráfico de comandos.
Cómo Funciona MONITOR
Cuando habilitas MONITOR, Redis envía una respuesta al cliente MONITOR por cada comando que recibe y procesa. Esto puede generar un volumen muy alto de salida, especialmente en instancias Redis ocupadas. Por lo tanto, generalmente se recomienda usar MONITOR con moderación y solo cuando se esté depurando activamente.
Ejemplo de Uso de MONITOR
Desde una sesión separada de redis-cli, ejecuta el comando MONITOR:
# Conéctate a tu instancia de Redis en un terminal *separado*
redis-cli
# Inicia el monitoreo
127.0.0.1:6379> MONITOR
Ahora, cualquier comando ejecutado en otra sesión de redis-cli o por tu aplicación aparecerá en la salida de MONITOR. Por ejemplo, si ejecutas SET mykey myvalue en otro cliente, verás:
1678887000.123456 [0 127.0.0.1:54321] "SET" "mykey" "myvalue"
Usando MONITOR para Depurar
- Reproduce el Problema: Cuando notes una ralentización, inicia inmediatamente
MONITORen una sesión dedicada deredis-cli. - Desencadena la Operación Lenta: Haz que tu aplicación realice la acción que sospechas que está causando la ralentización.
- Analiza la Salida: Observa los comandos en el flujo de
MONITOR. Busca:- Comandos que tardan mucho en aparecer (aunque
MONITORno muestra el tiempo de ejecución, puedes inferirlo midiendo los comandos manualmente u observando retrasos). - Comandos inusuales o inesperados que se están ejecutando.
- Un alto volumen de comandos que podrían estar sobrecargando el servidor.
- Comandos que tardan mucho en aparecer (aunque
- Detén el Monitoreo: Presiona
Ctrl+Cpara salir del comandoMONITOR.
Importante: No ejecutes MONITOR en un entorno de producción por períodos prolongados, ya que puede afectar significativamente el rendimiento de Redis debido a la sobrecarga de enviar cada comando al cliente.
Causas Comunes de Comandos Lentos y Cómo Solucionarlos
Basado en la información recopilada de SLOWLOG y MONITOR, aquí hay culpables comunes y sus soluciones:
1. Comando KEYS
- Problema: El comando
KEYSitera sobre todo el espacio de claves para encontrar claves que coincidan con un patrón. En bases de datos con millones de claves, esto puede tomar mucho tiempo y bloquear el servidor Redis, afectando a todos los demás clientes. - Solución: Evita
KEYSen espacios de claves grandes de producción. UsaSCANcuando necesites iteración incremental de claves.SCANdevuelve un subconjunto de claves que coinciden con un patrón en cada llamada, lo que reduce la posibilidad de bloquear el servidor por mucho tiempo.
Necesitarás llamar a# En lugar de KEYS user:* redis-cli -h <host> -p <port> SCAN 0 MATCH user:* COUNT 100SCANvarias veces, usando el cursor devuelto por la llamada anterior, hasta que el cursor vuelva a 0.
2. Scripting Complejo (Scripts Lua)
- Problema: Scripts Lua de larga duración o ineficientes ejecutados a través de
EVALoEVALSHApueden bloquear el servidor. Aunque Redis ejecuta scripts de forma atómica, un solo script largo puede monopolizar el bucle de eventos. - Solución: Optimiza tus scripts Lua. Divide la lógica compleja en scripts más pequeños y manejables. Analiza el rendimiento del script. Asegúrate de que los bucles dentro de los scripts sean eficientes y terminen correctamente. Realiza pruebas comparativas de tus scripts para entender su tiempo de ejecución.
3. Operaciones en Estructuras de Datos Grandes
- Problema: Comandos como
SMEMBERSen un conjunto con millones de miembros,LRANGEen una lista muy larga, oZRANGEen un conjunto ordenado enorme pueden ser lentos. - Solución: Evita obtener estructuras de datos grandes completas. En su lugar, usa comandos iterativos o procesa datos en fragmentos:
- Conjuntos: Usa
SSCANen lugar deSMEMBERS. - Listas: Usa
LRANGEcon valoresstartystopmás pequeños para recuperar datos en páginas. - Conjuntos Ordenados: Usa
ZRANGEconLIMIToZSCAN.
- Conjuntos: Usa
4. Comandos que Requieren Iteración de Claves (Menos Común pero Posible)
- Problema: Aunque es menos común, los comandos que podrían iterar implícitamente sobre claves debido a su naturaleza podrían ser lentos si el espacio de claves es grande.
- Solución: Revisa la referencia de comandos de Redis para el comando específico y comprende su complejidad. Considera estructuras de datos o enfoques alternativos si un comando específico resulta ser un cuello de botella.
5. Comandos Bloqueantes (Raros en Redis Moderno)
- Problema: Las versiones antiguas de Redis tenían algunos comandos que podían bloquear el servidor. La mayoría de estos han sido solucionados o reemplazados.
- Solución: Asegúrate de estar usando una versión reciente de Redis. Consulta la documentación de Redis para cualquier operación de bloqueo conocida específica de tu versión.
Primero Decide si Redis es Lento o el Cliente está Esperando
Cuando alguien dice "Redis es lento", puede referirse a varias cosas diferentes. El servidor puede estar tardando demasiado en ejecutar un comando. El cliente puede estar esperando en la red. Un grupo de conexiones puede estar agotado. Un proxy TLS puede estar sobrecargado. Una respuesta grande puede estar tardando más en transferirse de lo que tardó el comando en ejecutarse.
SLOWLOG solo registra el tiempo de ejecución del comando dentro de Redis. No incluye el tiempo de transferencia de red, el tiempo de cola del cliente, ni el tiempo de espera por una conexión de un grupo de aplicaciones. Es por eso que un registro lento limpio no siempre prueba que los usuarios están imaginando latencia.
Compara tres vistas:
redis-cli --latency -h <host> -p <port>
redis-cli --latency-history -h <host> -p <port>
redis-cli SLOWLOG GET 10
Si la latencia es alta pero SLOWLOG está vacío, mira la red, los grupos de clientes, la saturación de CPU del servidor, la actividad de fork, la persistencia o las respuestas grandes. Si SLOWLOG muestra comandos costosos repetidos, comienza con el diseño del comando y la estructura de datos.
En las aplicaciones, agrega temporización alrededor de las llamadas a Redis en el límite del cliente. Registra la familia de comandos, el patrón de clave, el tiempo transcurrido y si el cliente esperó por una conexión del grupo. No registres secretos ni cargas útiles completas. Una pequeña cantidad de temporización estructurada generalmente responde si el retraso está dentro de Redis o antes de que el comando siquiera lo alcance.
Usa la Complejidad del Comando como una Prueba de Olfato
Los comandos de Redis son rápidos cuando tocan una cantidad pequeña y limitada de datos. Se vuelven riesgosos cuando escanean un gran espacio de claves, devuelven una colección enorme o hacen trabajo proporcional a un valor grande.
Antes de culpar al hardware, verifica la complejidad del comando en la referencia de comandos de Redis para tu versión. No necesitas memorizar cada etiqueta de complejidad, pero la forma importa:
GET user:123está limitado por el tamaño de un valor.HGET profile:123 emailestá limitado por una búsqueda en hash.SMEMBERS followers:celebritydevuelve todo el conjunto.KEYS *escanea todo el espacio de claves.LRANGE queue 0 -1devuelve toda la lista.ZREMRANGEBYSCOREpuede eliminar un gran número de miembros de un conjunto ordenado.
El patrón arriesgado suele ser "dame todo". Puede funcionar durante meses, luego fallar cuando un conjunto crece de cientos de miembros a millones. Redis no se volvió repentinamente lento; los datos cruzaron el punto donde un comando sin límite se hizo visible.
Reemplazos Más Seguros para Patrones Lentos Comunes
Reemplaza los comandos de espacio de claves completo y colección completa con patrones incrementales.
Para descubrimiento de claves, usa SCAN:
redis-cli --scan --pattern 'user:*'
Para conjuntos, usa SSCAN:
SSCAN active_users 0 COUNT 500
Para hashes, usa HSCAN:
HSCAN user:123:settings 0 COUNT 200
Para conjuntos ordenados, prefiere rangos con límites explícitos:
ZRANGE leaderboard 0 99 WITHSCORES
ZRANGEBYSCORE events 1716600000 1716686400 LIMIT 0 500
Para listas, pagina con rangos limitados:
LRANGE recent_jobs 0 99
SCAN es incremental, pero no es una operación mágica gratuita. Puede devolver duplicados y no proporciona una instantánea perfectamente consistente mientras las claves cambian. Es bueno para mantenimiento, migración y descubrimiento en segundo plano. Generalmente no es la primitiva adecuada para una ruta de solicitud orientada al usuario que necesita una lista precisa en tiempo real.
Las Respuestas Grandes Pueden Ser el Costo Real
Un comando puede ejecutarse rápidamente y aún así perjudicar a tu aplicación si devuelve demasiados datos. SMEMBERS en un conjunto enorme, HGETALL en un hash grande, o MGET sobre miles de valores grandes pueden dedicar tiempo a serializar la respuesta y enviarla a través de la red. Ese costo puede no aparecer claramente solo como tiempo de ejecución del comando.
Observa la salida de red y la memoria del cliente durante la operación lenta. Si una sola solicitud devuelve decenas o cientos de megabytes, rediseña el patrón de acceso. Almacena datos de resumen por separado. Pagina el resultado. Usa un índice de conjunto ordenado y obtén solo la porción visible. Evita colocar documentos grandes en Redis cuando la aplicación generalmente necesita un campo.
Un ejemplo práctico: si un panel muestra los últimos 50 trabajos, no almacenes cada ID de trabajo en una lista y llames a LRANGE jobs 0 -1 antes de dividir en la aplicación. Almacena la lista en orden del más nuevo al más antiguo y solicita solo lo que la página necesita:
LRANGE jobs:recent 0 49
Ese pequeño cambio puede eliminar una cantidad sorprendente de latencia y presión de memoria.
MONITOR es un Bisturí, No un Panel de Control
MONITOR es útil cuando necesitas ver exactamente qué comandos envía un cliente, especialmente cuando sospechas que la aplicación está haciendo algo diferente de lo que sugiere la revisión de código. Pero en un servidor Redis ocupado, MONITOR crea sobrecarga y produce un torrente de salida.
Úsalo por una ventana corta y controlada:
redis-cli MONITOR | head -n 200
Luego detenlo. En producción, prefiere el muestreo de registros de aplicación, estadísticas de comandos de Redis o una ventana de mantenimiento corta cuando sea posible.
INFO commandstats suele ser más seguro para una vista amplia:
redis-cli INFO commandstats
Muestra conteos de llamadas por comando y microsegundos acumulados. No te dirá qué clave fue lenta, pero puede revelar que una aplicación está emitiendo muchas más llamadas HGETALL, KEYS o EVAL de lo esperado.
Los Scripts Lua Necesitan Límites
Los scripts Lua son poderosos porque se ejecutan atómicamente dentro de Redis. Ese mismo comportamiento atómico significa que un script largo bloquea otros comandos mientras se ejecuta. Los scripts lentos a menudo provienen de bucles sobre colecciones grandes, descubrimiento de claves sin límite o lógica que creció de un pequeño ayudante a una mini aplicación.
Revisa los scripts con las mismas preguntas:
- ¿Cuántas claves puede tocar esto?
- ¿Cuántos elementos puede recorrer en bucle?
- ¿Qué sucede cuando la clave de entrada tiene un millón de miembros?
- ¿Se puede dividir el trabajo en fragmentos más pequeños?
- ¿El script devuelve una carga útil grande?
Si un script aparece en SLOWLOG, resiste la tentación de solo aumentar slowlog-log-slower-than. El registro te está diciendo que un bloque atómico está tomando suficiente tiempo como para afectar a otros clientes.
Persistencia, Forks y "Comandos Lentos" Que Son Síntomas
A veces los comandos son lentos porque Redis está ocupado con trabajo en segundo plano. Las instantáneas RDB y las operaciones de reescritura AOF pueden aumentar la CPU, la presión de memoria y la E/S de disco. En Linux, bifurcar un proceso grande de Redis también puede crear picos de latencia, especialmente cuando están involucrados overcommit de memoria, páginas enormes o almacenamiento lento.
Verifica:
redis-cli INFO persistence
redis-cli INFO stats
redis-cli INFO memory
redis-cli LATENCY LATEST
Si los picos de latencia coinciden con guardados en segundo plano o reescrituras AOF, ajusta la persistencia con cuidado. Puede que necesites almacenamiento más rápido, políticas de guardado ajustadas, umbrales de reescritura AOF o configuraciones de memoria. No deshabilites la persistencia solo para hacer que un benchmark se vea mejor a menos que Redis sea puramente un caché desechable y el negocio acepte perder los datos.
El Comportamiento del Cliente Puede Sobrecargar Redis Sin Un Comando Malo
Un servidor Redis puede verse perjudicado por millones de pequeñas llamadas ineficientes tanto como por un comando obviamente lento. Una página que hace 200 llamadas secuenciales GET se sentirá lenta incluso si cada GET individual es rápido.
Usa pipelining cuando la aplicación necesite muchos comandos independientes y pueda tolerar recibir las respuestas juntas:
GET user:1
GET user:2
GET user:3
enviado como pipeline evita un viaje de ida y vuelta por comando. El pipelining no es un reemplazo para un buen modelado de datos, y puede aumentar el uso de memoria si los lotes son demasiado grandes. Comienza con tamaños de lote modestos y mide.
También inspecciona los grupos de conexiones. Si los registros de la aplicación muestran llamadas a Redis que toman 500 ms pero Redis no ve comandos lentos, la aplicación puede estar esperando una conexión libre. Aumenta el grupo solo después de verificar por qué las conexiones existentes están ocupadas. Un grupo más grande puede ocultar el síntoma mientras aumenta la presión sobre Redis.
Una Lista de Verificación de Incidentes Práctica
Cuando la latencia de Redis está perjudicando a los usuarios, recopila hechos en este orden:
date -u
redis-cli PING
redis-cli --latency -i 1
redis-cli SLOWLOG GET 20
redis-cli INFO commandstats
redis-cli INFO clients
redis-cli INFO memory
redis-cli INFO persistence
redis-cli LATENCY LATEST
Luego pregunta qué cambió: un despliegue, un nuevo endpoint, un evento de crecimiento de datos, un trabajo por lotes, una migración, una consulta de panel, un nuevo patrón de clave de caché o una reescritura de persistencia. Las ralentizaciones de Redis a menudo están vinculadas a un patrón de acceso único que se volvió popular o a una clave que se volvió mucho más grande de lo esperado.
Para cada comando lento, anota el patrón de clave y el propietario. "SMEMBERS lento" no es suficiente. "El servicio de recomendaciones llama a SMEMBERS product:123:viewers en un conjunto que puede crecer sin límite" es procesable.
Resumen de la Lista de Verificación de Ajuste de Rendimiento
- Habilita y Monitorea
SLOWLOG: Revisa periódicamenteSLOWLOG GETpara identificar comandos lentos recurrentes. Ajustaslowlog-log-slower-thansi es necesario. - Usa
MONITORcon Precaución: Para depuración en tiempo real durante sospechas de ralentizaciones, pero desactívalo inmediatamente después. - Evita
KEYSen espacios de claves grandes de producción: UsaSCANpara iteración incremental cuando sea realmente necesario el descubrimiento de claves. - Optimiza Scripts Lua: Asegúrate de que los scripts
EVALyEVALSHAsean eficientes y no se ejecuten excesivamente largos. - Procesa Estructuras de Datos Grandes de Forma Iterativa: Usa
SSCAN,ZSCAN,LRANGEcon límites, oSCANen lugar de obtener colecciones completas. - Analiza los Argumentos de los Comandos: Asegúrate de que los argumentos pasados a los comandos no estén causando un comportamiento inesperado (por ejemplo, conteos muy grandes, patrones complejos).
- Monitorea los Recursos del Servidor: Mantén un ojo en el uso de CPU, memoria y red del servidor Redis. Los comandos lentos a veces pueden ser un síntoma de un servidor estresado.
- Optimizaciones del Lado del Cliente: Verifica que tu aplicación no esté enviando comandos demasiado rápido o en lotes ineficientes. Considera el pipelining para múltiples comandos cuando sea apropiado.
Verificación Final
Usa SLOWLOG para encontrar comandos que son lentos dentro de Redis, herramientas de latencia para detectar picos del lado del servidor y temporización de la aplicación para detectar espera del cliente. Luego arregla el patrón de acceso, no solo el umbral. Comandos limitados, respuestas más pequeñas, lotes sensatos y una propiedad clara de las claves grandes hacen más por el rendimiento de Redis que perseguir cambios de ajuste únicos.