Now & Go — AI 여행 플래너
4인 팀 · 백엔드 공통 모듈 · 아키텍처 설계 개발 약 1개월검색 → 추천 → 대리결제를 잇는 여행 커머스 / Java · Spring Boot 3 · Python · Kafka · Redis · Elasticsearch
- Role
- 백엔드 공통 모듈과 아키텍처 설계를 맡았습니다. 인증·이벤트·데이터소스 등 공통 모듈, 서비스 간 통신 구조, RAG 추천, 동시성 제어를 다뤘고, 그중 RAG 추천과 분산락 두 가지를 아래에 소개합니다.
01 — Search & Recommendation
RAG 파이프라인
- Summary
- “8월에 부산, 아이랑 느긋하게, 회는 빼고” 같은 문장을 넣으면 지금 실제로 예약 가능한 상품만 골라 3일치 여행 계획 3개를 만들어 줍니다.
- Problem
- ChatGPT 같은 일반 LLM은 우리 플랫폼에 그 상품이 실제로 있는지, 그날 자리가 남았는지를 모릅니다. 없는 상품을 추천하면 예약이 안 되니, LLM에게 답을 맡기지 않고 DB에서 먼저 찾아온 실제 상품만 근거로 주고 계획을 쓰게 했습니다. RAG라고 부르는 방식입니다. 대화 기억도 외부 도구 호출도 필요 없는 구조라 LangChain은 오버스펙이었고, 숙소·먹거리·놀거리가 각각 최소 몇 개씩은 꼭 담겨야 한다는 요구 때문에 검색 쿼리 제어권을 넘길 수 없었습니다.
- Solution
- Haiku가 문장에서 조건(지역·기간·동행·취향)을 뽑고 → Titan이 문장을 숫자 벡터로 바꾸고 → Elasticsearch가 뜻이 비슷한 상품(kNN)과 단어가 겹치는 상품(BM25)을 따로 찾아 순위를 합치면서(RRF) 카테고리별 최소 개수를 강제로 채우고 → PostgreSQL에서 그 날짜의 실제 재고·가격을 붙이고 → Sonnet이 이 후보만으로 계획을 쓰고 → 마지막에 서버가 규칙 위반을 직접 검사해, 어기면 이유를 알려주고 다시 쓰게 합니다.
02 — Concurrency
분산락 & Outbox
- Summary
- 같은 좌석을 두 사람이 동시에 눌러도 한 명만 잡히게 하고, 결제를 포기하면 15분 뒤 자동으로 풀립니다.
- Problem
- 좌석 선점을 DB로 막으면 결제가 끝날 때까지 그 행을 붙잡고 있어야 합니다. 그런데 결제까지 15분이 걸립니다 — 동시 접속이 몰리면 같은 행을 기다리는 트랜잭션이 쌓이고(락 경합), DB 접속 슬롯이 바닥납니다(커넥션 풀 고갈).
- Solution
- 좌석 잡기를 DB 밖 Redis로 옮기고, 선점(15분 뒤 자동 만료) → 결제 확정(10초) 2단계로 나눴습니다. 풀 때는 ‘내가 잡은 게 맞는지 확인’과 ‘삭제’를 쪼갤 수 없는 한 덩어리로(Lua) 처리해, 남의 좌석을 실수로 푸는 사고를 막았습니다.
- Insight
- 락이라기보다 예약 홀드에 가깝습니다. 만료 시간을 작업이 걸리는 시간이 아니라 결제에 주는 시간으로 잡았습니다.
- 획득 —
SET key uuid NX EX 900‘좌석 잡기’와 ‘15분 뒤 만료 설정’을 한 명령으로 처리합니다. 둘로 나눠 쓰면 그 틈에 서버가 죽었을 때 영원히 안 풀리는 좌석이 남습니다. - 해제 — ‘내 것인지 확인’과 ‘삭제’를 따로 하면 그 틈에 만료가 지나 남이 새로 잡은 좌석을 지워버릴 수 있습니다. 둘을 쪼갤 수 없는 한 덩어리로(Lua) 묶었습니다.
- 확정 — 결제 콜백은 같은 요청이 두 번 이상 올 수 있습니다(재시도 때문에).
주문번호로 잠금을 걸어 이중 확정을 차단했습니다
(
lock:confirm-seats:{orderNo}). - Outbox — DB 저장은 됐는데 알림 이벤트 발행이 실패하면 이벤트만 사라집니다. 이벤트를 같은 트랜잭션 안에 함께 저장해두고 별도 작업이 꺼내 발행하도록 바꿔, 쓰기 서비스 8개에 일괄 적용했습니다.
- 알려진 한계 — 작업이 15분을 넘기면 만료가 먼저 와서 상호배제가 깨질 수 있고
(연장해주는 장치를 두지 않았습니다), Redis 한 대 기준이라 RedLock이 아닙니다.
그래서 마지막 방어선은 DB의 유니크 제약입니다 — 앞이 다 뚫려도
같은 좌석 두 줄은 DB가 거부합니다(
uk_sku_seat).
15분
좌석 자동 해제
8개 서비스
Outbox 적용



















