-
Notifications
You must be signed in to change notification settings - Fork 0
외부 API 사용 시 선택할 수 있는 전략 ‐ 카카오 API 사례 기반
Myeongha Joo edited this page Jun 9, 2025
·
2 revisions
외부 API를 호출할 때, 서비스 상황과 성능 요구에 따라 다양한 호출 전략을 선택할 수 있습니다.
해당 글은 처리량을 테스트하기 위함이기 때문에 코드는 첨부하지 않겠습니다.
단계 | 전략 | 특징 |
---|---|---|
1단계 | RestClient (동기) | 간단한 호출, 블록킹 I/O, 처리량 낮음 |
2단계 | RestClient + 비동기 (ex. CompletableFuture) | 병렬 처리 가능, 하지만 RestClient 내부는 블록킹이므로 한계 존재 |
3단계 | WebClient (Reactive) | 비동기 논블로킹 I/O, 고성능 가능, 적절한 리액티브 설계 필요 |
동기적인 프로그래밍을 시작으로 사용량에 따라 점차 비동기 논블로킹 I/O로 전환하면 현재 서버의 리소스를 최대한 활용할 수 있습니다.
처음부터 WebClient를 사용하는 것도 좋은 방법이지만, 오버 엔지니어링이 될 수 있는 것 같습니다.
스프링에서 비동기 프로그래밍을 하는 경우에 Blocking I/O와 Non Blocking I/O가 있습니다.
정말 심플하게 이해를 돕기 위해 그렸습니다...ㅎㅎ
- 메인 Thread인 Tomcat Thread가 Blocking 되는 것을 막기 위해 내부의 Thread pool를 설정하여 해로운 스레드로 작업을 위임합니다.
- 그렇기때문에 Tomcat Thread는 다른 Request를 받아서 처리할 수 있게 됩니다.
- 대신 내부 스레드는 Blocking되어 있습니다.
출처: LG유플러스기술 블로그
- WebClient는 I/O 작업을 커널에게 위임합니다.
- 커널은 파일 디스크립터로 소켓 상태를 관리합니다.
- 소켓을 읽을 수 있는 상태가 되면 이벤트를 발생시켜 이벤트 루프가 처리하도록 합니다. 때문에 Thread Blocking없이 동작이 가능합니다.
이번 테스트에서는 카카오 로컬 API 를 비동기 논블로킹 I/O인 WebClient로 호출하는 경우와 RestClient(동기)로 호출하는 경우 2단계만 테스트를 진행하였습니다.
- 테스트 도구: JMeter
-
테스트 대상:
https://dapi.kakao.com/v2/local/search/keyword.json
- 테스트 환경: Tomcat Thread를 1개로 고정
- WebClient + Retry 적용: 카카오 api 쿼터제로 인해 예외가 발생하여 Retry를 적용하였습니다.
전략 / 조건 | 처리량 (Throughput) | 에러율 |
---|---|---|
RestClient + 기본 처리 | 21 req/sec | 0% |
WebClient + Retry | 264 req/sec | 30.37% (429 Too Many Requests 발생) |
RestClient 결과
WebClient 결과
- WebClient으로 처리한 경우 Throughput이 10배정도 차이나는 것을 볼 수 있습니다.
- 심지어 위 결과는 카카오 API의 초당 쿼터 제한이 존재하여 일정 이상부터 429(Too Many Requests) 발생 → Retry/Backoff 영향으로 Throughput이 감소한 상태였습니다.
- 정상 상황(쿼터 제한이 없다면)에서는 WebClient가 지금보다 훨씬 더 높은 처리량을 낼 수 있다고 생각합니다.
- 이번 결과는 API 제공자의 쿼터 정책 영향이 컸던 것
- WebClient 자체는 서버 리소스를 효율적으로 사용하는 구조이므로 스레드 풀 고갈 없이 많은 요청 처리가 가능합니다.
- WebClient 기반 구조는 충분히 높은 처리량을 낼 수 있지만 API 제공자의 쿼터 제한이 있는 경우에는 별도의 Retry/Backoff 설계가 중요합니다.
- Java Virtual Thread: 커널 수준의 Thread가 아니기 때문에 매우 가볍다는 특징이 있습니다.
- Kotlin: Kotlin의 코루틴은 비동기 처리를 위한 경량화된 실행 단위이며, Thread 단위가 아니라 여러 코루틴이 하나의 Thread 위에서 협력적으로 실행됩니다. 이를 통해 Thread blocking 없이 효율적인 리소스 사용이 가능합니다.