Redis 연결 오류 효과적으로 해결하기

Redis 연결 문제로 어려움을 겪고 계신가요? 이 실용적인 가이드는 '연결 거부', '시간 초과', '인증 실패'와 같은 일반적인 오류를 진단하고 해결하는 명확한 단계를 제공합니다. 서버 상태, 네트워크 구성, 방화벽 및 Redis 성능 메트릭을 확인하는 방법을 알아보세요. `redis-cli` 및 클라이언트 라이브러리를 위한 실행 가능한 예제를 포함하여 Redis 연결을 효율적으로 복구할 수 있습니다.

Redis 연결 오류 효과적으로 해결하기

Redis 연결 오류는 일반적으로 세 가지 질문으로 나누면 명확해집니다: 클라이언트가 호스트와 포트에 도달할 수 있는지, Redis가 연결을 수락하는지, 연결 후 클라이언트가 명령을 실행할 수 있는지 여부입니다.

순서대로 진행하세요. Redis가 중지되었을 때 애플리케이션 코드로 바로 뛰어드는 것은 시간 낭비입니다. 비밀번호가 잘못되었을 때 방화벽 규칙을 다시 구축하는 것도 시간 낭비입니다. 작고 반복 가능한 체크리스트를 사용하면 실제 실패 지점에 더 빨리 도달할 수 있습니다.

먼저, 애플리케이션과 동일한 위치에서 테스트하세요

노트북에서 테스트하는 것은 유용하지만, Kubernetes 파드, VM, 컨테이너 또는 CI 실행기가 Redis에 도달할 수 있다는 것을 증명하지는 않습니다. 실패하는 애플리케이션과 동일한 네트워크 위치 내에서 시작하세요.

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

예상 출력:

PONG

Redis에 TLS가 필요한 경우, 배포에서 예상하는 TLS 옵션을 사용하세요:

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

Redis에 인증이 필요한 경우:

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

셸 기록에 비밀번호가 남지 않도록 주의하세요. 프로덕션에서는 가능하면 임시 자격 증명이나 환경 변수를 사용하세요.

연결 거부

ECONNREFUSED, Connection refused 또는 Could not connect to Redis는 일반적으로 TCP 연결이 대상 호스트에 도달했지만 해당 포트에서 수락하는 것이 없음을 의미합니다. 가장 일반적인 원인은 간단합니다:

  • Redis가 실행 중이 아닙니다.
  • 클라이언트가 잘못된 호스트 또는 포트를 사용하고 있습니다.
  • Redis가 localhost에만 바인딩되어 있습니다.
  • 컨테이너 또는 서비스 매핑이 잘못된 포트를 가리키고 있습니다.
  • 방화벽이 연결을 적극적으로 거부합니다.

Redis 호스트에서 프로세스와 리스너를 확인하세요:

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

Redis가 예상 주소와 포트(일반적으로 127.0.0.1:6379, 0.0.0.0:6379 또는 개인 인터페이스 주소)에서 수신 대기 중인지 확인해야 합니다.

redis.conf 또는 유효한 구성을 확인하세요:

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

bind127.0.0.1이면 원격 클라이언트가 직접 연결할 수 없습니다. 이는 종종 의도적입니다. Redis가 인증, ACL, 방화벽 규칙 및 개인 네트워킹으로 보호되지 않는 한 빠른 수정으로 0.0.0.0으로 변경하지 마세요. 공용 인터넷에 노출된 Redis는 심각한 보안 사고가 발생할 수 있습니다.

Docker에서는 컨테이너 포트와 호스트 포트의 차이를 기억하세요:

docker ps
docker port <redis-container>

Docker Compose 네트워크 내에서 애플리케이션은 일반적으로 서비스 이름과 내부 포트에 연결합니다:

redis://redis:6379

호스트에서 매핑에 따라 localhost:6379 또는 localhost:6381과 같은 게시된 포트에 연결할 수 있습니다.

연결 시간 초과

시간 초과는 클라이언트가 대기했지만 제 시간에 작업을 완료하지 못했음을 의미합니다. 연결 거부와 달리 시간 초과는 종종 경로 문제나 서버 과부하를 나타냅니다.

TCP 경로를 확인하세요:

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

ping은 완벽하지 않습니다. ICMP가 차단될 수 있지만 TCP는 작동할 수 있기 때문입니다. 그러나 명백한 DNS 또는 라우팅 실수를 드러낼 수 있습니다. nc는 Redis 클라이언트가 필요로 하는 것에 더 가깝습니다.

TCP가 연결되지만 Redis 명령이 시간 초과되면 Redis가 바쁜지 확인하세요:

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

차단된 클라이언트, 높은 연결 클라이언트 수, maxmemory에 가까운 메모리, 호스트의 스왑, 느린 명령 및 지연 이벤트를 찾으세요. KEYS *, 큰 HGETALL 또는 긴 Lua 스크립트와 같은 단일 비용이 많이 드는 명령은 Redis 명령 실행이 대부분 단일 스레드이기 때문에 관련 없는 클라이언트를 지연시킬 수 있습니다.

