커피 주문 시스템 설계

E.NO·2026년 4월 6일

1. 설계 방향

이번 과제는 단순 기능 구현이 아니라 다수 서버 환경에서 안정적으로 동작하는 시스템 설계가 핵심이라고 판단했다.

그래서 다음 3가지를 중심으로 구조를 설계했다.

  • 동시성 제어
  • 데이터 일관성 보장
  • 확장 가능한 구조

전체 흐름은 다음과 같이 구성했다.

  • 메뉴 조회 → Redis 캐시 적용
  • 포인트 충전 → Redis 분산 락 적용
  • 주문/결제 → 하나의 트랜잭션으로 처리
  • 주문 이벤트 → Outbox + Kafka로 비동기 전송
  • 인기 메뉴 → Redis ZSet 기반 집계

2. 동시성 해결 전략

포인트는 동일 사용자에 대해 동시에 수정될 가능성이 높기 때문에 userId 기준 Redis 분산 락을 적용했다.

  • 락 키: lock:point:user:{userId}
  • 동일 사용자 요청은 직렬화
  • 다른 사용자 요청은 병렬 처리 가능

또한 락과 트랜잭션을 분리하여 DB 반영 완료 후 락이 해제되도록 구조를 설계했다.

-> 결과적으로 다중 서버 환경에서도 포인트 데이터 충돌을 방지할 수 있다.


3. 데이터 일관성 보장 전략

주문/결제 API에서는 다음 작업을 하나의 트랜잭션으로 묶었다.

  • 포인트 차감
  • 포인트 사용 이력 저장
  • 주문 생성
  • Outbox 이벤트 저장

이렇게 설계한 이유는:

  • 부분 성공(주문만 성공, 포인트 미차감 등)을 방지
  • 실패 시 전체 롤백 보장

또한 Kafka 전송은 트랜잭션 외부에서 처리하기 위해 Outbox 패턴을 적용했다.

-> DB와 메시지 전송 간 불일치를 최소화하고, 재처리가 가능한 구조를 확보했다.


4. 확장성 고려

4-1. Kafka 기반 이벤트 구조

주문 완료 후 이벤트를 Kafka로 전송하고, Consumer가 다음 작업을 수행하도록 분리했다.

  • 주문 이벤트 로그 저장
  • 인기 메뉴 집계

-> 이후 통계, 알림, 추천 시스템 등으로 쉽게 확장 가능


4-2. Redis ZSet 기반 인기 메뉴

인기 메뉴는 최근 7일 기준으로 집계해야 하므로 날짜별 ZSet 구조로 설계했다.

  • key: popular:menu:{date}
  • score: 주문 횟수

조회 시 최근 7일 데이터를 합산하여 Top3를 계산한다.

-> 빠른 조회 성능 + 기간 기반 집계 가능


4-3. 조회/쓰기 역할 분리

  • 정합성 중요한 데이터 → DB 중심 처리
  • 조회 성능 중요한 데이터 → Redis 활용

-> 트래픽 증가 시 병목 분리 가능


5. 설계 선택 이유 정리

관점선택이유
동시성Redis 분산 락다중 서버 환경에서도 사용자 단위 동기화 가능
데이터 일관성트랜잭션 + Outbox부분 성공 방지 및 이벤트 유실 최소화
확장성Kafka + Consumer기능 확장 시 구조 변경 없이 대응 가능
성능Redis 캐시 & ZSet조회 속도 향상 및 실시간 집계

6. 결론

이번 설계는 단순 기능 구현이 아니라 안정성과 확장성을 고려한 구조 설계에 초점을 맞췄다.

  • 동시성 → Redis 분산 락으로 해결
  • 데이터 일관성 → 트랜잭션 + Outbox로 보장
  • 확장성 → Kafka 기반 이벤트 구조로 확보

-> 결국 이 시스템은 “문제가 생기지 않도록 미리 구조를 설계한 시스템”이라고 정리할 수 있다.

0개의 댓글