티스토리 뷰

반응형

안녕하세요 ! 오랜만에 새로운 글로 찾아온 GOLF 입니다! 

내용 요약

GPT 발췌

1. 문제 상황
사용자가 제일 먼저 구매했음에도 결제까지 완료되지 않으면, 다른 사용자가 결제를 진행하여 상품을 선점할 수 있는 문제가 발생합니다.

2. 해결 방법 비교:
주문 즉시 판매 처리 (보상 트랜잭션 방식): 주문 정보를 즉시 “팔림” 상태로 처리하여 다른 사용자가 결제하지 못하게 합니다.
결제 실패 시 보상 트랜잭션으로 롤백하는 등 복잡한 예외 처리와 상태 관리가 필요합니다.

상품 잠금 (선점) 방식:
주문 시점에 해당 티켓이나 상품을 잠금 처리하여 결제 전까지 다른 사용자가 접근하지 못하도록 합니다.
주문 처리에 문제가 생기면 단순히 잠금만 해제하면 되므로 구현 및 예외 처리가 간단합니다.

두 방식은 구현 난이도, 예외 처리, 시스템 복잡도 측면에서 차이가 있으며, 글에서는 선점 방식이 더 간결하다고 결론짓습니다.

시스템 설계 관점:
Redis vs. RDBMS(MySQL):
Redis: 빠른 in-memory 처리로 대규모 트래픽 환경에서 높은 처리량과 낮은 구현 난이도를 제공합니다. 단, 데이터 영속성은 보완적으로 고려해야 합니다.

MySQL: 동기 I/O 방식으로 데이터 안정성과 영속성이 뛰어나지만, 동시성 처리와 대규모 트래픽 처리에서는 성능 면에서 Redis에 비해 불리합니다.

따라서, 선점 정보는 Redis를 활용해 빠르게 처리하고, 주문 및 결제 정보는 MySQL과 같이 안정적인 저장소에 기록하는 하이브리드 아키텍처를 제안합니다.

문제 상황

옛날에 티켓을 사다보면 항상 걱정했던 부분이 좌석 선택부터 결제까지 너무 오래 걸려서 남들이 먼저 결제해버리면 어떡하지? 했던 경험이 있는데요 필자인 저 또한 그래서 항상 무통장 입금을 전제로 빠르게 결제를 마무리했던 경험이 있었습니다. 

 

시스템에서 상품을 제대로 선점해두지 못하면 사용자가 제일 먼저 구매했음에도 굉장히 불안해할텐데요. 이런 문제를 어떻게 하면 해결할 수 있을까요?

어떻게 해결해볼 수 있을까 (접근법)

문제 상황은 간단합니다! 제일 먼저 구매했음에도 결제 까지 가지 않으면 다른 사람도 결제 할 수 있다. 가 문제 상황입니다. 그렇다면?! 

사용자가 구매 버튼을 눌렀을 때 다른 사람이 사지 못하게 해야합니다. 

 

이 방법엔 두 가지가 있습니다. 

  • 주문을 했을 때 아예 팔렸다로 처리하여 다른 사람이 결제 하지 못하게 막는다.
  • 주문이 들어오면 해당 티켓은 결제 전 까지 잠궈둔다.

주문이 팔렸다로 처리하는 방법을 먼저 살펴보겠습니다.

 

 

주문 정보를 검토할 때 그리고 결제 할 때 마다 실패 시 보상 트랜잭션을 반드시 넣어주고 있고 롤백은 반드시 이뤄져야 합니다. 이는 애플리케이션에서 계속해서 주문의 흐름에 따라 보상 트랜잭션을 실행해주어야하고 상태 트래킹이 필수 입니다.

 

또한 주문 비즈니스가 복잡해지면 그 만큼 주문 롤백을 위해 처리하는 비용은 증가할 것입니다. 보상 트랜잭션 실패 시 처리 과정 또한 복잡해집니다.

 

그럼 잠금 매커니즘을 사용하면 어떨까요? 

플로우는 변하지 않습니다. 다만 주문 완료 -> 선점, 주문 처리 롤백 -> 선점 해제 로 바뀌었을 뿐입니다. 선점은 비교적 복잡한 주문 롤백 문제를 깔끔하게 해결해줍니다. 선점은 해당 티켓을 잠궈만 놓고 실제로 주문 처리 하지 않습니다. 

