Solucionando Errores Comunes de Conexión a Redis de Forma Efectiva

¿Problemas con la conexión a Redis? Esta guía práctica proporciona pasos claros para diagnosticar y resolver errores comunes como 'Conexión Rechazada', 'Tiempos de Espera' y 'Fallos de Autenticación'. Aprende a verificar el estado del servidor, configuraciones de red, cortafuegos y métricas de rendimiento de Redis. Incluye ejemplos prácticos para `redis-cli` y bibliotecas cliente para restablecer tus conexiones a Redis de manera eficiente.

Solucionando Errores Comunes de Conexión a Redis de Forma Efectiva

Los errores de conexión a Redis suelen ser simples una vez que los separas en tres preguntas: ¿puede el cliente alcanzar el host y el puerto?, ¿Redis acepta la conexión? y ¿el cliente tiene permiso para ejecutar comandos después de conectarse?

Hazlo en ese orden. Saltar directamente al código de la aplicación pierde tiempo cuando Redis está detenido. Reconstruir una regla de cortafuegos pierde tiempo cuando la contraseña es incorrecta. Una lista de verificación pequeña y repetible te lleva más rápido al fallo real.

Primero, prueba desde el mismo lugar que la aplicación

Probar desde tu portátil es útil, pero no demuestra que un pod de Kubernetes, una VM, un contenedor o un ejecutor de CI puedan alcanzar Redis. Comienza dentro de la misma ubicación de red que la aplicación que falla.

redis-cli -h redis.example.internal -p 6379 PING

Salida esperada:

PONG

Si Redis requiere TLS, usa las opciones TLS que espera tu despliegue:

redis-cli --tls -h redis.example.internal -p 6380 PING

Si Redis requiere autenticación:

redis-cli -u redis://app-user:[email protected]:6379 PING

Ten cuidado con las contraseñas en el historial del shell. Para producción, usa credenciales temporales o variables de entorno cuando sea posible.

Conexión rechazada

ECONNREFUSED, Connection refused o Could not connect to Redis generalmente significa que la conexión TCP alcanzó el host de destino, pero nada la aceptó en ese puerto. Las causas más comunes son simples:

  • Redis no está ejecutándose.
  • El cliente está usando el host o puerto incorrecto.
  • Redis está vinculado solo a localhost.
  • Un contenedor o mapeo de servicio apunta al puerto incorrecto.
  • Un cortafuegos rechaza activamente la conexión.

En el host de Redis, verifica el proceso y el listener:

redis-cli PING
ps aux | grep '[r]edis-server'
ss -ltnp | grep redis

Quieres ver a Redis escuchando en la dirección y puerto esperados, comúnmente 127.0.0.1:6379, 0.0.0.0:6379 o una dirección de interfaz privada.

Verifica redis.conf o la configuración efectiva:

redis-cli CONFIG GET bind
redis-cli CONFIG GET port
redis-cli CONFIG GET protected-mode

Si bind es 127.0.0.1, los clientes remotos no pueden conectarse directamente. Eso suele ser intencional. No lo cambies a 0.0.0.0 como solución rápida a menos que Redis esté protegido por autenticación, ACLs, reglas de cortafuegos y redes privadas. Redis expuesto en internet público es un incidente de seguridad grave a punto de ocurrir.

En Docker, recuerda la diferencia entre el puerto del contenedor y el puerto del host:

docker ps
docker port <redis-container>

Dentro de una red de Docker Compose, las aplicaciones generalmente se conectan al nombre del servicio y al puerto interno:

redis://redis:6379

Desde el host, pueden conectarse a un puerto publicado como localhost:6379 o localhost:6381, dependiendo del mapeo.

Tiempo de espera de conexión

Un tiempo de espera significa que el cliente esperó y no completó la operación a tiempo. A diferencia de las conexiones rechazadas, los tiempos de espera a menudo apuntan a un problema de ruta o un servidor ocupado.

Verifica la ruta TCP:

nc -vz redis.example.internal 6379
ping -c 5 redis.example.internal

ping no es perfecto porque ICMP puede estar bloqueado mientras TCP funciona, pero puede revelar errores obvios de DNS o enrutamiento. nc está más cerca de lo que necesita el cliente Redis.

Si TCP se conecta pero los comandos de Redis agotan el tiempo de espera, verifica si Redis está ocupado:

redis-cli INFO clients
redis-cli INFO stats
redis-cli INFO memory
redis-cli SLOWLOG GET 10
redis-cli LATENCY DOCTOR

Busca clientes bloqueados, recuentos altos de clientes conectados, memoria cerca de maxmemory, swap en el host, comandos lentos y eventos de latencia. Un solo comando costoso como KEYS *, un HGETALL grande o un script Lua largo puede retrasar clientes no relacionados porque la ejecución de comandos de Redis es en gran medida de un solo hilo.

