saga 디자인 패턴은 분산 트랜잭션 시나리오에서 마이크로 서비스 간의 데이터 일관성을 관리하는 방법
saga는 각 서비스를 업데이트하고 메시지 또는 이벤트를 게시하여 다음 트랜잭션 단계를 트리거하는 일련의 트랜잭션이다. 단계가 실패하면 sags는 이전 트랜잭션을 상쇄하는 보상 트랜잭션을 실행
컨텍스트 및 문제점
트랜젹션 내에서 발생한 이벤트는 엔티티에 발생하는 상태변경이며 작업을 수행하거나 이후 이벤트를 트리거하는데 필요한 정보를 캡슐화 한다.
트랜잭션은 ACID 특성을 가진다. 하지만 이건 단일 서비스에서의 문제이고 여러 서비스가 얽혀있다면 복잡해진다.
다중 서비스 아키텍처에선?!
- 원자성은 모두 발생하거나 모두 발생하지 않아야 하는 돌이킬 수 없는 작업 세트
- 일관성은 트랜잭션이 유효한 상태의 데이터만 다른 유효한 상태로 가져온다는 것
- 격리는 동시 트랜잭션이 순차적으로 실행된 트랜잭션이 생성한 것과 동일한 데이터 상태를 생성할 수 있도록 보장
- 내구성을 통해 시스템 오류 또는 정전 시에도 커밋된 트랜잭션이 커밋도니 상태로 유지
마이크로 서비스 별로 다른 데이터베이스를 사용하면 각 서비스가 사용하는 도메인의 상태를 최상의 품질로 유지할 수 있고 다른 서비스의 오류로부터 격리 시킬 수 있다. 그렇지만 데이터베이스 간에 일관성을 보장하는데 문제가 생김
해결 방법
사가 패턴은 로컬 트랜잭션을 사용하여 트랜잭션 관리를 제공한다. 로컬 트랜잭션은 사가 참가자가 수행하는 원자성 작업이다. 각 서비스의 로컬 트랜잭션은 이벤트로 받아온 요청을 처리하고 다음 서비스로 트리거 한다. 이것이 일련의 보상 트랜잭션이다.
SAGA 패턴
- 보상 가능한 트랜잭션은 반대 효과를 가진 다른 트랜잭션을 처리하여 잠재적으로 되돌릴 수 있는 트랜잭션이다.
- 피벗 트랜잭션은 saga의 이동 없음 지점이다. 피벗 트랜잭션이 커밋되면 saga가 완료될 때까지 실행된다.
- 다시 시도 가능한 트랜잭션은 피벗 트랜잭션을 따르는 트랜잭션이며 성공이 보장된다.
saga 패턴 구현 방법은 2가지
- 연출
- 오케스트레이션
방법1) 연출
참가자가 중앙 집중식 제어 지점 없이 이벤트를 교환하는 saga를 조정하는 방법. 각 로컬 트랜잭션은 연출을 사용하여 다른 서비스에서 로컬 트랜잭션을 트리거하는 도메인 이벤트를 게시한다.
이점
- 참가자가 거의 없고 조정 논리가 필요하지 않은 간단한 워크플로우에 적합
- 추가 서비스 구현 및 유지보수 불필요
- 책임은 saga 참가자에게 분산되어 단일 실패 지점을 도입하지 않음
단점
- saga 참가자의 어떤 명령을 수신대기 하는지 파악이 안되어 새 단계 추가시 어려움(워크플로우 혼동)이 있다.
- 서로의 명령을 소비해야해서 참가자 간에 순환 종속성이 발생할 수도 있다
- 트랜잭션을 테스트하려면 모든 서비스를 실행해야 해서 통합 테스트가 어렵다
방법2) 오케스트레이션
중앙 컨트롤러가 사가 참가자들에게 실행할 로컬 트랜잭션을 알려주는 saga 조정 방법이다. 오케스트레이터는 요청을 실행하고, 각 작업의 상태를 저장 및 처리하여 보상 트랜잭션을 사용하여 오류 복구를 처리한다.
이점
- 새 참가자를 추가하여 변경하는데 이점이 있다
- 모든 참가자를 제어하고 활동 흐름을 제어할 수 있을 때 좋다
- 오케스트레이터는 참가자들에게 의존하기 떄문에 순환 종속성을 도입하지 않는다
- 참가자는 다른 참가자의 명령에 대해서 알 필요가 없다 (관심사 분리가 된다)
단점
- 추가 디자인 복잡성을 위해서는 조정 논리를 구현해야 한다.
- 오케스트레이터가 전체 워크플로우를 관리하기 때문에 추가 실패 지점이 있다
문제 및 고려 사항
- 사가 패턴은 디버깅이 어렵고 참가자가 증가하면 할수록 복잡성이 증가한다
- 사가 패턴은 트랜젹슨을 조정하고 여러 서비스에 걸쳐서 데이터의 일관성을 유지하는 방법에 대한 새로운 사고 방식이 필요하기 떄문에 초반에는 어렵다
- saga 워크플로우를 모니터링하고 추적하는 가시성을 구현하는 것이 가장 좋다
- 참가자 데이터 격리가 부족하면 내구성 문제가 발생, saga 구현에는 변칙을 줄이기 위한 대책이 포함되야 한다 (이해가 안가는 부분,,,후)
변칙을 줄이거나 방지하기 위한 제안된 대책
- 의미 체계 잠금: Saga의 보상 가능한 트랜잭션이 세마포를 사용하여 업데이트가 진행 중임을 나타내는 애플리케이션 수준 잠금입니다.
- 통근 업데이트: 순서에 따라 실행되고 동일한 결과를 생성할 수 있습니다.
- 비관적 보기: 한 Saga는 작업을 롤백하기 위해 보상 가능한 트랜잭션을 실행하고 있는 동안 다른 Saga가 더티 데이터를 읽을 수 있습니다. 비관적 보기는 Saga를 다시 정렬하여 재시도 가능한 트랜잭션에서 기본 데이터가 업데이트되므로 더티 읽기의 가능성이 제거됩니다.
- 값 다시 읽기는 데이터가 변경되지 않았는지 확인한 다음, 레코드를 업데이트합니다. 레코드가 변경되면 단계가 중단되고 Saga가 다시 시작될 수 있습니다.
- 버전 파일은 레코드가 도착하는 동안 레코드에 대한 작업을 기록한 다음, 올바른 순서로 실행합니다.
- 값별로 각 요청의 비즈니스 위험을 사용하여 동시성 메커니즘을 동적으로 선택합니다. 위험 수준이 낮은 요청은 Saga를 선호하지만 위험 수준이 높은 요청은 분산 트랜잭션을 선호합니다.