또한 클라이언트 시간 초과 설정을 확인하세요. 일부 라이브러리는 연결 시간 초과 또는 명령 시간 초과에 대해 짧은 기본값을 사용합니다. 시간 초과를 늘리면 느린 네트워크에서 잘못된 실패를 줄일 수 있지만 과부하된 Redis 인스턴스를 숨겨서는 안 됩니다. 애플리케이션 호스트에서 간단한 PING이 몇 초 걸리면 재시도를 조정하기 전에 먼저 해결하세요.

이름 확인 및 잘못된 엔드포인트 문제

모든 연결 오류가 Redis인 것은 아닙니다. DNS 및 서비스 검색이 많은 원인을 제공합니다.

애플리케이션 호스트에서:

geten hosts redis.example.internal
nslookup redis.example.internal

Kubernetes에서:

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

애플리케이션이 읽기 복제본 엔드포인트, 센티널 엔드포인트, 클러스터 엔드포인트 또는 직접 노드 엔드포인트를 사용하고 있는지 확인하세요. Redis Cluster 클라이언트는 클러스터 인식 라이브러리가 필요합니다. 키가 다른 슬롯에 속할 수 있고 명령이 리디렉션을 받을 수 있기 때문입니다. 클러스터를 인식하지 못하는 클라이언트는 성공적으로 연결한 다음 실제 명령을 보내면 MOVED 또는 ASK 오류와 함께 실패할 수 있습니다.

인증 오류

인증 실패는 다음과 같이 나타납니다:

  • NOAUTH Authentication required
  • WRONGPASS invalid username-password pair
  • NOPERM this user has no permissions
  • 클라이언트 라이브러리별 인증 예외

Redis 6 이상에서는 ACL 사용자가 일반적입니다. 연결 문자열에는 사용자 이름과 비밀번호가 모두 필요할 수 있습니다:

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

기본 사용자의 경우 일부 클라이언트는 비밀번호만 사용합니다:

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

관리자 액세스 권한이 있는 경우 활성 사용자 구성을 확인하세요:

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

NOAUTH는 클라이언트가 명령을 실행하기 전에 인증하지 않았음을 의미합니다. WRONGPASS는 인증이 시도되었지만 거부되었음을 의미합니다. NOPERM은 인증이 작동했지만 사용자에게 명령, 키 패턴 또는 Pub/Sub 채널에 대한 권한이 없음을 의미합니다.

비밀이 순환될 때 실행 중인 모든 프로세스가 실제로 새 값을 받았는지 확인하세요. 컨테이너 플랫폼에서 비밀 객체를 업데이트해도 기존 파드나 프로세스가 항상 다시 시작되는 것은 아닙니다. 일반적인 실제 실패는 애플리케이션의 절반이 새 비밀번호를 사용하고 나머지 절반이 여전히 이전 비밀번호를 사용하는 경우입니다.

TLS 불일치

TLS 오류는 연결 재설정, 시간 초과 또는 읽을 수 없는 프로토콜 오류처럼 보일 수 있습니다.

포트를 확인하세요. 관리형 서비스는 종종 TLS 및 비TLS Redis에 대해 다른 포트를 사용합니다. 예를 들어, 한 엔드포인트는 일반 Redis 프로토콜을 예상하고 다른 엔드포인트는 첫 번째 바이트부터 TLS를 예상할 수 있습니다.

다음으로 테스트하세요:

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

조직에서 개인 인증서를 사용하는 경우 클라이언트에 CA 파일도 필요할 수 있습니다:

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

애플리케이션 로그에서 인증서 오류는 최상위 Redis 예외보다 더 명확한 경우가 많습니다. 알 수 없는 인증 기관, 만료된 인증서, 호스트 이름 불일치 또는 핸드셰이크 실패에 대한 메시지를 찾으세요.

너무 많은 연결

Redis에는 maxclients 제한이 있습니다. 운영 체제에도 파일 디스크립터 제한이 있습니다. 둘 중 하나가 소진되면 새 클라이언트가 실패하거나 기존 클라이언트가 제대로 작동하지 않을 수 있습니다.

확인:

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

유용한 필드에는 connected_clients, blocked_clientsINFO statsrejected_connections이 포함됩니다.

너무 많은 연결은 일반적으로 다음 패턴 중 하나에서 발생합니다:

  • 웹 요청당 새 Redis 클라이언트 생성.
  • 단기 작업에서 클라이언트를 닫지 않음.
  • 각각 자체 대규모 풀이 있는 너무 많은 작업자 프로세스.
  • 일반 명령 풀에서 연결을 차용하는 Pub/Sub 구독.
  • Redis 재시작 중 재시도 폭풍.

한도를 높이기 전에 애플리케이션 형태를 수정하세요. 프로세스당 하나의 공유 클라이언트 또는 제한된 풀을 사용하세요. 지터가 있는 재연결 백오프를 추가하여 모든 인스턴스가 중단 후 동시에 재연결되지 않도록 하세요.

보호 모드 및 바인드 설정

Redis 보호 모드는 우발적인 노출로 인한 피해를 줄이기 위해 설계되었습니다. Redis가 광범위하게 바인딩되고 인증이 없는 경우 보호 모드는 원격 연결을 거부할 수 있습니다.

