[마이크로서비스패턴] 4장 트랜잭션 관리: 사가

4장. 트랜잭션 관리 : 사가 패턴

4장 핵심내용

  • 분산 트랜잭션이 적잘하지 않은 이유
  • 사가 패턴 통한 데이터 일관성 유지
  • 사가 : 코레오그래피/오케스트레이션 방식
  • 비격리 문제 조치 대첵

마이크로서비스 아키텍처에서의 트랜잭션 관리

서비스마다 DB가 따로 있기 때문에 여러 DB에 걸쳐 데이터 일관성 유지위한 수단 필요.

분산 트랜잭션

과거 분산 트랜잭션 활용해 데이터 일관성 유지(X/Open XA: 분산 트랜잭션의 사실상 표준)

단점

  • NoSQL DB, 현대 메시지 브로커(RabbitMQ, 아파치 카프카) 등 미지원
  • 동기 IPC : 가용성 떨어짐
  • 요즘 애플리케이션에 부적합 : 일관성보다 가용성이 중시.

장점

  • 로컬 트랜잭션과 프로그래밍 모델과 동일

사가

사가는 비동기 메시징을 이용해 편성한 일련의 로컬 트랜잭션. 서비스 간 데이터 일관성은 사가로 유지

  1. ACID 트랜잭션에서 I(격리성)이 사가에는 없음.
  2. 로컬 트랜잭션마다 변경분을 커밋하므로 보상 트랜잭션을 걸어 롤백

로컬 트랜잭션이 완료되면 메시지를 발행 -> 다음 사가 단계 트리거

보상 트랜잭션

사가는 트랜잭션이 진행하는 반대 방향으로 보상 트랜잭션을 실행

사가 편성

사가의 두 가지 종류 : choreography, orchestration

코레오그래피 사가

의사 결정과 순서화를 사가 참여자에게 맡김. 사가 참여자는 주로 이벤트 교환 방식으로 통신
중앙 편성자 부재. 대신 사가 참여자가 서로 이벤트 구독 통해 그에 따라 반응

사가 참여자 간 발행/구독 방식 문제점

  • 사가 참여자가 자신의 DB를 업데이트하고, DB 트랜잭션의 일부로 이벤트를 발행하도록 해야 함 : 트랜잭셔널 메시징
  • 사가 참여자는 자신이 수신한 이벤트와 자신이 가진 데이터를 연관 지을 수 있어야.
    • 상관관계 ID가 포함된 이벤트 발행 필요

장단점

장점

  • 단순 : 비즈니시 객체 생성, 수정, 삭제할 때 서비스가 이벤트 발행
  • 느슨한 결합 : 참여자는 이벤트를 구독. 직접 알진 X

단점

  • 이해하기 어려움 : 여러 서비스에 구현 로직 산재.
  • 서비스 간 순환 의존성 : 이벤트로 인한 순한 의존 가능성
  • 단단히 결합 위험성

===> 간단한 사가의 경우 코레오그래피 방식도 충분. but, 복잡한 사가는 오케스트레이션이 적합

오케스트레이션 사가

사가 편성 로직을 사가 오케스트레이터에 중앙화. 사가 오케스트레이터는 사가 참여자에게 커맨드 메시지를 보내 수행 작업 지시
사가 오케스트레이터는 커맨드/비동기 응답 상호 작용통해 참여자와 통신

커맨드 메시지 전송 -> 사가 참여자 작업 수행 & 응답 -> 오케스트레이터 응답 처리 -> 다음 사가 단계 참여자에게 커맨드 -> …

사가 오케스트레이터를 상태 기계로 모델링

상태 기계?

  • 구성 : 상태 & 상태 전이
  • 사가 참여자가 로컬 트랜잭션 완료 시점 트리거됨 -> 로컬 트랜잭션 상태, 결과 기준 차후 상태 전이 및 액션 결정
  • 설계, 구현, 테스트 용이

장단점

장점

  • 의존 관계 단순화 : 순환 의존성 발생 X
  • 낮은 결합도
  • 관심사를 더 분리하, 비즈니스 로직 단순화

단점

  • 과도한 책임의 오케스트레이터
    • 오케스트레이터는 순서화만 담당. 비즈니스 로직 미포함하도록 설계 통해 해결

비격리 문제 처리

