이벤트 기반 아키텍처(EDA)란?

업데이트: 2026년 11월

이벤트 기반 아키텍처는 서비스가 불변의 사실을 이벤트로 알리고 소비자가 각자 독립적으로 반응하는 설계 방식입니다. 벤더 페이지들이 건너뛰는 정확성은 두 단어에 있습니다. 이벤트는 불변의 과거형 사실이고(PlaceOrder가 아니라 OrderPlaced), 생산자는 누가 반응하는지 알지도 못하고 신경 쓰지도 않습니다. 그 무관심이 곧 아키텍처입니다. 소비자는 생산자가 코드 한 줄 바꾸지 않아도 추가되고, 제거되고, 고장 날 수 있습니다. 가장 문자 그대로의 디커플링입니다. 그리고 EDA는 신앙이 아니라 스펙트럼입니다. 웹훅 하나도 이벤트 기반이고, 거대한 스트리밍 인프라도 마찬가지이며, 건강한 시스템 대부분은 그 둘의 하이브리드입니다.

핵심 요약

질문답변
이벤트란불변의 과거형 사실, 소비자는 반응할 수는 있어도 거부할 수는 없음
이벤트 ≠ 명령관심 있는 누구에게나 방송되는 사실 vs. 하나의 핸들러를 향한 명령
결정 규칙반응 전에 생산자의 일이 끝남 → 이벤트, 호출자가 답을 필요로 함 → 요청-응답
세 가지 유형알림 · 이벤트 전달 상태 · 이벤트 소싱(스토리지 선택)
늘 치러야 할 비용멱등한 소비자, 상관관계 ID, 최종 일관성을 고려한 UX

하나의 사실, 여러 반응

// JavaScript — Cloud Code (cloud/main.js)
// Everyday EDA: the write IS the event; consumers react independently
Parse.Cloud.afterSave('Order', async (req) => {
  const order = req.object;
  const becamePlaced = order.get('status') === 'placed' &&
    req.original?.get('status') !== 'placed';
  if (!becamePlaced) return;

  // Consumers of one fact — none knows about the others:
  await Parse.Cloud.httpRequest({          // fulfillment system (webhook)
    method: 'POST', url: process.env.FULFILL_WEBHOOK,
    body: { event: 'order.placed', id: order.id },
  });
  await enqueueConfirmationEmail(order);   // async job queue
  // Live Query pushes the change to every open dashboard automatically
});

하나의 사실(주문 접수)과 서로의 존재를 모르는 네 개의 소비자가 있습니다. 웹훅으로 통보받는 주문 처리 시스템, 큐에 들어가는 이메일 작업, 수치를 집계하는 분석, 라이브 구독으로 갱신되는 대시보드입니다. 다섯 번째 소비자를 추가해도 상류(upstream)에서는 아무것도 바뀌지 않습니다. 저장 한 번에 이 아키텍처의 핵심 주장이 모두 담겨 있습니다.

이벤트 기반 아키텍처의 생산자, 브로커, 독립적인 소비자생산자가 불변의 과거형 이벤트를 브로커로 보냅니다. 브로커는 주문 처리 서비스, 이메일 작업, 분석, 클라이언트 대시보드 등 독립적인 소비자에게 사본을 전달합니다. 소비자는 생산자를 바꾸지 않고도 독립적으로 추가되거나 실패할 수 있으며, 각 소비자는 중복을 멱등하게 처리해야 합니다.

OrderPlaced
(불변의 사실)

구독 – 생산자는
전혀 모름

생산자
주문 서비스

브로커 / 채널
토픽, 스트림 또는 트리거

주문 처리
(웹훅)

이메일 작업
(큐)

분석

대시보드
(라이브 쿼리)

새 소비자,
화요일에 추가

