[1편] MSA 이벤트 발행 –

이벤트를 게시해야 하는 이유는 무엇입니까?

MSA의 기능 중 하나는 서비스당 데이터베이스입니다.

즉, 서비스마다 자체 DB가 있습니다.

이를 통해 서비스는 서로 느슨한 결합을 유지할 수 있습니다.

또한 DB 잠금을 획득하여 다른 서비스가 서비스를 차단하는 것을 방지할 수 있습니다.


하지만 서비스마다 DB가 있기 때문에 트랜잭션 관리나 준정규화된 데이터 동기화가 어렵다.

따라서 MSA는 궁극적으로 일관성을 보장하는 방법을 선택합니다.

더보기

** 최종 일관성이란 무엇입니까 **?
결국 데이터 항목에 대한 새로운 업데이트가 없는 경우 해당 항목에 대한 모든 액세스는 가장 최근에 업데이트된 값을 반환합니다.


즉, 데이터의 합이 일시적으로 일치하지 않을 수 있지만 어느 날 동기화가 이루어지면 모든 클라이언트가 동일한 데이터를 얻을 수 있습니다.

그렇다면 궁극적인 일관성을 어떻게 보장합니까? MSA의 한 서비스에서 변경이 발생하면 최종 일관성을 보장하기 위해 변경이 다른 서비스에 전달됩니다.

이 시점에서 이벤트 기반은 다른 서비스에 변경 사항을 알리는 데 사용됩니다.

이 기사에서는 이벤트가 서비스에서 발생하는 방식을 구성하려고 합니다.

예시 소개

강의 관리 플랫폼

강의 관리 플랫폼은 교사가 강의를 업로드하고 학생이 수업에 참여할 수 있는 릴레이 플랫폼입니다.

본 글에서는 강좌 등록, 수정, 삭제가 가능한 강좌 서비스에서 이벤트를 발행하는 과정을 살펴본다.

클래스 서비스 이벤트 파생


이벤트 폭풍

위 사진은 MSA 이지과의 강의 서비스에 대한 이벤트 스토밍 결과입니다.

그 결과 과정 등록(CourseCreatedEvent), 과정 정보 변경(CourseUpdatedEvent), 과정 게시(CoursePostedEvent), 과정 게시 및 미게시(CourseUnpostedEvent), 과정 삭제(CourseDeletedEvent)의 5가지 이벤트가 발생합니다.

이벤트 이용

이벤트가 발생하는 방법을 살펴보기 전에 이 방법으로 발생한 이벤트를 어떻게 사용할 수 있는지 살펴보겠습니다.

첫째, 이벤트와 관련된 정책을 실행하는 데 사용할 수 있습니다.

강의가 게시되면 강의를 홍보하기 위해 마케팅 서비스를 통해 홍보 이메일이 학생들에게 전송된다고 가정합니다.

현재 강의가 게재될 경우 수강생들에게 홍보메일 발송을 원칙으로 하고 있습니다.

이를 구현하기 위해 코스 서비스는 코스 게시 이벤트(CoursePostedEvent)를 게시하고 해당 이벤트를 구독하는 마케팅 서비스는 새 코스가 게시되었음을 알리고 학생에게 홍보 이메일을 보냅니다.


CQRS는 또한 궁극적으로 패턴 사용의 일관성을 보장하는 데 사용됩니다.

쿼리 모델에 대한 명령으로 인해 발생하는 비즈니스 개체에 대한 변경 사항을 전달하는 데 이벤트를 사용할 수 있습니다.

예를 들어 코스가 게시되면(명령) 게시된 코스가 학생 등록 ​​페이지의 목록(쿼리)에 나타나야 합니다.

이를 위해 Course PostedEvent(CoursePostedEvent) 이벤트는 강좌를 게시하라는 명령 작업이 실행될 때 발생하므로 쿼리 모델에도 변경 사항이 반영될 수 있습니다.


CQRS

게시 이벤트

강의를 출판하는 과정을 살펴보자. 코스 리더(교사)는 코스 서비스에 REST API를 통해 코스(postCourse)를 게시하도록 요청합니다.

그러면 코스 서비스는 1) DB 어댑터를 통해 코스의 게시된 값을 1로 변경하고 2) 이벤트 게시 어댑터를 통해 게시된 코스 이벤트(CoursePostedEvent)를 게시합니다.

