외부 공공 API 응답 시간 13초 → 4ms로 개선한 과정
약 검색 API의 응답 시간을 13초에서 4ms로 개선한 과정을 정리한다. 측정 → 타임아웃 → 병렬화 → 캐싱 → 재시도 → 서킷브레이커, 6단계에 걸쳐 외부 API 의존성을 최적화했다. 배경 사이드 프로젝트에서 공공 데이터 포털(data.go.kr)의 약 검색 API 3종을 호출하는 기능을 만들었다. 문제는 한 번의 검색에 외부 API를 최...
약 검색 API의 응답 시간을 13초에서 4ms로 개선한 과정을 정리한다. 측정 → 타임아웃 → 병렬화 → 캐싱 → 재시도 → 서킷브레이커, 6단계에 걸쳐 외부 API 의존성을 최적화했다. 배경 사이드 프로젝트에서 공공 데이터 포털(data.go.kr)의 약 검색 API 3종을 호출하는 기능을 만들었다. 문제는 한 번의 검색에 외부 API를 최...
외부 API가 죽었을 때, 내 서비스까지 죽지 않으려면 어떻게 해야 할까? Circuit Breaker 패턴의 동작 원리, 3가지 상태 전이, Sliding Window 방식별 트레이드오프, 그리고 Resilience4j로의 구현까지 정리한다. Cascading Failure (연쇄 장애) Circuit Breaker를 이해하려면 먼저 왜 필요...
캐싱 패턴 3가지 Cache-Aside (Lazy Loading) 가장 일반적인 패턴입니다. 애플리케이션이 직접 캐시를 관리합니다. 읽기 흐름: 1. 캐시에서 조회 → 있으면 반환 (Cache Hit) 2. 없으면 DB/API에서 조회 (Cache Miss) 3. 결과를 캐시에 저장 4. 결과를 반환 클라이언트 → 애플리케이션 → 캐시 확인 ...
CompletableFuture 기본 개념 CompletableFuture는 Java 8에서 도입된 비동기 프로그래밍 API입니다. 기존 Future는 결과를 get()으로 블로킹해서 가져와야 했지만, CompletableFuture는 콜백 체이닝으로 비동기 흐름을 구성할 수 있습니다. supplyAsync - 비동기 작업 시작 // 별도 스레...
performance_schema.data_locks를 조회하면 LOCK_TYPE과 LOCK_MODE라는 두 컬럼이 나온다. 이 글을 읽으면 각 값이 무엇을 잠그는지, 서로 어떤 관계인지, 왜 이렇게 설계되었는지를 이해할 수 있다. 먼저 혼동을 정리하자 data_locks 테이블의 결과를 처음 보면 이런 의문이 생긴다. | LOCK_TYPE ...
TCP 3-way Handshake와 Connect Timeout TCP 3-way Handshake란 HTTP 요청을 보내기 전에, 클라이언트와 서버는 먼저 TCP 연결을 수립해야 합니다. 이 과정이 3-way Handshake입니다. 클라이언트 서버 | ---- SYN --------> |...
리뷰 복사 기능은 상위리뷰 데이터를 그대로 복사하는 기능으로, 데이터 양에 따라 최대 2시간 이상 소요되는 무거운 작업이에요. 이 기능을 동기 API에서 Kafka 기반 비동기 처리로 마이그레이션한 과정을 공유합니다. 왜 비동기 처리가 필요했나? 기존에는 리뷰 복사 요청이 들어오면 API 서버에서 직접 복사 작업을 수행하고, 완료될 때까지 응답...
TL;DR Kafka 컨슈머들이 동일 테이블에 DELETE + INSERT를 병렬로 수행하면서 REPEATABLE READ의 gap lock 때문에 데드락이 발생했다. 처음에는 서브쿼리가 원인이라고 판단했다. 하지만 performance_schema.data_locks로 실제 락을 비교한 결과, 서브쿼리 제거는 효과가 없었다. 근본 원인은 격리 수...
문자열 키(“korName”)로 객체의 프로퍼티 값을 가져와야 한다면, 어떻게 하시겠어요? 리플렉션? ObjectMapper? 이 글에서는 Spring MVC가 @ModelAttribute에서 사용하는 BeanWrapper를 인사카드 시스템에 활용한 경험을 공유합니다. 왜 런타임에 필드를 결정해야 했나? API 응답 구조의 특징 클라이언트에 내...
문제 상황 로컬 환경에서 할일 알림이 DB에 저장되지 않는 문제가 발생했습니다. 신기하게도 DEV, PROD 환경에서는 정상적으로 동작하고 있었고, 최신 DB 스냅샷과 dev 브랜치로 업데이트해도 문제가 지속되었습니다. 디버깅 과정 먼저 디버거를 통해 데이터 흐름을 확인했습니다. 디버깅 결과 데이터가 정상적으로 저장되는 것을 확인할 수 있...