확인:

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

원격 연결을 작동시키기 위해 보호 모드를 비활성화하지 마세요. 더 안전한 경로는 일반적으로 개인 네트워킹과 인증 및 좁은 바인드 주소입니다. Redis가 원격 클라이언트를 수락해야 하는 경우 개인 서브넷에 배치하고, 소스 IP를 제한하고, 자격 증명을 요구하고, 적절한 경우 TLS를 사용하세요.

실용적인 작업 순서

애플리케이션이 연결할 수 없는 경우 다음 순서를 사용하세요:

  1. 애플리케이션 환경에서 동일한 호스트와 포트에 대해 redis-cli PING을 실행합니다.
  2. 거부된 경우 Redis 프로세스, 리스너, 바인드, 포트 및 컨테이너 매핑을 확인합니다.
  3. 시간 초과된 경우 라우팅, 방화벽 규칙, 서버 부하, 느린 명령 및 클라이언트 시간 초과 설정을 확인합니다.
  4. 인증이 실패하면 사용자 이름, 비밀번호, ACL 권한 및 비밀 롤아웃을 확인합니다.
  5. 일부 명령만 실패하면 ACL 명령/키 권한 및 Redis Cluster 리디렉션을 확인합니다.
  6. 부하가 걸릴 때 실패가 발생하면 연결 수, 풀 크기, 재시도 및 서버 리소스 메트릭을 확인합니다.

연결 문제 해결은 주로 증거 수집입니다. 앱과 동일한 위치에서 깨끗한 CLI 결과를 얻은 다음 클라이언트 라이브러리가 수행하는 작업과 비교하세요. 두 경로가 다르면 일반적으로 차이가 보입니다: 누락된 TLS 플래그, 오래된 비밀번호, 잘못된 서비스 이름 또는 Redis가 처리하도록 크기가 조정된 것보다 훨씬 많은 연결을 생성하는 풀입니다.

과도하게 반응하지 않고 애플리케이션 오류 읽기

클라이언트 라이브러리는 Redis 오류를 자체 언어로 래핑합니다. Node.js 서비스는 ECONNRESET을 표시하고, Python 작업자는 redis.exceptions.ConnectionError를 표시하며, Java 서비스는 풀 획득 시간 초과를 보고할 수 있습니다. 이들은 모두 동일한 문제의 다른 계층을 설명할 수 있습니다.

분리하세요:

  • 연결 시간 초과: TCP 연결이 충분히 빨리 완료되지 않았습니다.
  • 읽기 시간 초과: 연결이 존재하지만 명령 응답이 제 시간에 도착하지 않았습니다.
  • 연결 재설정: Redis, 프록시, 네트워크 또는 피어에 의해 연결이 종료되었습니다.
  • 풀 시간 초과: 애플리케이션이 자체 풀에서 Redis 연결을 빌릴 수 없습니다.
  • 인증 오류: Redis가 자격 증명 또는 권한을 거부했습니다.

풀 시간 초과는 Redis 중단으로 오해하기 쉽습니다. 때로는 Redis는 괜찮지만 애플리케이션이 모든 풀 연결을 빌려서 반환하지 않았습니다. Pub/Sub 오용이 이를 유발할 수 있습니다. 또한 긴 차단 명령, 클라이언트를 닫는 것을 잊어버린 요청 핸들러 또는 프로세스의 동시성에 비해 너무 작은 풀도 원인이 될 수 있습니다.

양쪽을 동시에 확인하세요. 애플리케이션에서 라이브러리가 노출하는 경우 풀 메트릭을 검사하세요: 활성 연결, 유휴 연결, 대기자, 재시도 횟수. Redis에서 확인:

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

Redis가 소수의 클라이언트만 표시하지만 애플리케이션이 풀이 소진되었다고 말하면 문제는 아마도 애플리케이션 프로세스 내부에 있을 것입니다. Redis가 동일한 배포에서 수천 개의 연결을 표시하면 서비스가 너무 자주 클라이언트를 생성하고 있을 수 있습니다.

재시도는 특별한 주의가 필요합니다. 백오프 없는 재연결 루프는 짧은 Redis 재시작을 폭풍으로 바꿀 수 있습니다. 모든 애플리케이션 인스턴스가 즉시 재연결을 시도하고, 인증 및 TLS 핸드셰이크가 급증하며, Redis는 클라이언트의 공격을 받으면서 복구해야 합니다. 지터가 있는 지수 백오프를 사용하세요. 또한 어떤 명령을 재시도해도 안전한지 결정하세요. 멱등성 캐시 GET을 재시도하는 것은 연결이 끊어지기 전에 이미 성공했을 수 있는 쓰기를 재시도하는 것과 다릅니다.

인시던트 노트의 경우 정확한 오류 텍스트와 타이밍을 캡처하세요. "Redis가 다운되었습니다"는 종종 잘못된 것입니다. "14:03부터 14:06 UTC까지 앱 파드가 읽기 시간 초과를 보았고 Redis CPU는 한 코어였으며 SLOWLOG는 큰 HGETALL 호출을 보여주었습니다"는 실행 가능한 정보입니다.