1. 프로젝트 개요
외부 파트너사의 예약 API에 전적으로 의존하는 구조에서, 사용자 예약 흐름과 외부 시스템 간의 안정적인 연계를 목표로 예약/마이페이지 기능 및 통신 로깅 아키텍처를 설계하고 구현했습니다.
2. 문제 상황
1) 외부 의존 구조에서의 리스크
예약 데이터가 전적으로 외부 API에 존재하여, 파트너사 서버의 응답 지연이나 타임아웃이 곧바로 사용자 경험 저하(내부 서버 오류로 인식)로 이어지는 구조적 리스크가 있었습니다.
2) 비정상 트래픽에 대한 검증 불가
호텔 행사 진행 시 파트너사로부터 "비정상적인 대량 요청이 발생했다"는 클레임이 접수되었으나, 당사 서버에서 발생한 실제 요청 건수나 네트워크 레벨의 재전송 여부를 증명할 객관적 데이터(Trace)가 없었습니다.
3) DB 기반 로깅의 병목
초기에는 모든 cURL 통신 로그를 DB에 저장하도록 설계했으나, 수개월 동안 수백만 개의 로그 데이터가 쌓이면서 테이블이 비대해졌고, DB GUI 툴이 다운되는 현상까지 발생했습니다. 메인 비즈니스와 로깅이 동일한 DB 리소스를 공유하며 시스템 안정성을 해치는 역설적인 상황이었습니다.
3. 접근 전략
1) 외부 장애에 대한 UX 방어 설계
단순 예외 처리를 넘어 외부 API 실패를 사용자 경험 관점에서 재해석했습니다. 타임아웃을 "일시적 혼잡"으로 안내하고, 요청-응답 구간을 시각화하여 사용자의 혼란을 방지하고자 했습니다.
2) 로깅 아키텍처 분리 (DB → File)
DB는 핵심 비즈니스 데이터를 위한 자원으로 유지해야 한다고 판단했습니다. 쓰기 위주(Write-heavy)이며 트랜잭션 정합성이 덜 중요한 로그의 특성을 고려해, 비즈니스 DB와 로깅을 분리(Decoupling)하는 전략을 세웠습니다.
3) Fail-Safe 설계
"로깅은 실패할 수 있지만, 예약은 실패하면 안 된다"는 대원칙을 세우고, 로그 기록 실패가 메인 비즈니스 로직에 영향을 주지 않도록 모듈을 철저히 격리하기로 했습니다.
4. 구체적 해결 과정
1) 중복 요청 방어
요청 직후 버튼을 비활성화하고 로딩 상태를 명확히 하여, 클라이언트 단에서 다중 클릭으로 인한 서버 단 중복 요청 가능성을 사전에 차단했습니다.
2) 인메모리 버퍼링 기반 cURL 로그 시스템 구축
DB 로깅을 제거하고 날짜 단위(YYYY-MM-DD) 파일 로그 시스템을 직접 구현했습니다. 특히 파일 I/O 병목을 방지하기 위해 인메모리 버퍼링(Buffering) 패턴을 적용했습니다. 단건마다 파일에 쓰는 대신, 배열에 로그를 적재하다가 로그가 20건 쌓이거나 마지막 쓰기 이후 2초가 경과했을 때 일괄적으로 플러시(Flush) 하도록 구현하여 시스템 부하를 최소화했습니다.
3) 로깅 모듈 완전 격리
로깅 모듈 전체를 try-catch로 감싸, 파일 권한 오류나 디스크 용량 부족 문제가 발생하더라도 예약 흐름 자체에는 전혀 영향을 주지 않도록 구현했습니다.
5. 결과 및 영향
1) 데이터 기반 방어 체계 확보
구축한 파일 로그(요청 시각, 호출 IP, 세션 등)를 바탕으로, 행사 기간 중 발생한 비정상 트래픽이 당사 홈페이지를 통한 정상적인 API 호출 패턴이 아님을 증빙했습니다. 이를 통해 파트너사의 클레임을 객관적 수치로 방어하고 협업 관계를 안정화했습니다.
2) 시스템 안정성 개선
로깅 아키텍처 변경 및 버퍼링 도입으로 메인 DB의 병목 현상과 GUI 다운 문제를 완전히 해결하였고, 외부 장애 발생 시에도 유연한 운영 대응이 가능해졌습니다.
6. 배운 점 및 확장 사고
1) 로그 라이프사이클 관리의 중요성
당시에는 SSH 접속 후 수동 삭제 방식으로 로그를 관리했습니다. 현재 동일 구조를 설계한다면 Logrotate 기반의 자동 파기 정책, 로그 레벨 분리(INFO/WARN/ERROR), 중앙 집중형 로그 수집 아키텍처(ELK, Datadog 등)를 고려해 운영 확장성까지 포함한 설계를 진행했을 것입니다.
2) 동시성 제어에 대한 재설계 (현재 관점)
당시에는 "실제 데이터는 외부 시스템에 있으므로 동시성 문제는 파트너사의 책임"이라는 전제를 두었습니다. 현재라면 클라이언트 진입 시점부터 Redis 기반 TTL Lock (3~5분) 을 적용할 것입니다. 선점 실패 시 사용자에게 즉시 안내하고 확정 시 Lock을 해제하는 방식으로, 동시성 제어를 외부에 위임하지 않고 우리 시스템 내에서 주도적으로 제어하는 아키텍처를 그릴 것입니다.