사가는 격리성이 빠져있음.

  1. 한 사가가 실행 중에 접근하는 데이터를 도중에 다른 사가가 바꿔치기 가능성 존재
  2. 한 사가가 업데이트 하기 이전 데이터를 다른 사가가 읽을 수 있어 데이터 일관성 깨질 수 있음
    • Spring Data의 save()는 전체 프로퍼티 update : 만약 변경 전 데이터 읽은 후 save하면 변경 전 값이 반영될 수 있음…ㅜ
      • Hibernate의 @DynamicUpdate, JPA의 @Column 통해 변경된 데이터만 변경 가능

비정상

소실된 업데이트

한 사가의 변경분을 다른 사가가 미처 못 읽고 덮어씀.

더티 읽기

사가 업데이트를 하지 않은 변경분을 다른 트랜잭션이나 사가가 읽음.

퍼지/반복 불가능한 읽기

한 사가의 상이한 두 단계가 같은 데이터를 읽어도 결과가 달라지는 현상. 다른 사가의 그 사이 업데이트가 원인

비격리 대책

사가 구조

세 가지 트랜 잭션으로 구성

  1. 보상 가능 트랜잭션 : 보상 트랜잭션으로 롤백 가능한 트랜잭션
  2. 피봇 트랜잭션 : 사가의 진행/중단 지점. 피봇 트랜잭션 커밋 시 사가는 완료될 때까지 실행. 최종 보상 트랜잭션 또는 최초 재시도 가능 트랜잭션이 될 수 있음.
  3. 재시도 가능 트랜잭션 : 피봇 트랜잭션 직후의 트랜잭션. 반드시 성공.
단계서비스트랜잭션보상 트랜잭션사가 트랜잭션
1OrdercreateOrder()rejectOrder()보상 가능
2ConsumerverifyConsumerDetails()-보상 가능
3KitchencreateTicket()rejectTicket()보상 가능
4AccountingauthorizeCreditCard()-피봇
5Restaurant OrderapproveRestaurantOrder()-재시도 가능
6OrderapproveOrder()-재시도 가능

대책: 시멘틱 락

보상 가능 트랜잭션이 생성/수정하는 레코드에 무조건 플래그를 세팅하는 대책

플래그 용도

  • 레코드 접근 불가하도록 Lock
  • 다른 트랜잭션이 접근해서 사용시 warning

플래그는 재시도 가능 트랜잭션(사가 완료) 또는 보상 트랜잭션(사가 롤백)에 의해 해제

eg) *_PENDING 과 같은 상태 코드 프로퍼티
PENDING 중 다른 요청이 오는 경우? (createOrder() -> cancelOrder())

  1. 클라이언트에게 책임 넘긴다 ㅋㅋ : 다시 시도하세요~
  2. 락 해제 때까지 블로킹 : 애플리케이션에서 락 관리해야 하는 부담 감수 필요. 데드락 발생 시 사가 롤백 및 데드락 해소 재실행 조치해야.

대책: 교환적 업데이트

업데이트 작업은 어떤 순서로 실행해도 되게끔 설계

eg) 계좌의 인출<->입금 : 상호 교환적 업데이트

대책: 비관적 관점

사가 단계 순서를 재조정하여 비즈니스 리스크 최소화

더티 리드 막기 위해 단계 재조정

대책: 값 다시 읽기

데이터 덮어 쓸 때 그 전에 변경된 내용은 없는지 값을 다시 읽고 확인

소실된 업데이트 방지 대책. 낙관적 오프라인 락 : 값을 재읽기 -> 만약 변경 시 사가 중단. 나중에 재실행

대책: 버전 파일

순서를 재조정할 수 있게 업데이트 기록

레코드에 수행한 작업을 하나하나 기록하는 대책.

대책: 값에 의한

요청별 비즈니스 위험성을 기준으로 동시성 메커니즘을 동적 선택

사가? 분산 트랜잭션? 어떤 걸 쓸지 애플리케이션에서 판단

정리

  • __ : 메시징으로 편성한 일련의 로컬 트랜잭션
  • __ : 로컬 트랜잭션이 이벤트 발행. 다른 참여자가 로컬 트랜잭션을 실행하도록 트리거하는 사가의 한 방식.
  • __ : 중앙의 사가 오케스트레이터가 참여자에게 로컬 트랜잭션을 실행하라고 커맨드 메시지를 보내 지시하는 사가의 또 다른 방식.