전체 글 (10) 썸네일형 리스트형 트랜잭션 격리 수준 - 왜 MySQL은 RR인가 아주 예전에 트랜잭션 격리 수준에 대해서 알아보다가, DB마다 기본값이 다르다는 점을 깨달은 적이 있었습니다. MySQL의 InnoDB는 REPEATABLE READ(RR)를 기본값으로 사용하지만, Oracle과 PostgreSQL은 READ COMMITTED(RC)를 기본값으로 사용합니다. 같은 SQL 표준을 따르는 관계형 데이터베이스인데 왜 기본값은 다른지 궁금했었는데, 이번 기회에 이 궁금증을 다뤄보고자 합니다. 이번 글에서는 공식 문서와 개발자 기록을 바탕으로 각 DB가 서로 다른 기본값을 사용하게 된 배경을 살펴본다. MySQL에 대한 설명은 InnoDB를 기준으로 한다. MySQL과 Oracle, PostgreSQL은 왜 기본값이 다를까?DB기본 격리 수준MySQL InnoDBREPEATABL.. Event Sourcing에서 CQRS까지 (6) - 비동기 프로젝션의 장애와 복구 이 시리즈는 실제 경험을 바탕으로, 현재 상태를 저장하는 방식의 문제와 이를 해결할 대안들을 살펴봅니다. 각 대안의 장단점과 트레이드오프를 비교해 Event Sourcing을 선택한 이유를 설명합니다. 이어서 그 선택으로 감수한 비용과 제약을 짚고, 이를 보완하기 위해 최종적으로 CQRS를 선택한 과정까지 다룹니다. 이번 편은 시리즈의 마지막 이야기로, 비동기 반영 과정의 누락과 중복, 순서 역전에 대응하는 방법을 살펴봅니다. 원본 변경을 전달하는 구간과 조회 모델에 반영하는 구간을 나눠, 각 단계의 장애와 복구 방식을 설명합니다. 5편에서는 조회할 때마다 원본 이벤트에서 상태를 복원하고 정책과 결합해 금액을 계산하던 처리를 조회 모델 갱신 시점으로 옮겼다. 목록의 필터링과 정렬, 집계는 계산 결과를 저.. Event Sourcing에서 CQRS까지 (5) - 조회 모델 분리 이 시리즈는 실제 경험을 바탕으로, 현재 상태를 저장하는 방식의 문제와 이를 해결할 대안들을 살펴봅니다. 각 대안의 장단점과 트레이드오프를 비교해 Event Sourcing을 선택한 이유를 설명합니다. 이어서 그 선택으로 감수한 비용과 제약을 짚고, 이를 보완하기 위해 최종적으로 CQRS를 선택한 과정까지 다룹니다.이번 편은 시리즈의 다섯 번째 이야기로, 조회마다 반복하던 상태 복원과 정책 계산을 줄이기 위해 조회 모델을 분리하는 과정을 살펴봅니다. 조회 모델의 갱신 방식과 저장소를 비교하고, OpenSearch를 선택한 이유를 설명합니다. 데이터와 규모는 구조를 설명하기 위한 예시입니다. 4편에서는 이벤트에서 상태를 복원하고 정책과 결합해 조회 시점마다 금액을 계산하는 비용을 살펴봤다. 조회 범위와 요.. Event Sourcing에서 CQRS까지 (4) - 트레이드오프 이 시리즈는 실제 경험을 바탕으로, 현재 상태를 저장하는 방식의 문제와 이를 해결할 대안들을 살펴봅니다. 각 대안의 장단점과 트레이드오프를 비교해 Event Sourcing을 선택한 이유를 설명합니다. 이어서 그 선택으로 감수한 비용과 제약을 짚고, 이를 보완하기 위해 최종적으로 CQRS를 선택한 과정까지 다룹니다.이번 편은 시리즈의 네 번째 이야기로, 앞서 선택한 저장 구조에서 감수하게 된 조회 비용을 살펴봅니다. 이벤트에서 상태를 복원하고 정책으로 금액을 계산하는 작업이 목록의 필터링과 정렬, 집계에 어떤 영향을 주는지 다룹니다. 데이터 규모는 조회 과정을 설명하기 위한 가정입니다. 2편에서는 변경 이력과 과거 상태를 보존하기 위해 Event Sourcing을 선택했다. 3편에서는 이용 기록과 정책 .. Event Sourcing에서 CQRS까지 (3) - 대량 쓰기 문제의 해결 이 시리즈는 실제 경험을 바탕으로, 현재 상태를 저장하는 방식의 문제와 이를 해결할 대안들을 살펴봅니다. 각 대안의 장단점과 트레이드오프를 비교해 Event Sourcing을 선택한 이유를 설명합니다. 이어서 그 선택으로 감수한 비용과 제약을 짚고, 이를 보완하기 위해 최종적으로 CQRS를 선택한 과정까지 다룹니다.이번 편은 시리즈의 세 번째 이야기로, 잦은 정책 소급 반영과 잘못 적용한 정책의 복구가 대량 쓰기로 이어지는 사례에서 발생한 문제를 살펴봅니다. 청크 단위 갱신과 원본 기록을 정책 계산에서 분리하는 방법을 비교하고, 문제를 어떻게 해결할 수 있는지 살펴봅니다. 1편에서 살펴본 실제 경험에서는 여러 운영 테이블의 계산 결과를 하나의 트랜잭션으로 갱신했다. 정책 소급 반영이 잦았고, 잘못 적용한.. 분산 트랜잭션과 Saga (1) - 분산 트랜잭션은 왜 필요할까? 이 시리즈는 분산 트랜잭션과 Saga를 공부하며 정리한 내용을 다룹니다. 실제 운영 경험을 소개하는 글이 아니라, 학습을 위한 가상의 주문, 재고, 결제 예제로 서비스 간 데이터 일관성을 유지하는 방법을 살펴봅니다. 2PC와 Saga의 비교에서 시작해 Saga를 구현할 때 필요한 상태 저장과 보상, 장애 후 재개를 다루고, 취소와 예약 만료, 여러 작업의 복구까지 조건을 추가하며 설계를 구체화하는 과정을 다룹니다. 분산 트랜잭션은 왜 필요할까 일반적인 RDB의 로컬 트랜잭션은 하나의 DB 연결에서 시작해, 그 트랜잭션에 포함한 변경을 함께 커밋하거나 롤백한다. 모든 변경이 확정되거나 아무 변경도 확정되지 않도록 하는 성질이 원자성이다. 같은 서버 애플리케이션에서 주문 저장과 재고 변경을 동일한 트랜잭션에.. 동시성 제어 (2) - Redis 분산 락은 언제 필요한가 1편에서는 MySQL의 조건부 UPDATE, 낙관적 락, 비관적 락으로 동시 요청을 다뤘다. 서버가 여러 파드로 늘어나도 이 방법들은 여전히 동작한다. 같은 MySQL을 사용한다면 어느 파드에서 온 요청이든 DB에서 같은 조건을 검사하고 잠글 수 있기 때문이다. 그렇다면 Redis에 분산 락을 따로 두는 이유는 무엇일까? 핵심은 작업을 한 번만 실행하려는 이유에 있다. 어떤 작업은 두 번 실행되면 데이터가 잘못되고, 어떤 작업은 데이터는 그대로지만 계산 비용만 늘어난다. Redis 잠금은 후자처럼 잠시 동안 중복 실행을 줄이고 싶을 때 선택하기 쉽다. 이 차이를 먼저 이해해야 잠금이 해결할 문제와 잠금만으로는 해결되지 않는 문제를 구분할 수 있다. Redis 분산 락이 보장하려는 것한 파드의 메모리 잠금.. 동시성 제어 (1) - 낙관적 락과 비관적 락 서버 애플리케이션에는 여러 요청이 동시에 들어온다. 서로 영향을 주지 않는 요청이라면 문제가 없지만, 같은 상태나 업무 조건에 의존해 변경하거나 외부 작업을 실행하는 요청은 순서가 엇갈릴 수 있다. 요청 하나만 실행할 때는 올바른 코드라도 여러 요청이 함께 실행되면 결과가 달라지는 이유다. 계좌 잔액처럼 현재 상태와 처리 기록이 맞아야 하고, 그 상태에 근거한 행동도 올바르게 이루어져야 하는 데이터에서는 이 차이가 단순한 화면 오류로 끝나지 않는다. 이번에는 계좌 출금을 예로 들어 동시성 문제가 무엇인지 살펴본다. 이어 조건부 UPDATE로 해결할 수 있는 경우를 확인하고, 낙관적 락과 비관적 락의 충돌 처리 방식을 비교한다. 애플리케이션 인스턴스 하나와 MySQL 하나에 출금 요청 50건을 동시에 보내.. 이전 1 2 다음