특정 데이터 저장 요청 -> 카프카 메시지 -> 서버저장
이 과정을 거치는데 카프카 메시지 도착전 쿼리를 날리고 요청을 하면 동시성 문제로 중복 삽입 문재.
물론 최종 저장전 확인이 가능하지만 유저는 모름
-> 레디스 사용
내일 수정예정
===========================================
어제 곰곰히 생각해보니 MSA기반 서버에서는 동시성 문제가 필연적일 수 밖에 없는것 같다.
-> 동시성 문제 발생..
이 문제를 트랜잭션 격리 수준이나 - DB Lock등의 기법으로 저장이야 해결할 수 있는데, 유저는 이게 어캐된건지 모름?
Request를 했는데 Response는 됐다매!!!!!!!!!!!!!!!!!!!!!!!!!!!
왜 내가 구매한게 사라져있는데!!!!!
그래서.. Request와 Response의 Sync는 맞춰줘야 하는데 보통 java에서는 synchronized 예약어를 사용해서 하나씩 접근할 수 있게 하는데 얘는 어캐 해야 되나 막막했음.
https://upcurvewave.tistory.com/369
https://brewagebear.github.io/concurrency-distributed-transaction-with-tcc/
이러한 글들을 찾아 봤는데, 트랜잭션 상에서 오류가 발생했을때 해당 서버와 DB간의 상호작용을 핸들링 하고 순차적으로 처리할 수 있게 하는 구조로 설명되어 있다.
즉, 그쪽 서버랑 db만 알고 클라이언트는 아직 모른다는것이다.
나는 '실시간 선착순'시스템을 기반으로 유저가 확실한 여부를 알아야 한다고 생각해 더 찾아봤다.
https://upcurvewave.tistory.com/482
!!!
위 글을 토대로 kafka와 redis를 같이 사용해야만 이를 해결할 수 있다고 봤다.
예전에 redis 한번 써보긴 했었는데, synchronized를 건것처럼 하나의 쓰레드에서 순차적으로 명령들을 처리해 주기 때문에 동시성을 해결해 줄 수는 있는데,
문제는 싱글쓰레드라는 점이다. 너무 많은 연산을 해버리는 순간 지연시간이 엄청 오래 걸리는 문제도 있고, pub sub또한 확실한 메시지의 전달을 보증해줄 수 없다.
그래서 kafka와 함께 사용해서 안정성을 높이려 한다.
맨 처음 생각했을때 1에서 확인한 결과를 토대로 2를 요청하면 확실하게 요청도 될거고 동시성 문제도 안생길거다~ 라고 생각했는데, 좌석을 보고 예약까지 이어진다는 flow가 100% 확신할 수 도 없고, 이를 블로킹 할 수도 없었다.
실제 선착순 예약 시스템도 남아있는 좌석을 클릭해도 그 사이에 누가 예약하면 예약할 수 없다고 뜨기 때문.
그래서 실제 동기화는 2에서 수행하되, 서버의 부담이 없다면 1또한 동기화를 걸어주고자 한다.
일단 2. 좌석 예약 을 먼저 고려하고자 한다.
좌석 예약 end point로 좌석의 id를 넘겨준다 가정하자.
해당 좌석 id를 event 서버로 넘겨 좌석이 비어있는지 확인한다. (OpenFeign)
해당 event 서버는 DB에서 find로 정보를 가져오는데, 'Redis'를 확인해서 현재 예약이 이루어졌는지 확인한다.
만약 Redis 캐시에도 없으면 예약 가능하다 반환한다.
좌석 예약 api 서버는 좌석 예약했다고 kafka에 메시지를 보내고, Redis에다 좌석값을 넣는다. (Order, Event 갱신)
-> Redis를 통해 확실하게 원자성을 보장해줄 수 있으므로 신청한 예약은 확실히 통과된다.
1, 남아있는 좌석 조회는
db에서 findall로 좌석 데이터를 가져온다.
이를 즉시 반환해도 되지만, 만약 kafka의 데이터가 도달하지 못했을경우를 고려한다고 하면
redis의 키값이 존재하는지 여부를 cross-check 한 뒤 반환해주면 되겠다.
근데, 이 redis의 키 값을 가져오는게 getNX등을 이용하면 O(1)정도로 끝낼 수 있지만, 전체 리스트를 가져온다고 하면 O(N)까지 늘어나기 때문에 이 부분은 추후에 고려를 해봐야겠다.
https://www.baeldung.com/cs/cache-write-policy
그래서 이와 비슷한 개념으로 Cache 쓰기 정책이 있다.
예전에 이거 관련해서 머리가 좀 아팠던 기억이 있는데 현재 구상하는 방식은 Write-Through와 일치하는것 같다.
다만, 이거 잘못 구성하면 Redis의 부담이 매우 커지기 때문에 최적화가 가장 중요하다.