배경 및 목표
채용담당자가 인적성 검사 결과를 조회할 때, 외부 서비스에서 실시간으로 파일을 가져와 처리하는 구조였습니다. 최초 조회 시 파일 다운로드 + 파싱에 6초가 걸렸고, 그 동안 DB 커넥션을 점유하여 다른 요청에도 영향을 주었습니다.
목표
- 최초 조회 시 6초 지연·커넥션 점유를 없애고 즉시 응답한다.
- 롱 트랜잭션 없이 결과지를 사전 적재한다.
해결 방법과 해결 후보군
후보군 비교
| 방식 | 설명 | 한계 |
|---|---|---|
| 실시간 폴링 | 조회 시점에 외부 처리 | 6초 지연 + 커넥션 점유 |
| 조회 결과 캐싱 | 첫 조회 후 캐시 | 첫 조회는 여전히 6초 |
| 사전 배치 적재 (채택) | 미리 가져와 DB 적재 | 조회 즉시 응답, 롱 트랜잭션 제거 |
1. 사전 배치 처리 방식으로 전환
조회 시점에 외부 서비스를 호출하는 대신, 주기적 배치로 결과를 미리 가져와 DB에 적재하는 방식으로 변경했습니다.
fun preloadResults() {
val pendingIds = resultRepository.findPendingIds()
pendingIds.forEach { id ->
val result = externalClient.fetchResult(id)
if (result != null) {
resultRepository.save(result.toEntity())
}
}
}2. 조회 시 즉시 응답
채용담당자가 결과를 조회하면, 이미 적재된 데이터를 반환하므로 외부 호출이 불필요하고 DB 커넥션 점유 문제도 해소되었습니다.
결과
| 지표 | 기존 | 개선 |
|---|---|---|
| 결과 조회 | 6초 | 1초 이하 (83% 단축) |
| 커넥션 점유 | 길음 | 해소 |
| 롱 트랜잭션 | 발생 | 제거 |
모니터링
- 결과지 조회 응답시간(6초→1초 이하)과 커넥션 점유 시간을 관측한다.
- 사전 배치 처리 성공률·지연을 관측한다.