Spring 프로젝트에서 외부 API 호출을 기존 RestTemplate과 자체 HTTP Client로 처리하고 있었다.
API 호출 코드가 늘어나면서 유지보수와 테스트가 점점 불편해져서
OpenFeign으로 전환하는 리팩토링을 진행했다.
전환 과정에서 외부 API 장애로 인한 서버 부하를 줄이기 위해
Resilience4j를 적용해 서킷 브레이커 패턴도 함께 적용했다.
이 글은 RestTemplate 기반 외부 API 호출을
OpenFeign + Resilience4j 구조로 리팩토링한 기록이다.
[핵심 요약]
1. 자체 HTTP Client 및 RestTemplate을 OpenFeign으로 전환
- 기존에는 RestTemplate이나 직접 구현한 HTTP Client를 사용하여 외부 API를 호출했지만, 이를 OpenFeign으로 변경했다.
- OpenFeign을 사용하면 API 호출을 인터페이스 기반으로 선언형으로 작성할 수 있어 코드가 간결해지고 유지보수가 쉬워진다.
- 테스트 시에도 API 호출을 Mock 객체로 대체하기 쉬워 테스트 용이성이 증가한다.
2. OpenFeign + Resilience4j로 서킷 브레이커 패턴 적용
- 기존 HTTP Client에서 네트워크 장애가 발생하면, 응답 시간이 지연되거나 서버 부하가 증가하는 문제가 있었다.
- 이를 Resilience4j의 서킷 브레이커 패턴을 활용해 해결했다.
- OpenFeign을 사용할 때 Resilience4j를 적용하면, 장애 발생 시 즉시 실패 처리하고, 특정 시간 동안 API 호출을 차단하여 서버가 과부하되지 않도록 보호한다.
1. [Before] 기존 RestTemplate 사용 방식 (예시)
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.http.ResponseEntity;
@Service
public class UserService {
private final RestTemplate restTemplate = new RestTemplate();
public String getUserInfo(Long userId) {
String url = "http://localhost:8080/users/" + userId;
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
return response.getBody();
}
}
[문제점]
- HTTP 요청을 직접 생성해야 하고, 예외 처리 및 장애 대응을 수동으로 구현해야 한다.
- API 호출 코드가 많아지고 테스트하기 어렵다.
2. [After] OpenFeign 적용 방식
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name = "userClient", url = "https://api.example.com")
public interface UserClient {
@GetMapping("/users/{id}")
String getUserInfo(@PathVariable("id") Long userId);
}
[장점]
- API 호출 로직이 인터페이스 선언만으로 간결해진다.
- 테스트 시 이 인터페이스를 Mock 객체로 대체가 가능하다.
3. [Resilience4j 적용] 서킷 브레이커 추가
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import org.springframework.stereotype.Service;
@Service
public class UserService {
private final UserClient userClient;
public UserService(UserClient userClient) {
this.userClient = userClient;
}
@CircuitBreaker(name = "userService", fallbackMethod = "fallbackUserInfo")
public String getUserInfo(Long userId) {
return userClient.getUserInfo(userId);
}
public String fallbackUserInfo(Long userId, Throwable t) {
return "Default User Info"; // 장애 발생 시 기본 응답 반환
}
}
[서킷 브레이커 기능]
- API 요청이 반복적으로 실패하면, 일정 기간 동안 요청을 차단하여 서버 과부하를 방지한다.
- 장애 발생 시 fallbackUserInfo() 메서드를 호출하여 기본 응답을 반환한다.
- Resilience4j 덕분에 안정적인 API 호출 구조를 유지할 수 있다.
4. 결론
- 기존의 HTTP Clinet, RestTemplate을 OpenFeign으로 전환하여 코드를 간결화하고 테스트 용이성을 증가시켰다.
- OpenFeign에 Resilience4j 서킷 브레이커 패턴을 적용하여, API 장애 발생 시 즉시 실패 처리하고 서버 과부하를 방지한다.
정리하면, 외부 API 호출이 많은 Spring 프로젝트에서는 RestTemplate 기반 구조보다
OpenFeign + Resilience4j 조합이 유지보수와 안정성 측면에서 훨씬 효과적이었다.
'웹 개발 > Spring&JPA' 카테고리의 다른 글
| [트러블슈팅] EC2 서버 멀쩡한데 서비스가 전부 안 될 때: SSL 인증서 만료였다 (0) | 2026.01.13 |
|---|---|
| [트러블슈팅] Spring @Conditional 사용 시 PostConstruct로 빈 등록 실패한 이유 (1) | 2025.04.05 |
| [트러블슈팅] PostgreSQL 한글 정렬 안 되는 문제 해결 (Collation 설정) (0) | 2025.02.04 |
| [Spring Data JPA] 영속성 컨텍스트(Persistence Context)와 엔티티 생명주기 (0) | 2024.08.30 |
| [Spring Boot 3] P6Spy SQL 로그 포맷 커스터마이징 및 파일 로그 설정 (0) | 2024.08.29 |