Redis 타임아웃, 원인은 Redis가 아니었다
Redis를 도입하고 나서 간헐적으로 타임아웃이 발생했다. 당연히 Redis가 느린 줄 알았는데, slow log를 확인해보니 비어있었다. Redis는 빠르게 응답하고 있었다. 그럼 뭐가 문제였을까?
Redis 도입 후 APP에서 간헐적으로 타임아웃 에러가 발생했다.
증상:
- APP에서 Redis 요청 타임아웃
- 특정 API에서만 발생
- Redis slow log는 비어있음
Redis가 느리면 slow log에 기록이 남아야 한다. 근데 비어있다? Redis는 정상이라는 뜻이다.
문제는 데이터 크기였다.
sequenceDiagram
participant APP as APP
participant Network as 네트워크
participant Redis as Redis
APP->>Network: GET all-codes
Network->>Redis: 요청 전송
Redis->>Redis: 처리 (5ms ✓)
Redis->>Network: 응답 (1MB)
Note over Network: 대용량 전송
Network->>APP: 데이터 수신
APP->>APP: 역직렬화
Note over APP: 3초 초과 → 타임아웃!
Redis slow log가 비어있던 이유:
- Redis 처리 시간은 5ms로 빠름 (slow log 기준 미달)
- 병목은 네트워크 전송과 APP의 역직렬화
Java에서 Redis 클라이언트로 많이 사용하는 Lettuce의 기본 타임아웃은 60초다.
| 항목 | 기본값 |
|---|---|
| Command Timeout | 60초 |
| Connection Timeout | 10초 |
하지만 APP에서 타임아웃을 더 짧게 설정하는 경우가 많다. 확인해보니 우리 APP은 3초로 설정되어 있었다.
|
|
sequenceDiagram
participant APP as APP
participant Redis as Redis
APP->>Redis: GET all-codes
Redis-->>APP: 1MB 응답 전송 중...
APP->>APP: 데이터 수신 + 역직렬화 중...
Note over APP: 3초 초과 → 타임아웃!
1MB 데이터를 네트워크로 받고 역직렬화하는데 3초 안에 끝나지 않아서 타임아웃이 발생한 것이다.
Redis에서 받은 JSON 문자열을 Java 객체로 변환하는 과정이다.
|
|
역직렬화가 오래 걸리는 이유:
- JSON 문자열 파싱 (구문 분석)
- 객체 1만 개 생성 (메모리 할당)
- 각 필드에 값 매핑
데이터가 크면 이 과정이 오래 걸려서 타임아웃이 발생한다.
확인해보니 문제가 되는 키의 데이터가 1MB 이상이었다.
# 정상 케이스
GET user:session:123 → 500 bytes → 정상
# 문제 케이스
GET all-codes → 1MB+ → 타임아웃
한 키에 너무 많은 데이터를 저장하고 있었다.
| 크기 | 판정 | 설명 |
|---|---|---|
| < 1KB | 최적 ✓ | 단일 객체, 세션 |
| 1KB ~ 10KB | 양호 ✓ | 작은 리스트, 캐시 |
| 10KB ~ 100KB | 주의 ⚠️ | 모니터링 필요 |
| 100KB ~ 1MB | 위험 ❌ | 분리 권장 |
| > 1MB | 금지 🚫 | 반드시 분리 |
Redis 기술적 한계는 512MB지만, 권장은 100KB 이하다.
1KB 전송: ~1ms
1MB 전송: ~수백ms (1000배 차이)
|
|
Redis 입장에서는 그냥 문자열을 GET 한 것뿐이다. 5ms면 충분히 빠르다. slow log에 남을 이유가 없다.
병목은 Redis 바깥에서 발생한다.
|
|
방법 1: 개별 키로 분리
|
|
방법 2: Hash 구조 활용
|
|
방법 3: 페이징
|
|
데이터 구조를 개선한 후 타임아웃이 사라졌다.
| 항목 | Before | After |
|---|---|---|
| 데이터 크기 | 1MB+ | < 10KB |
| 응답 시간 | 타임아웃 | < 10ms |
| 에러율 | 간헐적 발생 | 0% |
Redis 타임아웃이 발생했을 때:
- slow log 먼저 확인 - 비어있으면 Redis는 정상
- 데이터 크기 확인 - 100KB 이상이면 의심
- 병목 지점 파악 - 네트워크 전송, 역직렬화
- 데이터 구조 개선 - 분리, Hash, 페이징
Redis가 느린 게 아니라 데이터가 큰 것이 문제일 수 있다. slow log만 보고 “Redis는 정상이네?” 하고 넘어가면 안 된다.