Tech/Kafka

Kafka 트랜잭션과 Spring 트랜잭션 시점 차이로 인한 데이터 일관성 문제

봄의 개발자 2024. 5. 23.
728x90
반응형
 

들어가며

카프카를 사용하면서 카프카 트랜잭션과 스프링 트랜잭션의 시점 차이로 인한 데이터 일관성 문제에 대해 해결한 글을 작성할 예정이다. 이는 결론적으로 트랜잭션과 카프카 이벤트 발행 사이에서 발생하는 정합성 문제이다.

 


문제 상황

발생한 문제의 상황은 트랜잭션 내에서 데이터 변경 후 이벤트를 발행하는 경우, 다른 서비스에서 트랜잭션 커밋 이전의 데이터를 사용할 때이다. 이때 예외가 발생해버리는 것이다. 

 


문제 원인 및 해결

트랜잭션이 커밋되기 이전에 카프카 이벤트를 발행하면, 트랜잭션의 실패 여부와 상관없이 이벤트는 발행되도록 구현했던 것이 문제의 원인이었다. 이를 해결하기 위해 TransactionalEventListener를 활용했다. 

 

현재 spring transaction이 후에 kafka 이벤트가 produce 되는 것을 목표로 한다. TransactionalEventListener 이를 활용하면 트랜잭션 결과에 따라 이벤트 발행 시점을 정할 수 있게 된다. 나는 경우에 따라 커밋 혹은 롤백 이후에 이벤트가 발행되도록 구현했다.

 

우선 코드부터 살펴보자.

 

 

@TransactionalEventListener 해당 어노테이션을 사용해서 phase 옵션으로 이벤트 발생 시점을 설정할 수 있다. 24번째 라인에서 볼 수 있듯이 트랜잭션 커밋 이후에 이벤트가 발행되도록 구현했다.

 

그렇다면 phase 옵션에서 사용할 수 있는 값의 종류를 간단하게 알아보자.

 

  • BEFORE_COMMIT: 트랜잭션이 커밋되기 전에 이벤트 리스너가 실행됨
  • AFTER_COMMIT: 트랜잭션이 성공적으로 커밋된 후에 이벤트 리스너가 실행됨
  • AFTER_ROLLBACK: 트랜잭션이 롤백된 후에 이벤트 리스너가 실행됨
  • AFTER_COMPLETION: 트랜잭션이 완료된 후(커밋 또는 롤백)에 이벤트 리스너가 실행됨

 

결과

주문 상품(재고 감소) api 호출 시 product service에서 분산 락을 통해 동시성 제어를 하며 재고를 감소한다.

 

 

스프링 트랜잭션 적용 전

트랜잭션이 시작되고 종료되기 전에 sent: ProducerRecord(...) 와 같은 로그가 찍히는 걸 볼 수 있다.

 

스프링 트랜잭션 적용 후

우선 트랜잭션이 모두 완료된 후에

 

이렇게 이벤트가 발행되는 것을 확인할 수 있다.

 


 

마치며

@TransactionalEventListener를 활용해서 트랜잭션의 결과(커밋 또는 롤백)에 따라 이벤트를 발행하도록 했다.

트랜잭션이 성공적으로 커밋됐을 때 이벤트를 발행하도록 구현하고, 만약 트랜잭션이 롤백되는 경우에는 실패와 관련된 이벤트를 발행하도록 구현을 했다. 이렇게 함으로써 데이터 일관성 문제를 해결할 수 있게 되었다.

728x90
반응형

댓글