본문 바로가기

문제 해결 경험

@Transactional 격리 수준 - 오류 발생 경험

이번 포스팅에서는 @Transaction의 격리수준을 알고 있었지만, 실제 운영환경에서 에러를 냈던 경험에 대해서 포스팅하려고 합니다. 그리고 격리수준에 대해서는 간단하게만 적어보려 합니다.

 

트랜잭션 격리 수준(4단계)

트랜잭션의 격리 수준이란??
동시에 여러개의 요청이 들어왔을때, 트랜잭션별로 영향을 끼치는 정도라고 생각하면 될 것 같습니다. 그리고 그 격리 수준에따라 다른 트랜잭션이 변경 된 데이터를 읽을 수 있는지 없는지 결정되게 됩니다.

간단하게 격리 수준을 정리해보면.. 아래와 같이 4단계로 구분이 됩니다.

 

READ_UNCOMMITED(0단계)

1. commited되지 않은 데이터를 읽을 수 있는 격리 수준이기 때문에 데이터의 정합성이 맞지 않을 확률이 큽니다.

2. Dirty Read 발생 가능

 A트랜잭션에서 데이터를 변경하고 커밋되지 않은상태에서 B트랜잭션이 해당 데이터를 읽었는데, A트랜잭션에서 에러가 나서 롤백이 된다면 B트랜잭션이 읽은 데이터는 정확하지 않은 데이터입니다.

READ_COMMITED(1단계)

1. commited이 이루어진 데이터만 읽을 수 있는 격리수준

2. Non-Repeatable Read 발생 가능

A트랜잭션이 어떤 유저의 나이정보를 조회(20살)하고 B트랜잭션이 유저의 나이정보를 수정하고 커밋(21살)하였는데, A트랜잭션에서 다시 그 유저의 나이를 조회하면 21살로 되어 있는 현상입니다.

REPEATABLE_READ(2단계)

1. Non-Repeatable Read가 발생하지 않음.

 - A트랜잭션이 10번 사원의 이름을 조회(이름 =.자바)

 - B트랜잭션이 10번 사원의 이름을 수정하고 커밋(이름 = 자바수정)

 - A트랜잭션이 10번 사원의 이름을 조회(이름 = 자바)

SERIALIZABLE(3단계)

1. 가장 엄격한 레벨로 데이터의 정합성이 보장되는 격루수준입니다.

2. 데이터의 정합성이 보장 된 대신 여러개의 트랜잭션이 들어올 경우 대기해야하는 시간이 발생.

3. 성능이 중요한 서비스에서는 사용하지 않는게 좋음.

 

에러 상황!!

룰렛 이벤트에서 응모권을 사용하여 할인 쿠폰이 당첨되면 고객에게 쿠폰 번호가 노출되는 로직이 있었습니다.

하지만, 쿠폰이 당첨 되었음에도 불구하고 고객에게 쿠폰 번호가 노출되지 않는 에러가 live환경에서 발생하게 되었습니다.

왜 이런 상황이 발생하게 되었는지 자세하게 설명해보도록 하겠습니다.

1. 사전 상황

1 - 1. Replication 방식인 Master / Slave 구조의 DB방식

  • Master DB에 커밋이 되면 Slave DB로 데이터 동기화를 진행
  • 어플리케이션에서 insert, update, delete는 Master DB에서 진행
  • 어플리케이션에서 select는 Slave DB에서 진행.

1 - 2. 당첨 메소드의 @Transactional 선언

당첨 메소드를 간단하게 요약해보면 3가지 순서로 진행이 됩니다.

 

해당 메소드에는 @Transactional이 선언이 되어있고, live환경은 RDS가 Master Slave구조로 되어있어서 에러가 발생하였습니다. 그 이유는 @Transactional을 선언하였기 때문인데 저희 DB는 기본적으로 격리 수준이 READ_COMMITED단계라 커밋되지 않은 데이터는 읽을 수 없었습니다. 

 

1 - 3. 해결 방안

간단하게 @Transactional을 제거하게 되면, 쉽게 해결되는 문제지만 데이터의 정합성을 위해 메소드를 분리하는 방법을 선택하게 되었습니다. 즉, 아래 부분을 조회하는 로직을 @Transactional에서 따로 분리하여 Controller에서 Service를 호출하는 방식을 사용하여 문제를 해결 할 수 있었습니다.

 

고객의 응모권을 사용하는 이벤트라 고객센터에 당첨 문의도 많이 들어오고, 마음은 급하고 개발에서는 재현이 안되어서 찾는데 오랜시간이 걸렸지만, 이론으로만 배웠던 트랜잭션의 격리 수준을 직접 몸으로 경험하게 되어서 저에게 많은 도움이 되었던 이벤트라고 생각이 듭니다.

 

 

'문제 해결 경험' 카테고리의 다른 글

Thread를 활용한 비동기 처리  (0) 2023.01.08