NDM

6. 재고 감소 -> 주문이 맞을까, 주문 -> 재고 감소가 맞을까? 본문

[프로젝트] Slow Delivery

6. 재고 감소 -> 주문이 맞을까, 주문 -> 재고 감소가 맞을까?

ndm.jr 2022. 9. 14. 17:12

배달 서비스를 구현하는 slowDelivery 프로젝트 진행중입니다.

주문 로직에 대해 제가 고려한 것을 포스팅 하려고 합니다.

 

도메인은 장바구니 / 상품/ 재고 / 가게 / 주문이 있으며,

결제API는 클라이언트쪽에서 연동하기 때문에 결제데이터를 save하는 정도로만 구현했습니다.

 

장바구니와 재고는 Redis로 되어있으며, 나머지는 RDB를 사용했습니다.

 

재고에 Redis를 사용한 이유는 https://ndm-tech.tistory.com/34 에 기록해 두었습니다.

 

이번 포스팅에서는 아래의 내용을 다룹니다.

  • 주문 로직의 순서를 결정하게 된 고민 과정

 


 

프로젝트를 진행하며 처음에 고생했던 부분 주문이 성공하고 나서야 재고를 감소시켰었다는 점 입니다.

이것은 실제 상황과 비교해 볼 때,

  • 가장 유사한 순서이며
  • 주문이 실패했을 때 재고를 원복시켜야 하는 경우도 고려할 필요 없습니다.

하지만 주문이 성공하고 나서야 재고를 감소시키면 어플리케이션에서는 문제가 발생하게 됩니다.

 

왜냐하면 재고 데이터에 락을 걸어줘야 하기 떄문입니다. 재고가 10개남은 엽기떡볶이를 2개 주문한다고 가정해봅시다.

 

락을 걸지 않는다면, 주문 중간에 다른 사람이 9개를 주문했을 때 재고는 10개뿐인데 11개가 주문되는 상황이 나타날 수 있습니다.

 

위 그림처럼 락을 걸어야 10 - 2를 했을때 재고가 8개 남는 상황을 보장할 수 있습니다.

하지만 위 그림처럼 락을 건다면, 한 사람이 주문하는 동안 다른 사람은 그 사람의 주문이 끝날떄까지 엽기떡볶이를 주문하지 못하는 상황이 생깁니다.

 

떄문에 주문이 시작될 때 미리 재고를 감소시키고, 예외가 생겨 주문이 실패하거나 소비자가 주문을 취소한다면 그 때 다시 재고를 원상복구하는 방식으로 로직을 변경하게 되었습니다.

 

여기서 중요한것은

만약 재고를 RDB로 관리하고 있고, 트랜잭션 전파레벨이 Required_New가 아니라면 로직 전후의 데이터가 보장되지 않기 떄문에 재고를 먼저 감소한다고 하더라도 여전히 락을 걸어줘야 합니다.

 

 

Required_New는 위 그림처럼 동작하는데, 트랜잭션 N개를 사용하기 때문에 [재고 감소]를 트랜잭션 하나를 이용해 처리한다면 [주문]과는 관계없이 먼저 재고를 감소시킬 수 있습니다.

하지만 N개의 커넥션 풀을 사용해야 한다는 단점이 존재해 이 방법을 배제했습니다.

 

제 경우처럼 재고를 Redis로 관리한다면, RDB의 트랜잭션과 별개로 작동하기 떄문에 주문과 별개로 재고를 감소시킬 수 있습니다.

 

 

Redis에만 먼저 재고를 감소시키는 명령을 보내고, 주문 실패 시 롤백하는 로직을 추가로 작성하였습니다.

Redis는 Spring Transactional의 영향을 받지 않기 떄문에, 롤백 로직을 추가로 작성한 뒤 write연산이 이루어지기 전에 먼저 선언을 해줘야 합니다.

 

 

롤백 로직은 감소한 개수만큼 올려주면 됩니다.

 


 


출처

https://tjdrnr05571.tistory.com/9?category=876333 

 

[#3] 정확히 트랜잭션이 롤백 되었을 때 장바구니를 복원하기 -TransactionSynchronization afterCompletion (Ro

@Transactional을 적용하여 어떠한 메소드를 실행한다면 롤백이 되었을 때 DB에 관련된 추가, 삭제등 로직은 @Transactional에 적용되어있는 AOP 로직에 의해 저절로 롤백이 됩니다. 하지만 레디스나 다른

tjdrnr05571.tistory.com