마이크로서비스패턴[4] — 4장
4장 트랜잭션 관리: 사가
1장 모놀리식 지옥에서 벗어나라
2장 분해 전략
3장 프로세스 간 통신
4장 트랜잭션 관리: 사가
5장 비즈니스 로직 설계
6장 비즈니스 로직 개발: 이벤트 소싱
7장 마이크로서비스 쿼리 구현
8장 외부 API 패턴
9장 마이크로서비스 테스트 1부
10장 마이크로서비스 테스트 2부
11장 프로덕션 레디 서비스 개발
12장 마이크로서비스 배포
13장 마이크로서비스로 리팩터링
사가라는 단어는 평소에 아주 드물게 접할 수 있는 단어이다.예전에 포가튼사가라는 게임도 있었는데,지금은 사가라고 검색해보면 ***사가라고 게임들이 주로 나타난다.
사가(saga)란 단어는 아이슬란드어로 ‘말로 전하다’라는 의미라고 한다. 사용할때는 비슷한 의미로 ‘서사시(epic)'가 있지만, 개인적인 생각으로는 나름 멋드러지게 사용하려고 개발쪽에서 사용하지 않았을까싶기도 하다. 결국 무언가의 일관적인 관리를 위해서 사용하는 뉘앙스로 용어를 받아들이면 이해가 쉬울것같다.
4. 사가
단일 서비스 내부의 트랜잭션은 ACID가 보장하지만, 여러 서비스의 데이터를 업데이트하는 트랜잭션은 구현하기가 까다롭다. 그런 문제점을 해결하기 위해 나온것이 필요한 것이 사가(saga)라는 메시지 주도 방식의 로컬 트랜잭션이다.
사가는 ACID에서 I(격리성)이 빠진 ACD만 지원하며, 격리가 되지 않기 때문에 동시에 비정상적인 문제가 발생할 방법을 줄일 수 있는 설계 기법을 함께 고민해야 한다.
4.1.마이크로서비스 아키텍처에서의 트랜잭션 관리
모놀리식 아키텍처로 구현된 어플리케이션 스프링프레임워크 기반으로 만들어졌다면 @Transactional 만으로로도 ACID가 자동으로 걸려 데이터의 일관성을 보장할 수 있다. 마이크로 서비스 아키텍처로 구현하는 경우 분산 트랜잭션을 통해 문제를 해결하려고 시도할 수도 있는데, MongoDB 나 RabbitMQ, 아파치 카프카등은 분산 트랜잭션을 지원하지 않기 때문에 기술적인 문제가 있다는 점을 이해할 필요가 있다.
- 데이터 일관성 유지: 사가패턴
사가는 마이크로서비스 아키텍처에서 분산 트랜잭션 없이 데이터 일광성을 유지하는 매커니즘이다. 여러 서비스의 데이터를 업데이트하는 시스템 커맨드마다 사가를 하나씩 정의한다.
위 그림에서 사가에서 3개의 로컬 트랜잭션을 볼 수 있는데, 각 서비스는 로컬 트랜잭션이 완료되면 메시지를 발행하여 다음 사가단계를 트리거한다. 메시지를 통해 사가 내 서비스들의 관계를 느슨하게 결합하고, 사가가 반드시 완료되도록 보장할 수 있는 것이다.
- 보상 트랜잭션을 통한 변경분 롤백
ACID 트랜잭션은 에러발생시 쉽게 롤백이 가능하지만, 사가는 로컬DB에 변경분을 커밋하므로 자동 롤백이 불가능하다. 그렇기 때문에 만약 사가 단계중 실패(비즈니스 에러 등)가 일어나면 이전 단계들을 하나씩 undo하는 보상 트랜잭션을 미리 작성해야한다.
4.2. 사가편성
사가는 단계를 편성하는 로직으로 구성된다. 사가를 편성하는 로직은 2가지 종류가 있다.
- 코레오그래피(choreography)
의사 결정과 순서화를 사가 내 서비스에에게 맡긴다. 사가 내 서비스들은 이벤트 교환방식으로 통신한다. - 오케스트레이션(orchestration)
사가 오케스트레이터에 사가 편성 로직을 중앙화한다. 사가 오케스트레이터는 사가 내 서비스에게 커맨드 메시지를 보내 수행할 작업을 지시한다.
코레오그래피(choreography) 사가
사가 내 서비스들은 자신의 db를 업데이트하고 다음 서비스를 트리거하는 이벤트를 발행하며 프로세스를 진행한다.
- 통신이슈
- 서비스가 자신의 DB를 업데이트하고, DB 트랜잭션의 일부로 이벤트를 발행하도록 해야 한다. 각 작업들은 원자적(atomically)으로 일어나야 하므로, 이전 3장의 트랜잭셔널 메시징을 사용해야 한다. - 수신한 데이터와의 매핑
다른 서비스에게 상관관계ID가 포함된 이벤트를 발행하여, 받는 서비스가 보내는 서비스의 내용과 연관성을 알 수 있게 해야한다.
오케스트레이션(Orchestration) 사가
사가 내 서비스들이 할 일이 지정된 오케스트레이션 클래스를 정의하고, 사가 오케스트레이터는 커맨드/비동기 응답 상호작용을 하여 서비스들에게 통신을 한다.
오케스트레이션 사가는 각 서비스들의 의존관계를 낮출 수 있고 비즈니스 로직을 단순화 할 수 있다는 장점이있지만, 오케스트레이션에 기능이 너무 많이 중앙화 될 수 있다는 단점도 존재한다. 이 단점은 오케스트레이터가 순서화만 담당하고 비즈니스 로직은 갖지 않도록 설계를 함으로써 해결할 수 있다.
4.3 비격리 문제 처리
위 사가는 서비스들간에 통신을 유용하게 하지만, 트랜잭션간의 격리성을 보장할 수 없기 때문에 데이터의 일관성이 깨줄 수 있다는 문제점이 보인다. 격리수준을 정하고 대책수준을 선택하여 보완하는 것이 좋다.
- 시맨틱 락 : 레코드에 플래그를 셋팅해서 락을 걸거나 경고를 알림(confluence에서 기능을 볼 수 있음)
- 교환적 업데이트 : 순서에 상관없이 실행 가능하도록 설계
- 비관적 관점 : 더티 읽기를 최소화하기 위해 사가 단계의 순서를 재조정
- 값 다시 읽기 : 사가가 레코드를 업데이트 하기 전에 다시 값을 읽어 값이 변경되었는지 재확인
- 버전 파일 : 레코드에 수행한 작업을 하나하나 기록하는 방법.
- by value : 어플리케이션이 요청의 속성을 보고 사가를 쓸지 분산 트랜잭션을 쓸지 자율적으로 판단.
사가의 기본적 개념들은 위 내용을 인지하는것으로 충분하지 않을까라는 생각이든다. 책에서는 이후의 내용들은 예제로 설명하는데, 아무래도 추후 간단한 프로젝트를 만들어서 적어보는게 좋을 것 같다. 아쉬운건 이 책만큼 마이크로서비스에 대해 개념과 더불어 코드까지 알려주는 책은 없다는 것이다.
(내가 모를 수도..)