-
EDA ( Event - Driven -Architecture)DESIGN PATTERN & ARCHITECTURE 2022. 9. 29. 22:37
최근 아키텍쳐에 관한 강의를 듣고 EDA에 대해 희미하게 나마 생각해보다가,
동기분 께서 설명해주신 부분을 듣고 공부하면 좋을 것 같아 작성하게 되었다! 🙌
면접 준비를 하면서 Monolithic Architecture나 MicroService Architecture에 대해서는 공부했지만
EDA 부분은 자세히 알지 못했기 때문에 영상을 찾아보았고,
사진 부분은 모두 유튜브 설명 영상 내용을 캡쳐하였다.
Reference 영상
- ( 영상을 캡쳐하여 정리하는데 참고하였습니다 🙌)
- https://www.youtube.com/watch?v=LHgCA3XVNkw
기존의 Monolithic Architecture
MSA (Micro Service Architecture)
- 도커위에 각각의 서비스에 대한 쿠버네티스 pod을 올리고 각각 health check를 하며 통신
- 데이터에 접근하거나 api 서비스로부터 정보를 받아오는 것이 synchronized하게 발생
- Ask → wait 패턴 (다른 api의 응답을 기다리며 서로 의존적인 모습)
- 아무리 작은 MSA로 구성하더라도 서버가 다운되면 정보의 손실 발생 가능성
-SAGA 패턴
- 기존의 monolithic 구조에서는 구매에 대한 여러가지 반응들이 하나의 트랜잭션 안에서 발생하고 하나의 DB에 반영되어 DBMS의 트랜잭션 기능을 통해 commit 혹은 rollback이 일관성있게 관리
- Applcation 과 DB가 분산된 MSA에서는 트랜잭션 처리를 단일 DBMS에서 제공하는 방식으로 해결이 불가
- 대안 1) Two-Phase Commit
- prepare phase와 commit phase를 나눔
- prepare phase 단계
- transaction co-ordinator → request-to-prepare 요청 → resource managers
- transaction co-ordinator ← prepared 응답 ← resource managers
- commit phase 단계
- transaction co-ordinator → commit 요청 → resource managers
- transaction co-ordinator ← done 응답 ← resource managers
- 하나의 서비스가 장애가 있는 경우나 동시에 각각의 서비스에 락킹이 걸리면 성능의 문제가 발생하여 비효율적
- 각각의 서비스가 다른 인스턴스에 존재하여 통제에 어려움
- 대안 2) SAGA 패턴
- MS 끼리 이벤트를 주고받아 하나의 MS에서 작업이 실패하면 이전의 MS들에게 보상(compensation)이벤트를 주어 분산환경에서도 원자성 보장
- 트랜잭션의 관리 주체가 DBMS가 아닌 Application에 존재하며 각각의 어플리케이션은 각각의 DB에 로컬 트랜잭션만을 담당하여 보상 처리를 어플리케이션이 구현
- 마지막 트랜잭션까지 처리 완료되어 영속화 되면 최종 일관성(eventually consistency) 달성
- Orchestration 방식과 Choreography 방식이 존재
— SAGA - 1) Orchestation 방식
- 트랜잭션 처리를 위한 SAGA 관리자 인스턴스(ORDER)가 별도로 존재
- 트랜잭션에 관여하는 모든 어플리케이션은 관리자에 의해 순차적으로 트랜잭션을 수행하고 결과 전달
- 마지막 트랜잭션이 끝나면 관리자를 종료하고 전체 트랜잭션 처리 종료
- 중간에 Fail 발생시 매니저가 보상 트랜잭션을 발생시켜 일관성 유지
- 즉, 관리자가 트랜잭션을 관리하여 분산 트랜잭션의 중앙 집중화를 이룸
- 장점
- 서비스간의 복잡성 감소 (구현 및 테스트 용이)
- 트랜잭션 상태를 알고있는 매니저에 의해 롤백이 용이
- 단점
- 관리자를 위한 Orchestrator 서비스 추가로 인해 인프라 구현의 복잡도 증가
— SAGA - 2) Choreography 방식
- 보유한 서비스내(Application)에서 로컬 트랜잭션을 관리 → 트랜잭션 실패시 해당 Application에서 보상 이벤트를 발생시켜 롤백 처리
- 순차적으로 트랜잭션 발생
- 트랜잭션 종료 시 이벤트 발행 (다음 수행될 트랜잭션이 존재하면 다음 트랜잭션에게 이벤트 발행)
- 이벤트는 kafka와 같은 메세지 큐를 이용해 비동기 방식으로 전달이 가능
- 장점
- 구성에 용이
- 단점
- 운영자가 트랜잭션의 현황을 파악하는데 어려움
cf) 항상 SAGA 패턴이 옳은가?
- 여러곳에서 트랜잭션을 처리하게 되면 복잡도가 증가하게 되므로 비지니스 로직상 트랜잭션 처리가 필요한 경우에만 사용하는 것이 좋음
EDA (Event Driven Architecture) = Message Driven
- 람다 베이스의 잘 디자인된 MSA 원칙
- 특징
- 이벤트를 이용하여 polling, webhooks를 대체
- 복잡성 감소
- scalability (확장성 증가)
- 실시간 분석 가능
- decoupling
- dependency inversion
- 단, 언제 어떻게 일어나는지에 대한 정보의 추적이 필요
- 사용 시기 : performance 보다 scalability가 더 중요할 때
- eventual consistency : 이벤트 송수신이 동시에 발생하지 않음 ⇒ 이벤트 분실 염려 감소
- complexity : 이벤트가 서로 다른 다양한 이벤트를 유발시킬 수 있음
- data replication / parallel processing : 이벤트에 따라서 각각의 서비스들이 각각의 데이터베이스에 정보 전달
- kafka(pipe)를 이용하여 이루어진 이벤트 스트리밍 플랫폼
- 하루에 조 단위의 이벤트 처리가 가능
- 처음에는 분리된 commit log로 message queue로 인식되었으나 스트리밍 플랫폼으로 진화
- 흐름 :
- 각각의 api가 Producer와 Consumer를 생성
- 사용자 정보 수정 이벤트 발생
- 서비스 플랫폼 api 선택
- 사용자 정보 수정
- kafka 이벤트 큐( topic )에 이벤트 추가
- 사용자 정보가 수정되는지 듣고있던 다른 api가 변화발생 감지
- Consumer api 데이터 베이스에 반영 (각각의 Consumer가 각각의 요청 처리)
- 전체적인 흐름
- Producer가 정보(event)를 생성 후 topic (이벤트 큐)에 넣음
- Consumer가 소비하기 전까지는 이벤트가 큐에 존재 (kafka)
- Consumer가 소비하게 되면 큐에서 꺼내짐
- Events
- 소프트 웨어 시스템에서 발생할 수 있음
- 이벤트를 통해 다른 액션을 유발 시킬 수 있음
- 그룹화된 party들이 event 발생 시 전체 trigger가 될 수도 있음
- 여기서 이벤트는 데이터를 포함하거나 그저 상황이 발생함을 알리는 용도로 사용될 수도 있음
- IMMUTABLE
- ex) 사용자 정보 업데이트, 카드 정보 수정 등
- Event Streaming Architecture
- 각각의 서비스가 이벤트 발생을 알림
- 이벤트 큐의 party들이 관심있으면 queue에서 꺼내고 관심이 없으면 남겨둠
- Tell / get 패턴 → 다른 party와 상관없이 사용자 정보가 바뀌면 tell하면 끝
- Streaming Data
- 일정한 정보의 흐름
- 각각이 상태변화 이벤트에 대한 정보를 가져 실시간으로 시스템에 전달
- 데이터 타입이나 이벤트의 성질이 결과적 액션에 영향
-EDA의 예시 1) External Integration
- 외부와의 통합 예시
- 1) AWS SES의 Email send 이벤트 발생
- 2) Broker(메세지 큐)에 이벤트 등록
- 3) 해당 이벤트를 듣고 있던 Consumer(Email, Webhooks)가 소비
- 4) 각각 AWS SES, HTTP API 통신 (여기서 AWS SES 전달과 동시에 각각의 쓰레드나 프로세스를 통해 논리적 decoupling으로 HTTP API 전달 → HTTP API가 먼저 종료되고 그 후 AWS SES가 종료될 수도 있음)
- 5) 이후 다른 이벤트인 SMS 이벤트 발생 (동일하게 진행)
-EDA의 예시 2) Workflow
- 실행 순서에 따라 차례대로 발생되는 workflow 형태
- 1) 주문 이벤트 발생
- 2) 주문 이벤트를 읽고 있던 Billing이 Order placed 이벤트를 소비
- 3) 소비후 처리를 마친 Billing이 Order billed 이벤트 생성
- 4) 이를 수신하고 있던 Warehouse가 이벤트 소비
- 5) 이벤트를 소비한 Warehouse가 Shipping Label Created 이벤트 생성
- 6) 이를 수신하는 Sales측에서 이벤트 소비
-EDA의 예시 3) State Transfer
- 상태변화 이벤트를 수신
- 1) Producer가 상태변화에 대한 이벤트 생성 이벤트 큐에 등록
- 2) 수신하는 Consumer가 이벤트를 수신
- 3) 수신한 상태에 따라 Cache, DataWarehouse 등을 업데이트
-EDA의 예시 4) Temporal decoupling
- 만약 이벤트를 전달하는 과정에서 Consumer가 고장나는 상태가 발생한다면?
- 일이 모두 중단되고 손실이 발생하는 것이 아닌, 고장난 Consumer가 다시 수행 가능 할 때까지 주문 생성이 이벤트 큐에서 계속 대기하고 있을 것
Event sourcing
- 이벤트를 통한 상태 전달이 가능 → event log를 통해서 이벤트 상태를 확인하는 것이 가능함
- Complete Rebuild
- Temporal Query
- Event Replay ( 스냅샷 )
- 전체 흐름
- 이벤트 로그 : Day1. 상품이 추가됨 (10개)
- 이벤트 로그 : Day2. 상품구매 발생 (1개)
- 이벤트 로그 : Day3. 상품구매 발생 (1개)
- 현재 상품 갯수 8개 저장 ⇒ 이벤트 로그를 통해서 8개임을 알 수 있음 (complete rebuild)
- Day 정보를 통해서 시간 정보를 확인 가능 (temporary query)
- 스냅샷 등 이벤트 로그를 통해서 이벤트를 다시 재생하는 것이 가능
- 장점
- 언제, 무슨 일이 발생하였는지 파악이 가능
- reader, writer 가 많을 때 상태 파악에 유리
- 이벤트 로그는 immutable (각각에 따라 알아서 프로세싱)
- eventual consistency → 이벤트 로그를 통해서 비동기적으로 처리 및 확인 가능
CQRS(Command - Query Responsibility Segregation)
- CRUD(Create, Read, Update, Delete)에서 CUD(Command)와 R(Query)를 분리하는 것
- 명령 조회 책임 분리
- 왜 사용하는 가?
- 데이터베이스로부터 데이터를 읽어오고 처리하게 되면 이미 그 사이에 데이터가 변경되었을 가능성이 높음
- CQRS는 이러한 CUD와 Read사이의 delay가 존재함을 인정하는 것
- + 도메인 또는 비지니스 규칙이 간단하고 간단한 CRUD 스타일의 사용자 인터페이스 및 데이터 액세스 작업으로 충분한 경우는 권장되지 않음
- 장점
- 각각에 더 최적화된 데이터 베이스 구성을 통해 성능 향상
- Read에 의해 데이터가 변경되는 것을 방지
- 과도하게 복잡한 모델을 덜 복잡하게 만듦 → 시스템 복잡도 감소
- ex) Read의 경우 aggregation(집계함수) 등의 부가적인 attribute가 엔티티에 필요
- 구현 방식
- Event sourcing
- Eventual Consistency
- Domain Driven Design
참고한 블로그
- CQRS 패턴 → https://bluayer.com/37
'DESIGN PATTERN & ARCHITECTURE' 카테고리의 다른 글
도메인 주도 개발 시작하기 CH.8 ~ CH.9 (1) 2024.07.03 도메인 주도 개발 시작하기 CH.6 ~ CH.7 (0) 2024.06.26 도메인 주도 개발 시작하기 CH.4 ~ CH.5 (0) 2024.06.19 도메인 주도 개발 시작하기 CH.1 ~ CH.3 (0) 2024.06.10 도메인 주도 설계 핵심 (0) 2024.03.31