리드 타임아웃
서버와 연결된 후, 응답 데이터를 수신하기까지 기다리는 최대 시간입니다. 이 시간 내에 응답이 없으면 에러가 발생합니다.
왜 필요한가?
- 서버가 응답을 안 줄 때 무한정 대기 방지
- 느린 서버로 인한 장애 전파 차단
- 클라이언트 리소스 보호
동작 방식
클라이언트 ── 연결 완료 ──▶ 서버
│ │
│──── 요청 전송 ───────▶│
│ │ 서버 처리 중...
│ Read Timeout │
│ (예: 5초) │
│ │
│ 5초 내 응답 없으면 │
└─── ReadTimeoutException 발생
커넥션 타임아웃 vs 리드 타임아웃
| 항목 | Connection Timeout | Read Timeout |
| 시점 | 연결 수립 | 데이터 수신 |
| 질문 | "연결할 수 있나?" | "응답이 오나?" |
| 원인 | 서버 다운, 방화벽 | 서버 과부하, 느린 쿼리 |
| 권장값 | 1~3초 | 3~30초 |
[전체 흐름]
연결 시도 ──▶ 연결 완료 ──▶ 요청 전송 ──▶ 응답 수신
│ │ │
Connection 연결 성공 Read
Timeout Timeout
설정 예시
RestTemplate (Spring)
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(3000); // 연결 3초
factory.setReadTimeout(10000); // 응답 대기 10초
RestTemplate restTemplate = new RestTemplate(factory);
WebClient (Spring WebFlux)
HttpClient httpClient = HttpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000)
.responseTimeout(Duration.ofSeconds(10)); // 리드 타임아웃
WebClient client = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
JDBC
String url = "jdbc:mysql://localhost:3306/db" +
"?connectTimeout=3000" + // 연결
"&socketTimeout=10000"; // 읽기/쓰기
리드 타임아웃 발생 원인
1. 서버 과부하 → 처리 지연
2. 느린 DB 쿼리
3. 외부 API 호출 지연
4. 대용량 데이터 처리
5. 네트워크 지연
적절한 설정값
| 상황 | 권장값 |
| 일반 API 호출 | 3~5초 |
| 복잡한 조회 | 10~15초 |
| 파일 업로드/다운로드 | 30초 이상 |
| 배치 작업 | 작업에 맞게 |
주의점
// X 타임아웃 없이 무한 대기
restTemplate.getForObject(url, String.class);
// O 항상 타임아웃 설정
factory.setReadTimeout(5000);
- 타임아웃 미설정 시 무한 대기 가능
- 장애 시 스레드/커넥션 고갈 위험