También verifica la configuración de tiempo de espera del cliente. Algunas bibliotecas usan valores predeterminados cortos para tiempos de espera de conexión o de comandos. Aumentar el tiempo de espera puede reducir fallos falsos en una red lenta, pero no debe ocultar una instancia de Redis que está sobrecargada. Si un simple PING tarda segundos desde el host de la aplicación, soluciona eso antes de ajustar los reintentos.

Problemas de resolución de nombres y puntos finales incorrectos

No todos los errores de conexión son de Redis. DNS y el descubrimiento de servicios causan muchos de ellos.

Desde el host de la aplicación:

getent hosts redis.example.internal
nslookup redis.example.internal

En Kubernetes:

kubectl exec -it deploy/my-app -- sh
getent hosts redis.default.svc.cluster.local
nc -vz redis.default.svc.cluster.local 6379

Verifica si la aplicación está usando un punto final de réplica de lectura, un punto final de centinela, un punto final de clúster o un punto final de nodo directo. Los clientes de Redis Cluster necesitan bibliotecas conscientes del clúster porque las claves pueden pertenecer a diferentes slots y los comandos pueden recibir redirecciones. Un cliente no consciente del clúster puede conectarse exitosamente y luego fallar con errores MOVED o ASK una vez que envía comandos reales.

Errores de autenticación

Los fallos de autenticación se muestran como:

  • NOAUTH Authentication required
  • WRONGPASS invalid username-password pair
  • NOPERM this user has no permissions
  • Excepciones de autenticación específicas de la biblioteca cliente

Para Redis 6 y versiones posteriores, los usuarios ACL son comunes. Una cadena de conexión puede necesitar tanto nombre de usuario como contraseña:

redis://app-user:[email protected]:6379/0

Con el usuario predeterminado, algunos clientes usan solo una contraseña:

redis://:[email protected]:6379/0

Verifica la configuración del usuario activo si tienes acceso de administrador:

redis-cli ACL LIST
redis-cli ACL GETUSER app-user

NOAUTH significa que el cliente no se autenticó antes de emitir un comando. WRONGPASS significa que se intentó la autenticación pero fue rechazada. NOPERM significa que la autenticación funcionó, pero el usuario no tiene permiso para el comando, patrón de clave o canal Pub/Sub.

Cuando los secretos rotan, confirma que cada proceso en ejecución realmente recibió el nuevo valor. En plataformas de contenedores, actualizar un objeto secreto no siempre reinicia pods o procesos existentes. Un fallo común en el mundo real es que la mitad de la aplicación use la nueva contraseña y la mitad aún use la antigua.

Desajuste de TLS

Los errores de TLS pueden parecer reinicios de conexión, tiempos de espera o errores de protocolo ilegibles.

Verifica el puerto. Los servicios gestionados a menudo usan puertos diferentes para TLS y Redis sin TLS. Por ejemplo, un punto final puede esperar el protocolo Redis simple y otro puede esperar TLS desde el primer byte.

Prueba con:

redis-cli --tls -h redis.example.internal -p 6380 PING
redis-cli -h redis.example.internal -p 6379 PING

Si tu organización usa certificados privados, el cliente también puede necesitar un archivo CA:

redis-cli --tls --cacert /path/to/ca.pem -h redis.example.internal -p 6380 PING

En los registros de la aplicación, los errores de certificado suelen ser más claros que la excepción de Redis de nivel superior. Busca mensajes sobre autoridades desconocidas, certificados caducados, discrepancia de nombre de host o fallo de handshake.

Demasiadas conexiones

Redis tiene un límite de maxclients. El sistema operativo también tiene límites de descriptores de archivo. Cuando cualquiera de ellos se agota, los nuevos clientes pueden fallar o los clientes existentes pueden comportarse mal.

Verifica:

redis-cli INFO clients
redis-cli CONFIG GET maxclients
ulimit -n

Los campos útiles incluyen connected_clients, blocked_clients y rejected_connections de INFO stats.

Demasiadas conexiones generalmente provienen de uno de estos patrones:

  • Crear un nuevo cliente Redis por solicitud web.
  • No cerrar clientes en trabajos de corta duración.
  • Demasiados procesos de trabajo, cada uno con su propio grupo grande.
  • Suscripciones Pub/Sub que toman prestadas conexiones de un grupo de comandos normal.
  • Tormentas de reintentos durante un reinicio de Redis.

Arregla la forma de la aplicación antes de aumentar los límites. Usa un cliente compartido o un grupo acotado por proceso. Agrega un retroceso de reconexión con jitter para que cada instancia no se reconecte en el mismo milisegundo después de una interrupción.

Modo protegido y configuración de bind