주문 처리를 하지 않았기 때문에 결제나 주문 중 문제가 생기더라도 잠금을 해제만 시켜주면 바로 다른 사용자가 살 수 있습니다. 그리고 비즈니스의 영향도 받지 않기 때문에 주문 비즈니스가 복잡해지더라도 선점 해제 로직이 복잡해질 확률은 비교적 낮습니다. 

 

다만, 단점은 잠금 해제와 획득을 위한 추가적인 작업 비용이 들어간다는 점입니다.

 

표로 정리해보면 다음과 같습니다.

비교 항목 상품 판매 처리 방식 상품 잠금 방식
구현 난이도 어려움 로직이 복잡해질 수 있음. 동시성 제어도 명확하고 구현 자체도 단순
예외 처리 복잡한 트랜잭션 흐름과 상태 관리로 인한
예외처리 복잡도 높음
단일 흐름으로 처리되어 예외 처리 시스템 구축이 단순함.
시스템 복잡도 복잡도높음 복잡도 낮음

 

결론적으로 잠금 방식이 구현 난이도도 훨씬 간결하고 어렵지 않게 문제를 해결할 수 있기 때문에 잠금 방식으로 문제를 해결하는 것이 가장 좋아보입니다.

시스템 설계

그러면 시스템을 설계 해볼 건데요. 잠금은 어떻게 설계해보면 좋을까요? 

  • 레디스를 이용한 방법
  • RDBMS를 이용한 방법

RDBMS는 간결하고 영속화가 된다는 점에 장점을 갖고 있는 저장소입니다. 반면에 Redis 는 신속한 처리속도와 높은 수준의 처리량을 갖는 저장소입니다.

 

또한, 두 인프라 모두 각자의 방식으로 동시성을 제어하고 있죠. 우리가 여기서 따져봐야할 것은 다음과 같습니다. 

  • 구현이 간결한가?
  • 동시성 문제로 인한 추가 Lock 매커니즘 구현 복잡도가 있는가?
  • 대규모 트래픽을 고려했을 때 순간 요청이 몰리는 순간 높은 처리량으로 병목을 방지할 수 있는가?

이 관점으로 봤을 때 표로 나타내면 두 인프라간 차이는 다음과 같습니다.

비교항목 Redis RDBMS (MySQL)
구현 난이도 낮음 높음
(TTL 같은 게 없기 때문에 lock release를 고려해야함)
동시성 문제 없음 없음
대규모 트래픽 안정성 높음
(in-memory & multi-plex I/O)
비교적 낮음
(대부분 요청에서 동기 방식 I/O 방식 사용)
데이터 안정성 낮음 높음

(Deep 한 부분은 연관성이 떨어져 이 chapter 에선 설명하지 않습니다. )

 

선점은 선점 정보가 영속화 될 필요 없이 TTL 에 따라서 바로 바로 날려주어야합니다. 또한 중요한 데이터라고 보기도 어렵습니다. 그리고 무엇보다 몰리는 대규모 트래픽 환경에선 처리량이 높은 Redis가 더 적절하다고 판단됩니다. 

 

결론적으로 Redis를 이용하여 처리하기로 했습니다. 

 

그럼 아키텍처를 보면 다음 과 같습니다.

 

1. 주문 및 결제 시 Redis에 선점 정보를 저장하고 상품이 안전하게 처리되도록 합니다.

2. 결제와 주문 정보는 안전한 RDBMS에 저장하면서 주문과 결제 상태를 영속화 하여 지속적으로 트래킹 가능하게 처리해줍니다.

3. 선점에는 반드시 TTL을 포함하여 어뷰징으로 부터 보호합니다. 적절한 TTL을 걸어주어 의도적인 어뷰징을 막습니다.

 

여기 까지가 문제 해결을 위한 접근 및 시스템 아키텍처 설계 얘기였습니다. part.2 에서는 선점 로직을 직접 구현하면서 구현전략에 대한 자세한 얘기를 진행해보겠습니다.

 

마침.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함