최근에 공공데이터포털 아파트 실거래 조회 API를 이용해서 프론트엔드에서 거래 내역을 보여주는 프로젝트를 진행했다.
하지만 바로 부딪힌 문제는 속도와 중복 호출이었다.
- 응답 속도
- 정부 API 특성상 XML로 데이터를 내려주고, 이를 JSON으로 변환해야 했다.
- 네트워크도 느리고 응답 처리 과정까지 거치니 사용자가 같은 조건으로 여러 번 조회할 때마다 매번 느린 응답을 받아야 했다.
- 중복 호출
- 유저가 같은 조건(예: "강남구 2025년 9월")으로 여러 번 검색할 경우,
매번 정부 서버를 다시 치게 되어 불필요한 트래픽이 발생했다.
- 유저가 같은 조건(예: "강남구 2025년 9월")으로 여러 번 검색할 경우,
- 최근 검색 내역 없음
- "내가 조금 전에 검색했던 조건"을 다시 보려면,
유저가 직접 다시 입력해야 했다.
- "내가 조금 전에 검색했던 조건"을 다시 보려면,
👉 이 세 가지 문제를 해결하기 위해 Spring Boot + Redis 캐시를 도입하기로 했다.
- 캐시(Cache): 같은 조건으로 조회하면 일정 시간 동안은 Redis에서 바로 꺼내오기 → 빠른 응답
- 최근 검색(Recent List): 사용자가 조회한 조건을 Redis 리스트에 저장해 두고, 최근 검색 내역을 보여주기
전체적인 구조
[Frontend (Vite/React)]
│
▼
[Spring Boot (8081)]
- Redis Cache (@Cacheable)
- Redis List (최근 검색)
│
▼
[Node Proxy (8080, Express)]
- 공공데이터포털 API 호출
- XML → JSON 변환
│
▼
[Government Open API]
│
▼
[Redis (6379)]
- 캐시 저장소
- 최근 검색 내역 기록
동작 원리
- 프론트에서 /api/trades 호출
- Spring Boot가 먼저 Redis 캐시 확인
- 캐시 HIT → 바로 응답
- 캐시 MISS → Node 프록시 호출
- Node 프록시가 정부 API 호출 후 JSON 응답으로 정규화
- Spring Boot가 받은 결과를 Redis에 저장
- 캐시: TTL 2분
- 최근 검색: Redis List로 기록 (최대 20개, 7일 TTL)
- 프론트에서 /api/recent 호출 시 Redis에 쌓인 최근 검색 내역 응답
아키텍처 다이어그램
┌───────────────────────────────┐
│ Frontend (5173) │
│ React / Vite / TS │
└───────────────▲───────────────┘
│ fetch /api/*
│
┌───────────────┴───────────────┐
│ Spring Boot (8081) │
│ - @Cacheable (Redis Cache) │
│ - 최근검색 (Redis List) │
└───────────────▲───────────────┘
│ REST call
┌───────────────┴───────────────┐
│ Node Proxy (8080, Express) │
│ - 공공데이터포털 API 호출 │
│ - XML → JSON 변환 │
└───────────────▲───────────────┘
│
┌───────────────┴───────────────┐
│ Government Open API (RTMS) │
└───────────────────────────────┘
┌───────────────────────────────┐
│ Redis (6379) │
│ - Cache (2분 TTL) │
│ - 최근검색 리스트(20개, 7일) │
└───────────────────────────────┘
컨트롤러
package com.example.redis_demo.api;
import com.example.redis_demo.dto.TradeListResp;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class DealController {
private final DealService service;
@GetMapping("/trades")
public TradeListResp trades(
@RequestParam String sgg,
@RequestParam String ym,
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size,
@RequestHeader(value = "X-User-Id", required = false) String userId
) {
return service.getDeals(sgg, ym, page, size, userId);
}
@GetMapping("/recent")
public List<String> recent(
@RequestParam(defaultValue = "10") int limit,
@RequestHeader(value = "X-User-Id", required = false) String userId
) {
return service.getRecent(userId, limit);
}
}
'개발로 사고하기' 카테고리의 다른 글
| [error 해결기] React 페이지네이션 시 이전 데이터가 화면에 남는 문제 (0) | 2025.10.02 |
|---|---|
| 서울시 열린 데이터 광장 공공데이터 Open API 신청 & 활용 (0) | 2025.10.02 |
| 국토교통부 아파트 실거래가 API 활용기 (1) | 2025.09.25 |
| 😤 CORS? 403? API 호출 대참사 해결기 (0) | 2025.09.11 |
| 🚨 Spring Boot Kafka 개발 중 “No qualifying bean” 에러 해결기 (0) | 2025.09.07 |