El modo protegido de Redis está diseñado para reducir el daño de la exposición accidental. Si Redis está vinculado ampliamente y no tiene autenticación, el modo protegido puede rechazar conexiones remotas.

Verifica:

redis-cli CONFIG GET protected-mode
redis-cli CONFIG GET bind
redis-cli CONFIG GET requirepass

No deshabilites el modo protegido solo para hacer funcionar una conexión remota. El camino más seguro suele ser redes privadas más autenticación y una dirección de bind estrecha. Si Redis debe aceptar clientes remotos, colócalo en una subred privada, restringe las IP de origen, requiere credenciales y usa TLS cuando sea apropiado.

Un orden práctico de operaciones

Cuando una aplicación no puede conectarse, usa esta secuencia:

  1. Desde el entorno de la aplicación, ejecuta redis-cli PING contra el mismo host y puerto.
  2. Si es rechazado, verifica el proceso de Redis, listener, bind, puerto y mapeo del contenedor.
  3. Si se agota el tiempo de espera, verifica enrutamiento, reglas de cortafuegos, carga del servidor, comandos lentos y configuración de tiempo de espera del cliente.
  4. Si la autenticación falla, verifica nombre de usuario, contraseña, permisos ACL y despliegue de secretos.
  5. Si solo algunos comandos fallan, verifica permisos de comandos/claves ACL y redirecciones de Redis Cluster.
  6. Si los fallos ocurren bajo carga, verifica recuentos de conexiones, tamaño del grupo, reintentos y métricas de recursos del servidor.

La solución de problemas de conexión es principalmente recopilación de evidencia. Obtén un resultado limpio de CLI desde el mismo lugar que la aplicación, luego compáralo con lo que está haciendo la biblioteca cliente. Una vez que esos dos caminos difieren, la brecha suele ser visible: una bandera TLS faltante, una contraseña antigua, un nombre de servicio incorrecto o un grupo que crea muchas más conexiones de las que Redis fue dimensionado para manejar.

Leyendo errores de aplicación sin reaccionar de más

Las bibliotecas cliente envuelven los errores de Redis en su propio lenguaje. Un servicio Node.js puede mostrar ECONNRESET, un trabajador Python puede mostrar redis.exceptions.ConnectionError y un servicio Java puede reportar un tiempo de espera de adquisición del grupo. Todos pueden describir diferentes capas del mismo problema.

Sepáralos:

  • Tiempo de espera de conexión: la conexión TCP no se completó lo suficientemente rápido.
  • Tiempo de espera de lectura: la conexión existe, pero una respuesta de comando no llegó a tiempo.
  • Reinicio de conexión: la conexión fue cerrada por Redis, un proxy, la red o el par.
  • Tiempo de espera del grupo: la aplicación no pudo tomar prestada una conexión Redis de su propio grupo.
  • Error de autenticación: Redis rechazó las credenciales o permisos.

Un tiempo de espera del grupo es fácil de malinterpretar como una interrupción de Redis. A veces Redis está bien, pero la aplicación tomó prestadas todas las conexiones del grupo y nunca las devolvió. El mal uso de Pub/Sub puede causar esto. También comandos de bloqueo largos, manejadores de solicitudes que olvidan cerrar clientes o un grupo demasiado pequeño para la concurrencia del proceso.

Verifica ambos lados al mismo tiempo. En la aplicación, inspecciona las métricas del grupo si la biblioteca las expone: conexiones activas, conexiones inactivas, esperas, recuento de reintentos. En Redis, verifica:

redis-cli INFO clients
redis-cli CLIENT LIST | head

Si Redis muestra solo un puñado de clientes pero la aplicación dice que su grupo está agotado, el problema probablemente está dentro del proceso de la aplicación. Si Redis muestra miles de conexiones del mismo despliegue, el servicio puede estar creando clientes con demasiada frecuencia.

Los reintentos merecen atención especial. Un bucle de reconexión sin retroceso puede convertir un reinicio corto de Redis en una tormenta. Cada instancia de la aplicación intenta reconectarse inmediatamente, las autenticaciones y handshakes TLS se disparan, y Redis tiene que recuperarse mientras es golpeado por los clientes. Usa retroceso exponencial con jitter. También decide qué comandos son seguros de reintentar. Reintentar un GET de caché idempotente es diferente de reintentar una escritura que ya puede haber tenido éxito antes de que la conexión se cayera.

Para notas de incidentes, captura el texto exacto del error y el tiempo. "Redis estaba caído" a menudo es incorrecto. "De 14:03 a 14:06 UTC, los pods de la aplicación vieron tiempos de espera de lectura mientras la CPU de Redis estaba en un núcleo y SLOWLOG mostraba grandes llamadas HGETALL" es procesable.