생산자가 불변의 과거형 이벤트를 브로커로 보냅니다. 브로커는 주문 처리 서비스, 이메일 작업, 분석, 클라이언트 대시보드 등 독립적인 소비자에게 사본을 전달합니다. 소비자는 생산자를 바꾸지 않고도 독립적으로 추가되거나 실패할 수 있으며, 각 소비자는 중복을 멱등하게 처리해야 합니다.

용어 정리

검색 결과 상위 페이지들의 용어 혼란을 표 하나로 정리합니다. 세 가지 메시지 유형을 전송 방식이 아니라 의도로 구분합니다.

Criterion명령 (Command)이벤트 (Event)쿼리 (Query)
문법명령형: ShipOrder과거형: OrderShipped의문형
대상하나의 핸들러구독한 누구나하나의 응답자
거부 가능 여부예아니요, 이미 일어난 일입니다해당 없음
결합도송신자가 핸들러를 앎생산자는 아무도 모름호출자가 대기

Fowler의 경고는 그대로 옮길 가치가 있습니다. 수동 공격적 명령(passive-aggressive command)을 경계해야 합니다. 생산자가 이벤트라고 내보내면서 실은 특정 소비자 하나가 행동하기를 요구하는 “이벤트”를 말합니다. 그 소비자가 응답하지 않을 때 흐름이 깨진다면 그것은 처음부터 명령이었고, 이벤트라는 이름은 결합을 숨겼을 뿐입니다. (인프라 용어인 브로커, 라우터, 버스, 채널, 토픽은 가운데 상자를 가리키는 거의 같은 말입니다. 그 장치는 pub/sub 항목에서 다루며, EDA는 그것을 일반화한 아키텍처입니다.)

이벤트 기반 vs. 요청-응답

Criterion요청-응답이벤트 기반
시간적 결합호출자가 대기, 피호출자가 살아 있어야 함발행 후 망각(fire-and-forget), 소비자가 나중에 따라잡음
답호출자에게 반환답은 없고 반응만 있음
장애 양상즉각적이고 눈에 보이는 오류복원력이 있지만 최종적으로 일관됨
디버깅하나의 콜 스택여러 홉에 걸친 상관관계 ID
적합한 곳읽기, 로그인, 결제 등 호출자가 필요로 하는 모든 것독립적인 소비자가 있는 사실

한 문장 규칙은 이렇습니다. 호출자가 계속 진행하는 데 결과가 필요하다면 요청-응답, 어떤 반응이 시작되기 전에 생산자의 일이 끝난다면 이벤트입니다. 주문 접수에는 동기적인 답(“성공했습니까?”)이 필요합니다. 그 이후의 모든 것, 즉 이메일, 주문 처리, 분석은 하나의 사실에 대한 반응입니다. 실제 시스템이 타협의 결과가 아니라 설계에 의해 하이브리드가 되는 이유입니다.

Fowler의 세 가지 유형과 이벤트 소싱의 실제 위치

패턴이벤트가 담는 것소비자트레이드오프
이벤트 알림 (event notification)ID와 최소한의 정보세부 정보를 위해 다시 호출단순하지만 콜백 트래픽이 다시 결합을 만듦
이벤트 전달 상태 전송 (event-carried state transfer)관련 상태 전체로컬 사본 유지콜백은 없지만 데이터 중복과 낡은 사본
이벤트 소싱 (event sourcing)그 자체가 기록 시스템(system of record)재생으로 상태 재구성완벽한 감사 추적, 되돌리기 어려운 스토리지 설계 결정

회의 시간을 아껴 주는 구분이 있습니다. 이벤트 소싱은 한 시스템이 데이터를 저장하는 방식이고, EDA는 시스템들이 대화하는 방식입니다. 둘은 함께 쓸 수 있지만 어느 쪽도 다른 쪽을 요구하지 않습니다. 벤더들이 흐리는 선이 하나 더 있습니다. pub/sub 전달은 잊어버립니다. 늦게 들어온 구독자는 자신이 도착하기 전에 발생한 이벤트를 놓칩니다. 반면 스트리밍(Kafka 방식의 순서 있는 로그)은 기억하므로 소비자가 어느 지점에서든 재생할 수 있습니다. 이력이 제품의 일부인지에 따라 선택하는 것이 좋습니다.

