이벤트 기반 아키텍처 (EDA, Event Driven Architecture)

The world is Asynchronous - AWS re:Invent 2022

애플리케이션이 클라우드 네이티브거나 대규모 분산 환경에서 돌아가면서 메세징을 사용하지 않는다면 버그일 가능성이 높다. - Tim Bray

실제 세계는 async하게 돌아가고 있고, 이렇게 모델링을 하면 더욱 느슨한 결합을 유지할 수 있다.
마이크로 서비스에서 더 느슨한 결합을 갖기 위해 진화된 architecture.

특징

EDA는 시스템이 이벤트를 생산/소비 하는 방식으로 서로 통신한다.
소비된 이벤트는 바로 사라지지 않고 같은 메세지를 필요로하는 다른 컨슈머도 가져갈 수 있다.

MSA에서 EDA로 나가는 이유는 더 느슨한 결합을 위해서이다.
MSA에 event를 도입하면 마이크로 서비스간에 coupling을 없앨 수 있기 때문에 신규 서비스의 확장에 열려있는 구조이다.

  1. sender와 receiver를 추상화
  2. 응답성 향상 및 종속성 감소
  3. 서비스를 사용할 수 있을 때까지 메세지를 버퍼링

Monolithic vs MSA vs EDA

특징 Monolithic MSA EDA
서비스 구조 단일 서비스 독립적인 서비스 독립적인 서비스
통신 방식 프로세스 내 동기/비동기 프로세스 간 동기/비동기 프로세스 간 비동기 이벤트
코드베이스 단일 코드베이스 서비스별 독립 코드베이스 서비스별 독립 코드베이스
데이터베이스 단일 데이터베이스 서비스별 독립 데이터베이스 서비스별 독립 데이터베이스
배포 및 확장성 전체 서비스 배포/확장 서비스별 배포/확장 서비스별 배포/확장
운영 복잡성 낮음 높음 높음
기능 추가 및 수정 복잡성 높음 낮음 낮음
의존성 강하게 결합된 의존성 느슨하게 결합된 의존성 더 느슨하게 결합된 의존성
장애 영향도 특정 컴포넌트 실패 시 전체 애플리케이션 중단 가능 컴포넌트 분리로 장애 격리 느슨한 결합으로 더 나은 장애 격리
기술 스택 단일 기술 스택 다양한 기술 스택 다양한 기술 스택

synchronous MSA의 문제와 EDA의 해결책

synchoronous 마이크로 서비스의 문제는 asynchoronous EDA의 장점이기도 하다.

결합도

자신이 할 일을 다른 서비스에 의존한다.
의존관계가 꼬리에 꼬리를 물면 나중에 어느 서비스가 어떤 로직을 담당하는지 파악하기가 어렵다.
synchoronous MSA는 implementation coupling은 없지만 temporal coupling을 가지고 있는 구조이다.

EDA는 event를 통해 temporal coupling까지 끊어낸다.
sender는 event를 발행하고 client에 바로 응답을 줄 수 있으므로 client 응답이 빨라지고 사용자 경험을 좋게 만들 수 있다.

부하와 의존성 확장

한 서비스의 확장 가능 여부를 확인할 때 해당 서비스가 의존하는 다른 서비스들이 확장 가능한지 확인해야 한다.
부하가 늘거나 병목이 생기는 경우 장애가 되며 이를 서비스 운영중에 고려해야 한다.

EDA의 경우 늘어난 호출이 sender나 receiver에게 병목 등의 이슈로 장애가 되지 않는다.
receiver가 consumption 비율을 조절할 수 있다.

장애의 전파와 장애 처리

synchronous의 경우 장애가 전파된다.
전파되는 장애가 문제가 생기기도 하고 이를 위해 circuit breaker 같은 패턴을 사용할수도 있다.
더 중요한 문제는 실패로 인한 정합성을 위해 실패시 어떻게 처리할지를 정의해야하는데 서비스가 많을수록 복잡하다.

EDA의 경우 장애가 전파되지 않는다.
장애로 인한 복구도 해당 event 단위로 복구할 수 있다.

분산 모놀리스

서비스가 분산 모놀리스처럼 동작하도록 조합돼서 서비스간 호출이 얽히고 설킨다.
느슨한 결합을 위한 마이크로 서비스이지만 synchronous 이기 때문에 결합이 유지되며 어떤 경우엔 더 복잡하다.

EDA의 경우 별개의 event이기 때문에 호출이 명확하다.
그치만 디버깅을 위해서라면 조금 더 헷갈릴 수 있다.

EDA에서 고려해야할 점

synchronous MSA의 장점이기도 하다.

  • 직접 요청 & 응답이 필요한 유즈케이스에선 적절하지 않음
  • 네트워크 지연시간
  • 보다 더 어려운 구조
  • 여러 서비스에 걸친 추적이 용이
  • 디버깅과 가시성이 더 좋음

reference