이 시점에서 고려해야 할 사항 DB 업데이트와 이벤트 출력은 하나의 트랜잭션으로 이루어져야 합니다.

그것은. 그 이유는 DB만 업데이트하고 아직 메시지를 보내지 않은 상태에서 서비스를 중단하면 시스템이 불안정해지기 때문입니다.

따라서 DB 업데이트 및 이벤트 출력은 하나의 트랜잭션으로 원자적으로 수행되어야 하며 MSA 패턴은 이를 가능하게 합니다.

트랜잭션 종료 패턴오전.


강의 서비스 아키텍처

CREATE TABLE `course` (
  `course_id` varchar(36) NOT NULL,
  `name` varchar(45) NOT NULL,
  `thumbnail` varchar(45) NOT NULL,
  `description` varchar(45) NOT NULL,
  `teacher_id` varchar(45) NOT NULL,
  `registered_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `last_updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `posted` tinyint NOT NULL,
  PRIMARY KEY (`course_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;


강의 시리즈 예

트랜잭션 종료 패턴


트랜잭션 아웃박스 패턴(출처: https://microservices.io/patterns/data/transactional-outbox.html)

Outbox 패턴은 OUTBOX 테이블을 임시 메시지 큐로 사용하는 방법입니다.

비즈니스 객체에 대한 CUD-DB 트랜잭션의 일부로 메시지를 OUTBOX 테이블에 삽입합니다.

이는 Business Object를 변경하고 메시지를 임시 메시지 큐인 OUTBOX에 단일 트랜잭션으로 게시하는 프로세스를 실행합니다.

그리고 메시지 릴레이는 OUTBOX의 변경 사항을 읽고 메시지 브로커에게 메시지를 발행합니다.

CREATE TABLE `outbox` (
  `id` varchar(36) NOT NULL,
  `aggregatetype` varchar(255) NOT NULL,
  `aggregateid` varchar(255) NOT NULL,
  `type` varchar(255) NOT NULL,
  `payload` json NOT NULL,
  `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;


OUTBOX 테이블 구름

  • id: 메시지의 고유 ID입니다.

    메시지 작성 시 자동으로 생성됩니다.

    소비자 측에서 중복 메시지를 처리하는 데 사용할 수 있습니다.

  • aggregate_type: 이벤트와 연결된 집계 루트의 유형입니다.

    비즈니스 개체의 CUD는 집계된 루트를 통해 수행됩니다.

    따라서 비즈니스 객체의 변경에 의해 어떤 이벤트가 트리거되는지 알 수 있습니다.

    (예, 과정)
  • aggregate_id: 집계 루트의 ID입니다.

    이 예에서 과정의 ID는 집계의 ID입니다.

  • 유형: 이벤트 유형(예: CoursePostedEvent)
  • 페이로드: JSON 구조의 이벤트 콘텐츠
  • 타임스탬프: 이벤트 출력 시간

메시지 릴레이가 OUTBOX 테이블을 읽고 메시지를 브로커(폴링 발행자 패턴, 트랜잭션 로그 테일링 패턴), 하지만 이 예에서는 트랜잭션 로그 테일링 패턴을 사용합니다.

트랜잭션 로그 테일링 패턴은 DB 트랜잭션에 의해 생성된 로그를 읽고 변경 사항을 하나씩 메시지 브로커에 게시하는 트랜잭션 로그 마이너입니다.

이 예에서는 이를 적용하는 여러 가지 방법이 있습니다.

데시움(Divisium) 오픈 소스를 사용할 계획입니다.

Divisium은 Apache Kafka Message Broker DB 수정을 릴리스하고 mongodb, mysql 및 postgres와 같은 다양한 RDB에 대한 커넥터를 지원하는 오픈 소스 프로젝트입니다.

이 예에서는 MySQL을 통합합니다.


트랜잭션 로그 테일링 패턴(출처: https://microservices.io/patterns/data/transaction-log-tailing.html)

더보기

다음 포스트

(2부) MSA 이벤트 출시 – 구현

다음 파트에서는 ​​강의 관리 플랫폼의 서비스 중 하나인 강의 서비스를 구현하고 Debezium을 사용하여 강의 도메인 이벤트를 트랜잭션 방식으로 발행하는 아웃박스 패턴을 구현해 보겠습니다.