이번에는 테크블로그에 대한 아키텍쳐 이야기 + 책의 Transaction 이야기가 나왔다.
https://tech.kakao.com/posts/810
https://tech.kakao.com/posts/810
스터디원이 비판적인 사고방식을 가지고 있던 덕에 훌륭한 이야깃거리와 교훈을 얻었다.
테크블로그에서 이야기 하는 것은 다음과 같다. (지피티야 도와줘)
문제: 일부 SMS가 벤더 리포트는 도착했는데도 DB 상태가 SENT에 머무르는 “리포트 실종”이 발생했는데, 원인은 벤더 리포트가 너무 빨리 와서(DB 커밋 전, 평균 8ms) Report Server가 메시지를 조회하지 못하고 리포트를 드롭하는 레이스 컨디션이었다.
1차 개선: 트랜잭션 안의 불필요한 후처리(과금 이벤트 발행 등)를 AFTER_COMMIT 비동기로 빼고, 어떤 경로는 @Transactional 자체를 제거해 커밋 지연/커넥션 점유를 줄여 누락을 크게 감소시켰다.
근본 해결: 리포트를 먼저 Outbox에 적재하고, 처리/상태전이/과금 이벤트 발행을 단 하나의 워커(Report Replayer)가 전담하는 Single Writer + Outbox 구조로 바꿔 경쟁을 없애서 누락(리포트/과금) 문제를 구조적으로 제거했다.
Outbox 패턴을 적용한 근본적인 배경은 Race Condition 현상이 발생할 수 있는 근본적인 문제를 아키텍쳐적으로 해결하기 위함이었다.
실제 API서버에서 Message 상태를 DB 에 commit하기 전에, 기지국(벤더)리포트가 도착하는 경우가 있을 수도 있기 때문에...
하지만, 기지국으로 전송하기 전에 DB에 Message를 전송 진행중 (Pending)이라는 정보를 Commit한후에 기지국에 전송요청을 보낸다면...? 그러면 Race Condition이 근본적으로 제거가 된다. 더불어 Outbax패턴이 불필요하다.
다만 단점 몇가지가 있겠지..
비즈니스로직이 정확이 어떻게 되어있는진 알 순 없지만.. 단지 DB Read Write 시점을 반드시 보장해야되는 그런 상황에서는 Outbox패턴이 정답이 될 순 없을 것같다.
Consistency 와 Durability
Consistency는 DB차원에서 보장하기엔 어려운 부분이 많다.
PK/FK, UNIQUE, CHECK, NOT NULL, 트리거 등의 무결성은 OK. 하지만, 비즈니스의 제약조건을 모두 DB에서 해주는건 아니기때문이다. 이는 어플리케이션에 포함되는 좀 더 넓은 범위이다.
Durability는 하드웨어적인 관점 (HDD 자성잃으면?, SSD 셀 망가지면?) + WAL/REDO Log의 소프트웨어 관점이 합쳐진 개념
ReadCommitted든, Snapshot 격리이든 Dirty Write을 방지하기 위해 Write 대상의 Record에 Lock을 건다.
스냅샷은 Transactino ID기준으로 그 위의 트랜잭션의 내용은 읽을 수 없으므로, Repeatable Read가 보장. ReadCommitted는 그렇지않음
번외..
Read Timeout은 실제 응답 패킷이 늦게오는 경우임.
만약 DB Transaction에서 commit이 된 이후에 ReadTimeout이 발생한다면...? 롤백판단이 힘듬. 그래서 멱등성있게 API를 작성하는것이 베스트하다.
read->modify->write 할 때 자주 발생 이를 막기위해 무엇을?
두 트랜잭션이 각기 다른 객체를 갱신하면서 발생하는 경쟁 조건.
이를 막기 위해서는 ?