코레오그래피 vs. 오케스트레이션

Criterion코레오그래피 (EDA 고유)오케스트레이션
조정 방식서비스가 서로의 이벤트에 반응코디네이터가 각 단계를 지시
워크플로가 있는 곳명시적으로는 어디에도 없음, 창발적눈에 보이고 디버깅 가능한 한 곳
결합도최소오케스트레이터가 모두를 앎
장애 처리보상 이벤트, 분산형중앙 집중식 재시도와 오류 로직

오케스트레이션 항목과 공유하는 거울상 규칙입니다. 누군가 워크플로의 결과를 책임져야 한다면 오케스트레이션을, 생산자가 다음에 일어날 일에 정말로 관심이 없다면 코레오그래피를 선택합니다. 여러 서비스에 걸친 긴 비즈니스 트랜잭션은 어느 쪽이든 사가 형태를 띱니다. 이벤트나 오케스트레이터로 연결된 로컬 트랜잭션이며, 롤백이 아니라 보상 트랜잭션으로 되돌립니다.

일상 속의 EDA: 브로커 없이

아키텍처 중심의 글들이 결코 쓰지 않는 부분입니다. 대부분의 앱 개발자는 메시지 브로커 하나 없이 이미 이벤트 기반 패턴을 운영하고 있습니다. beforeSave/afterSave 트리거는 데이터 변경 이벤트의 소비자입니다. 웹훅은 평범한 HTTP로 회사의 경계를 넘는 이벤트입니다. 라이브 쿼리는 클라이언트를 구독자로 둔 pub/sub입니다. 트리거가 큐에 넣는 백그라운드 작업은 비동기 작업을 낳는 이벤트입니다. 위의 코드 탭이 정확히 이 스택입니다. 쓰기가 이벤트이고, 트리거가 라우터이며, 소비자는 웹훅, 큐, 구독입니다. 전용 브로커(Kafka, RabbitMQ, NATS, 그리고 표준 봉투 형식인 CloudEvents)는 이벤트 양, 재생, 팀 간 계약이 요구할 때 비로소 운영 부담만큼의 값을 합니다. 아키텍처는 그보다 훨씬 일찍 시작되며, “브로커가 필요합니까?”라는 질문은 대개 스스로 답을 냅니다. 아직은 아닙니다.

일반적인 사용 사례

  • 주문과 결제 흐름: 하나의 사실, 여러 부서. 전형적인 전자상거래 파이프라인입니다.
  • 시스템 간 통합: 서로 다른 팀이 소유한 서비스가 직접 호출이나 공유 배포 없이 반응합니다.
  • 실시간 기능: 대시보드, 피드, 프레즌스를 클라이언트 측의 이벤트 소비로 구현합니다.
  • 급증하는 워크로드: 큐가 버스트를 완충해 소비자가 자기 속도로 처리합니다.
  • 감사와 재생: “무슨 일이 어떤 순서로 일어났는가” 자체가 제품인 스트리밍 로그입니다.

이벤트 기반으로 가야 할까? 결정 매트릭스

상황권장 방향
하나의 사실, 여러 독립 소비자이벤트: 가장 잘 맞는 영역
호출자가 진행하려면 답이 필요함요청-응답, 망설일 이유 없음
책임자와 SLA가 있는 워크플로오케스트레이션: 단계를 지시
한 앱 안의 반응(가입 시 이메일)트리거 + 작업: 일상 속의 EDA
회사 간 알림웹훅
대용량, 재생 가능, 여러 팀이 쓰는 스트림진짜 브로커: 이제 값을 함

