티켓팅 오픈런 좌석 선점 동시성 이슈 해결과 락 성능 분석
·
스프링
들어가며인기 콘서트 예매나 선착순 이벤트 시스템을 설계할 때 가장 까다롭지만 중요한 부분 중 하나가 바로 '동시성 문제' 입니다. 수만 명의 사용자가 동시에 같은 좌석을 클릭하는 상황에서 시스템은 어떻게 단 한 명의 요청만 성공시키고 나머지는 정확하게 실패 처리할 수 있을까요? 이번 글에서는 티켓팅 서비스를 개발하며 겪었던 좌석 선점 동시성 이슈를 설명하고 낙관적 락, 비관적 락, 분산 락을 실제로 적용해 보며 얻은 테스트 결과를 공유합니다.동시성 제어가 필요한 이유한정된 자원에 짧은 시간 동안 트래픽이 집중되면 경쟁 상태(Race Condition)가 발생합니다.예를 들어, 두 개의 스레드(User A, User B)가 동시에 `Seat A` 정보를 읽고 빈 좌석임을 확인했다고 가정해보겠습니다.User..
[스프링] 중복 결제 요청 방어 로직에서 Hibernate Session 오염 문제
·
스프링
배경 콘서트 티켓팅 서비스에서 결제는 예민한 부분이다. 찰나의 순간에 수만 명이 몰리는 환경에서, 사용자의 실수나 네트워크 지연으로 인한 중복 결제 요청은 반드시 막아야 하는 과제이다.오늘은 이를 해결하기 위해 'Get-or-Create' 전략을 도입했다가, 예상치 못한 `AssertionsFailure`를 마주하며 영속성 컨텍스트의 특성을 알아본 기록을 공유하고자 한다.중복 결제를 막는 가장 확실한 방법클라이언트에서 디바운드로 더블 클릭을 어느정도 방지할 수 있지만, 중복 결제의 책임은 백엔드 서버라고 생각한다.결제 버튼을 더블 클릭했을 때, 서버에 요청이 두 번 들어와도 결제 데이터는 하나만 생성되어야 한다. 이를 위해 다음과 같은 Get-or-Create 전략을 세웠다.결제 요청 시 `PENDING..
[운영체제] 프로세스와 스레드의 차이
·
학습 기록/운영체제
메모리 구조 관점에서의 차이프로세스와 스레드의 가장 근본적인 차이는 자원을 어디까지 공유하느냐, 특히 주소 공간(가상 메모리 공간)을 공유하느냐에 있다.이 차이가 곧 격리 수준, 컨텍스트 스위칭 비용, 동시성 버그로 이어진다.프로세스프로세스는 OS로부터 독립된 가상 메모리를 할당받는다.각 프로세스는 서로 다른 주소 공간을 가지므로, 기본적으로 서로의 메모리에 직접 접근 할 수 없다. 프로세스 주소 공간 구성Code(Text): 실행할 프로그램 코드(명령어)Data: 전역 변수, 정적 변수Heap: 런타임 중 동적 할당(Stack): 주소 공간 안에 스택 영역이 존재하긴 하지만, 실제 스택은 스레드마다 별도로 할당된다. 프로세스의 장점한 프로세스가 비정상 종료되더라도, 보통 다른 프로세스는 영향을 덜 받..
[운영체제] 가상 메모리
·
학습 기록/운영체제
가상 메모리란?가상 메모리는 프로세스가 사용하는 가장 주소를 실제 RAM의 물리 주소로 변환하고, 그 과정에서 메모리 보호/격리/효율적 사용을 가능하게 하는 메모리 관리 방식이다.물리 주소: 실제 RAM의 하드웨어 주소가상 주소: 프로세스가 참조하는 논리적 주소 (0번지부터 시작)이 둘의 변환을 수행하는 하드웨어가 MMU(Memory Management Unit)개발자는 실제 RAM의 물리적 위치를 신경 쓰지 않고도 프로그램을 작성할 수 있다.왜 가상 메모리를 써야할까?메모리 보호/격리가상 메모리가 없다면 프로세스 A가 실수로 프로세스 B의 메모리를 덮어써서 시스템 전체가 망가질 수 있다.가상 메모리 환경에서는각 프로세스가 독립된 주소 공간을 가지고페이지 테이블이 프로세스마다 다르므로다른 프로세스의 메모..
[데이터베이스] 트랜잭션 격리 수준과 InnoDB의 격리수준 구현
·
학습 기록/데이터베이스
트랜잭션 특징원자성(Atomicity)트랜잭션 내의 작업은 모두 성공하거나 모두 실패일관성(Consistency)트랜잭션 전 후에 데이터베이스의 제약 조건이 깨지지 않아야 함격리성(Isolation)여러 트랜잭션은 서로에게 영향을 주지 않고 독립적으로 실행지속성(Durability)커밋된 트랜잭션의 결과는 데이터베이스에 영구적으로 저장트랜잭션의 동시성 문제Dirty Read다른 트랜잭션이 변경했지만 아직 커밋되지 않은 데이터를 읽는 현상Non-repeatable Read한 트랜잭션 내에서 같은 Row를 두 번 읽었는데 값이 달라지는 현상Phantom Read한 트랜잭셕 내에서 같은 조건으로 조회했는데 결과 집합이 달라지는 현상트랜잭션 격리 수준정합성과 성능 사이의 균형을 위해 DBMS는 4단계의 표준 격..
[스프링] Facade 패턴으로 트랜잭션에서 외부 API 분리
·
스프링
지난 글에서는 `UPDATE` 쿼리의 원자성을 이용해 단건 좌석에 대한 동시성 문제를 해결하는 과정을 정리했다. 하지만 실제 예매 로직은 단순히 좌석의 상태만 바꾸지 않는다. 할인 정책 적용, 결제(PG사 연동) 등 외부 시스템과의 통신이나 복잡한 비즈니스 로직이 추가되면서 시스템의 복잡도는 증가한다. 이번 글에서는 이러한 환경에서 성능을 어떻게 개선할 수 있을까? 고민을 한 경험을 공유하고자 한다. 기존 로직초기 구현은 데이터 정합성을 위해 예매의 모든 과정을 하나의 트랜잭션으로 묶어서 처리했다.@Service@RequiredArgsConstructorpublic class TicketingService { @Transactional public Long reserveSeat(Long use..