앞서 동일 사용자가 같은 요청을 여러 번 보내는 상황에 대비해, 결제 준비 및 결제 승인 API에 멱등키(user_id)를 적용해 요청을 멱등하게 처리하도록 설계하였다. (이전 글 : https://www.nextblog.me/parkmineum/299303e2-5222-8028-9949-d48dbc75cb8f )
결제 과정에서 발생하는 타임아웃은 다음 두 가지로 구분된다. 이 중 가장 위험한 상황은, PG에서는 결제가 완료되었지만 우리 서버는 이를 인지하지 못하는 경우다. 이때 시스템은 실제 결제와 다른 상태를 기록하게 되어 정합성 깨짐과 동시에 사용자 경험 저하로 이어진다. UNKNOWN(알 수 없음)은 네트워크 장애·타임아웃으로 인해 PG의 최종 상태를 확인할 수 없는 경우에 발생한다.
메인 글에서 다루지 않은 것들을 다루는 글이다. HTTP 메서드에도 멱등성이 존재한다. GET, PUT은 여러 번 호출해도 서버 상태가 변하지 않기 때문에 호출 결과가 항상 동일하다. 반면 POST, PATCH 처럼 서버 상태를 바꾸는 메서드는 기본적으로 멱등하지 않기에, 서버 측 구현을 통해 멱등성을 따로 보장해야 한다.
모임원의 설문 결과를 기반으로 외부 API로 데이터를 받아오는데, 이 과정에서 모임당 평균 20회 가량의 연쇄적인 API 호출이 발생한다. 요청 처리 시간 대부분이 네트워크 I/O 대기 시간으로 소비되는 구조이므로, 이 모든 시간이 요청 스레드에서 그대로 대기 시간으로 전환되고, 이 과정에서 스레드는 계속 점유된 상태로 유지된다.
동일한 식별자에 대해 복수의 row가 존재하는 데이터 무결성 위반 문제가 발생했다. 우리 시스템은 사용자당 하나의 FCM 토큰만 존재한다는 전제 하에 User - FcmToken을 @OneToOne 관계로 설계했다. Hibernate는 식별자 기반 조회 시 단일 row를 전제로 동작하기 때문에, 조회 결과가 복수로 반환되자 이를 비정상 상태로 판단하고 예외를 발생시킨 것이다.
이건 부하 테스트 정리글 에서 측정했었던 테스트 결괏값이고, RPS 60부터 평균 응답시간과 p95 지연이 눈에 띄게 증가하기 시작하며 시스템이 포화 지점에 근접하고 있음을 보여준다. 이 구간은 단순한 트래픽 증가가 아니라, 내부 자원(DB, 커넥션 풀, 스레드 등)의 병목이 드러나기 시작하는 경계 구간으로 볼 수 있다.
레플리케이션 환경에서는 트랜잭션의 속성(ReadOnly 여부 등)에 따라 Master / Replica(DataSource)를 동적으로 선택해야 한다. 이를 위해 스프링에서는 동적 라우팅을 위한 AbstractRoutingDataSource를 제공한다. AbstractRoutingDataSource는 DataSource 인터페이스의 구현체로, 여러 DataSource를 하나로 묶고, 런타임에 실제 사용할 DataSource를 결정하는 역할을 한다.
말 그대로 하나의 큰 애플리케이션을 여러 개의 독립적인 모듈로 나눠 관리하는 구조로, 각 모듈은 도메인이나 계층 단위로 역할을 명확히 나누고, 필요한 부분만 서로 의존하도록 구성된다. 멀티모듈의 핵심은 모듈 간 의존성은 단방향을 유지하며, 상위 계층이 하위 계층을 의존하는 구조로, 하위 모듈은 상위 모듈의 구현이나 내부를 알지 못해야 한다.
Nginx 내부의 프로세스 동작 과정은 ‘페이지’로 첨부하였고, 여기에선 무중단 배포 전체 플로우와 Graceful Shutdown 도입 이유, 고트래픽 상황에서의 대응 방안들을 정리하였다.
MDC는 각 요청 흐름에 고유한 컨텍스트를 부여하고, 해당 요청에서 발생하는 모든 로그에 자동으로 포함시켜 뒤섞인 로그를 명확하게 묶는 역할
마침 지난 주말 런칭데이 부스를 운영하면서 맛집 데이터들을 어떻게, 어떤 플로우로 가져오는지에 대한 질문들을 많이 받았었기에, 이번 기회를 통해