한계와 트레이드오프

  • 디버깅에서 콜 스택이 사라집니다. 다섯 번의 비동기 홉으로 퍼지는 요청은 첫 이벤트부터 전달된 상관관계 ID로만 추적할 수 있습니다. 나중에 덧붙이기는 고통스러우므로 첫날부터 연결해 두는 것이 좋습니다.
  • 최종 일관성이 UI까지 닿습니다. 사용자가 프로필을 수정했는데 다음 화면에 예전 이름이 보입니다. UX를 그에 맞게 설계하거나 그 경로를 동기식으로 유지해야 합니다.
  • 중복은 계약 사항입니다. 최소 한 번(at-least-once) 전달은 멱등한 소비자를 필수로 만듭니다. 큐가 부과하는 것과 같은 계약입니다. 같은 장치이기 때문입니다.
  • 스키마가 소비자의 발밑에서 진화합니다. 이벤트는 알 수 없는 구독자와 맺는 계약입니다. 변경은 추가 방식으로만 하고, 호환성을 깨는 변경에는 버전이 붙은 토픽을 쓰며, 모든 곳에 관대한 리더(tolerant reader)를 두어야 합니다.
  • 창발적 워크플로는 숨어 버립니다. 순수한 코레오그래피에서는 아무도 비즈니스 프로세스를 가리킬 수 없습니다. 감사자나 온콜 엔지니어가 그래야 할 때는 오케스트레이터를 추가해야 합니다.

Back4app에서의 이벤트 기반 패턴

Back4app은 관리형 데이터베이스, 자동 생성되는 REST 및 GraphQL API, 인증, 파일 스토리지, Cloud Code 서버리스 함수를 결합한 오픈소스 Backend as a Service(BaaS) 플랫폼입니다. 앞의 일상 속의 EDA 절은 이 플랫폼의 기능 목록을 아키텍처로 읽은 것입니다. 모든 저장은 이벤트이고, afterSave 트리거는 JavaScript 생태계 전체를 쓸 수 있는 서버 측 소비자이며, Live Query는 관리형 웹소켓을 통해 사실을 클라이언트로 팬아웃하고, 웹훅은 이를 외부 시스템으로 전달하며, 백그라운드 작업은 느린 반응을 흡수합니다. 코드 탭은 주문 저장 한 번에서 시작되는 전체 루프를 보여 줍니다. 이 글이 강조하는 규율(멱등한 after 훅, 과거형으로 생각하기, 호출자가 답을 필요로 하는 곳의 동기 처리)은 여전히 사용자의 몫입니다. 반면 브로커 형태의 인프라(팬아웃, 전달, 연결 관리)는 플랫폼 동작으로 제공되며, 나중에 전용 스트리밍 브로커로 옮겨 가는 것은 이 아키텍처에 무언가를 더하는 일이지 다시 쓰는 일이 아닙니다.

자주 묻는 질문

이벤트 기반 아키텍처를 쉽게 설명하면 무엇입니까?

구성 요소들이 서로를 호출하는 대신 무언가 일어났다는 사실, 즉 이벤트를 알리고, 관심 있는 구성 요소가 각자의 일정에 따라 반응하는 방식입니다. 전화 통화가 아니라 방송입니다. 알리는 쪽의 일은 알림으로 끝나고, 듣는 쪽은 알리는 쪽이 바뀌지 않아도 생겨나고 사라집니다.

이벤트와 명령의 차이는 무엇입니까?

의도입니다. 명령은 한 수신자를 향한 명령형 메시지이며 수신자는 이를 거부할 수 있습니다(ShipOrder). 이벤트는 관심 있는 누구에게나 방송되는 과거형 사실입니다(OrderShipped). 함정은 "수동 공격적 명령"입니다. 특정 소비자 하나가 행동하기를 몰래 기대하는 이벤트로, 이벤트로 변장한 명령입니다.

이벤트 기반과 요청-응답의 차이는 무엇입니까?

