선착순 이벤트 시스템 관련해서
Ex) 100개의 쿠폰을 발급한다고 했을 때
db로만 쿠폰 발급 로직을 조절할 경우 race condition 발생으로 인해 100개보다 더 많은 쿠폰이 발급될 수 있음
Redis 도입
가장 떠올리기 쉬운 방법은 java의 synchronized 키워드를 사용해서 access를 동시에 하는 것을 막는 건데
사실 이 방법의 가장 큰 문제점은 여러 대의 서버를 띄울 경우 무용지물인 부분이다.
(하나의 서버에 들어온 여러 개의 동시 접근을 막아주는 것이기 때문)
그렇다면 레디스 도입을 통해 문제를 해결하는데 레디스에는 incr라는 명령어가 있음
1 증가시키면서 증가시킨 값을 가지고 온다.
가지고 온 값이 100이 넘었을 경우 쿠폰을 발급하지 않도록 한다.
카프카 도입
레디스에 저장된 값이 100을 넘지 않았다면 db에 새 쿠폰을 저장할텐데
보통 선착순 이벤트를 진행할 경우 수천개의 트래픽이 단번에 몰리는 것이기 때문에 db에 부하를 줄 수 있다.
따라서 이 부하를 줄이기 때문에 카프카를 사용한다.
카프카란 실시간 스트리밍 시스템이라고 보면되는데, 프로듀서가 토픽을 던지면 컨슈머가 이 토픽을 받는 구조이다.
즉, 프로듀서는 요청을 던지면 토픽이라고 하는 queue에 이 요청을 잠시 넣었다가 컨슈머가 토픽에서 요청을 꺼내서 원하는 로직을 실행하면 된다.
컨슈머는 서버를 한 대 띄워서 메인 서버의 프로듀서가 던진 토픽을 받아오도록 한다.
프로듀서가 예를 들어 쿠폰을 발급해야하는 user_id를 토픽에 던졌다면 컨슈머가 user_id를 받아서 db에 쿠폰을 넣어주는 식으로 진행하면 된다.
한 사람당 쿠폰 하나라면
레디스도 도입했고 카프카도 도입했는데, 쿠폰을 발급했는지는 현재 db에서만 확인가능하다.
즉, 카프카가 db에 데이터를 잘 반영했는지가 주요 사항 중 하나인데, 여러 개의 동작이 몰리다보니 실시간으로 처리되지 못할 수 있다.
이런 경우 유저가 여러 번 쿠폰 발급을 요청했을 때 여러 개의 쿠폰을 발급할 가능성이 생겼다.
이 경우 레디스 set을 사용해서 한번 쿠폰 발급을 시도한 적이 있을 경우 user_id를 set에 등록해서 등록되어있을 경우 쿠폰을 발급한 적이 있다고 본다.
재고관리 시스템
재고관리 시스템 구현 시 데이터를 단순히 감소시키는 모양새로만 개발을 하게 되면 race condition이 발생하게 되어 실제 재고와 데이터 상의 재고 간의 차이가 발생하게 된다.
synchronized도 동일하다.
한 서버에 대해 동시에 접근하는 요청을 막는 것이지 여러 서버에서 동시에 하나의 데이터에 접근하는 요청을 막아주지는 못한다.
따라서 방법은 크게 두 가지이다.
MySQL에서 락을 사용하거나 Redis를 사용하는 방법이 있다.
MySQL에서 사용 가능한 락의 종류는 Optimisitic lock, pessimistic lock, named lock 세 가지이다.
Redis에서 사용 가능한 라이브러리는 Lettuce, Redisson 두 가지이다.
MySQL
Pessimistic Lock
Pessimistic lock은 비관적 락이다. 데이터베이스 row에 락을 건다.
이럴 경우 하나의 요청이 락을 걸고 데이터를 변경하고 있으면 락을 해제하고 나가기 전까지 대기하는 방식이다
Optimistic Lock
Optimistic lock은 낙관적 락이다. version이라고 하는 컬럼을 추가해서
조회와 수정 시 version을 where에 넣어서 함께 조회한다.
조회할 때 사용했던 version을 그대로 사용해서 수정하게 되는데, 수정 시 version도 함께 체크해서 틀리면 update가 실패하게 된다.
Named Lock
Named lock은 잘 기억이 안난다!^^! 다시 공부해야지..
Redis
Lettuce
lettuce는 setnx 명령어를 사용해서 구현한다.
lock이 걸려있는지를 체크하는 ‘키’를 생성하고 해당 ‘키’에 접근해서 락이 걸려있는지를 체크한다.
락이 걸려있으면 sleep하고 일정 시간 기다리면서 락을 획득할 때까지 기다린다. Spin lock 방식
Redisson
redisson은 pub-sub을 사용해서 lock을 획득했다가 해제할 때 채널에 ‘해제’ 를 Publish 한다. 그러면 락을 획득하고 싶어서 채널을 subscribe하고 있던 또 다른 요청에 ‘락 획득 가능’ 연락이 가게 되면서 락을 획득하게 된다.
redisson의 경우에는 라이브러리를 따로 mvn repository에서 가지고 와야하는 귀찮음이 있다.
lettuce의 경우에는 이미 redis template에 해당 라이브러리가 포함되어있다.
근데 redisson은 락 획득 시도 부분이 내장되어있기 때문에 좀 더 편하다.
MySQL, Redis 비교
일정 트래픽까지는 솔직히 mysql 써도 된다. 문제는 mysql이 트래픽을 버티지 못하는 것 같으면 redis로 바꿔야한다.
Mysql은 대부분 쓰고 있기 때문에 바로 적용 가능하겠지만 redis는 비싸서 안쓰고 있는 회사가 있을수도 있다.
따라서 성능이 좋으면 비싼 거니까 꼬옥 필요한지 잘 따져서 쓰길 바란다.
'공부공부' 카테고리의 다른 글
Rust Cargo (0) | 2023.11.04 |
---|---|
Rust 설치 및 Hello World 출력 (0) | 2023.11.04 |
토익2023.08.14 (0) | 2023.08.14 |
공부공부-20230726(스터디, Go, 쿠버네티스) (0) | 2023.07.26 |
공부공부-230529 (1) | 2023.05.29 |