시간적 결합입니다. 요청-응답은 동기식입니다. 호출자는 기다리고, 답이 필요하며, 피호출자가 다운되면 실패합니다. 이벤트는 발행 후 망각(fire-and-forget) 방식이라 복원력이 있고 결합이 느슨하지만 최종적으로 일관됩니다. 규칙은 이렇습니다. 호출자가 계속 진행하는 데 결과가 필요하면 요청-응답, 반응이 시작되기 전에 생산자의 일이 끝나면 이벤트입니다.

EDA와 pub/sub의 차이는 무엇입니까?

층위입니다. pub/sub은 메시징 패턴, 즉 발행자에서 토픽을 거쳐 구독자로 이어지는 하나의 전달 메커니즘입니다. EDA는 보통 큐, 스트림과 함께 그 위에서 동작하는 아키텍처 스타일입니다. pub/sub이 배관이라면 이벤트 기반은 그 배관이 뒷받침하는 설계 철학입니다.

이벤트 알림, 이벤트 전달 상태 전송, 이벤트 소싱이란 무엇입니까?

Fowler가 정리한, 하나의 이름 아래 숨은 서로 다른 세 가지 패턴입니다. 알림(notification)은 얇은 이벤트를 보내고 소비자가 세부 정보를 다시 요청합니다. 상태 전송(state transfer)은 이벤트가 전체 데이터를 담으므로 소비자가 로컬 사본을 유지합니다. 소싱(sourcing)은 영속성에 관한 선택으로, 모든 변경을 이벤트로 저장하고 재생으로 상태를 재구성합니다. 세 번째는 시스템들이 대화하는 방식이 아니라 한 시스템이 데이터를 저장하는 방식입니다.

코레오그래피와 오케스트레이션의 차이는 무엇입니까?

코레오그래피에서는 서비스들이 서로의 이벤트에 반응하며 중앙의 두뇌가 없습니다. 결합은 최소화되지만 워크플로는 어디에도 명시적으로 존재하지 않습니다. 오케스트레이션에서는 코디네이터가 각 단계를 지시합니다. 눈에 보이고 디버깅할 수 있지만 중앙 결합 지점이라는 대가를 치릅니다. 규칙은 누군가 결과를 책임져야 하면 오케스트레이션, 생산자가 다음에 일어날 일에 정말로 관심이 없으면 코레오그래피입니다.

중복되거나 순서가 뒤바뀐 이벤트는 어떻게 처리합니까?

희망이 아니라 설계로 처리합니다. 브로커는 최소 한 번(at-least-once) 전달하므로 소비자는 멱등해야 합니다. 이벤트 ID로 중복을 제거하거나, 반복되어도 해가 없는 핸들러를 작성합니다("상태를 shipped로 설정"이지, 절대 "토글"이 아닙니다). 순서는 파티션이나 키 단위로만 보장되며, 전역 순서를 요구하는 아키텍처는 자신의 전송 계층과 싸우는 셈입니다.

이벤트 기반 아키텍처는 언제 사용해야 합니까?

하나의 사실에 독립적인 소비자가 여럿일 때, 부하가 급증해 버퍼링이 도움이 될 때, 시스템들이 서로를 모른 채 통합되어야 할 때, 변경의 감사 추적에 가치가 있을 때입니다. 맞지 않는 경우는 단순한 CRUD, 읽기, 즉각적인 강한 일관성이 필요한 작업, 그리고 분산 시스템을 감당할 의지가 없는 팀입니다.

관련 용어

비교 대상

참고 자료

백엔드를 구축할 준비가 되셨나요?

몇 분 안에 Back4app에서 프로젝트를 시작하세요. 데이터베이스, 인증, API, Cloud Code가 포함되어 있으며 신용카드는 필요 없습니다.

작성 및 검수: Back4app Engineering, Back4app Engineering · 게시일 2026-11-02