이벤트 기반 아키텍처: 이벤트, 명령, 전달 보장 구분하기
작성: Ai Flowi · 게시일
이벤트 기반 아키텍처는 생산자가 발생한 사실을 이벤트로 발행하고 소비자가 그 사실에 반응하는 설계입니다. 생산자와 소비자는 이벤트 전달 메커니즘을 사이에 두고 독립적으로 동작할 수 있습니다. 이 설계에는 식별, 순서, 실패에 관한 명시적인 규칙이 필요합니다. 알림을 보내는 것만으로 신뢰할 수 있는 처리가 보장되지는 않습니다.
이벤트는 “이 일이 발생했습니다”라는 의미입니다. 명령은 “이 일을 해 주세요”라는 의미이며, 요청은 특정 서비스의 직접적인 응답을 기대할 수 있습니다. 이 의미를 구분하면 소비자가 관찰한 사실을 보고하는지, 아니면 어떤 행동을 허용할지 판단하는지 설명하기 쉽습니다.
이벤트 기반 아키텍처의 구성 요소는 무엇인가요?
생산자는 변경을 관찰하거나 완료하고 이벤트를 생성합니다. 전달 메커니즘은 해당 이벤트에 관심이 있는 소비자에게 이벤트를 전달합니다. 각 소비자는 자체 처리 규칙을 적용하고 결과를 기록합니다. 브로커가 전달 메커니즘의 일부일 수는 있지만, 브로커가 이벤트의 정의인 것은 아니며 이 예시에서도 브로커를 전제하지 않습니다.
생산자: 문서 승인 완료
↓
이벤트 봉투 + 승인된 문서 참조
↓
전달 경계
├─ 소비자 A: 운영 현황 갱신
└─ 소비자 B: 후속 조치 의도 기록승인이 이루어진 후에만 “문서 승인 완료”처럼 사실을 나타내는 이름을 사용합니다. “문서를 승인하세요”는 거부될 수 있는 명령입니다. 명령을 완료된 이벤트로 발행하면 소비자가 실제로 이루어지지 않은 승인을 근거로 동작할 수 있습니다. 생산자는 이벤트가 무엇을 입증하는지도 정확히 밝혀야 합니다. 저장된 승인, 요청된 승인, 전송된 승인 확인증은 서로 다른 관찰 결과입니다.
직접 작성한 이벤트 봉투 예시: 화면이 좁으면 표 영역에 초점을 맞추고 좌우로 스크롤하세요.
| 필드 | 의미 | 지켜야 할 경계 |
|---|---|---|
| event_id | 이 발생 건의 고정 식별자입니다. 예를 들어 synthetic-approval-A가 있습니다. | 새로운 승인이 아니라 같은 이벤트를 다시 전달할 때 재사용합니다. |
| occurred_at | 생산자가 승인 사실을 기록한 시각입니다. | 원본 시계의 맥락을 유지합니다. 도착 시각과 다를 수 있습니다. |
| received_at | 이 소비자가 이번 전달을 수신한 시각입니다. | 나중에 전달되면 수신 시각은 달라지지만 같은 발생 건입니다. |
| event_type | 이 가상의 규약에서는 document.approved입니다. | 실행되지 않은 지시가 아니라 사실을 나타냅니다. |
| schema_version | 봉투와 페이로드 의미의 버전입니다. | 소비자가 해석할 수 없는 버전은 거부하거나 검토합니다. |
| payload | 문서 식별자, 승인된 개정본, 승인 참조입니다. | 허용된 데이터와 반응에 필요한 근거만 포함합니다. |
전달 보장은 업무 결과에 대한 보장보다 범위가 좁습니다
최대 한 번 전달은 중복 전달을 피하는 대신 유실을 허용합니다. 최소 한 번 전달은 명시된 조건에서 최종 도착을 추구하면서 중복 전달을 허용합니다. 어느 표현도 그 자체로 소비자가 업무상 쓰기를 정확히 한 번 수행한다는 증거는 아닙니다. 전달 보장이 어느 경계를 가리키는지, 수신 확인이 유실되면 어떻게 되는지 확인합니다.
순서에도 범위가 필요합니다. 한 문서의 이벤트에는 순서가 있으면서 관련 없는 문서는 독립적으로 진행할 수 있습니다. 전체 수신 순서가 업무 변경의 발생 순서를 입증하지는 않습니다. 정확히 한 번 동작한다고 주장하는 시스템에는 정확한 범위와 실패 모델이 필요합니다. 근거 없이 이 표현을 모든 외부 부수 효과에 확대 적용해서는 안 됩니다.
중복 전달과 쓰기 후 실패 살펴보기
소비자 A는 synthetic-approval-A를 수신하고 승인된 개정본을 대상에 쓴 다음, 전달 수신을 확인하기 전에 실패합니다. 생산자나 전달 메커니즘은 쓰기가 완료되었는지 알 수 없으므로 같은 이벤트가 다시 도착합니다. 소비자가 조건 없이 추가하면 승인은 한 번뿐인데 두 번째 레코드가 생성됩니다.
멱등적인 반응은 같은 이벤트를 다시 처리해도 의도한 효과를 냅니다. 이를 위해서는 재시도 횟수만이 아니라 업무상 식별자와 갱신 규칙이 필요합니다. 소비자는 대상에 미친 효과와 함께 이벤트 식별자를 보관하거나, 검증된 규약이 효과의 반복을 막는 대상 작업을 사용할 수 있습니다. 별도로 “이미 본 이벤트”를 조회한 뒤 쓰는 방식은 복사본 두 개가 동시에 도착하면 여전히 경쟁 상태가 발생할 수 있습니다.
이벤트 식별자와 전달 시도 식별자를 구분합니다. 재시도마다 새로운 event_id를 부여하면 중복 감지가 무력화됩니다. 반대로 실제로 새로운 승인에 예전 식별자를 재사용하면 필요한 처리가 억제될 수 있습니다. 생산자가 이 구분을 책임집니다. 소비자는 같은 이벤트 식별자에 상충하는 페이로드가 있으면 무해한 반복으로 조용히 처리하지 말고 문제를 표시해야 합니다.
두 소비자의 순서 보장 범위 비교하기
고객 생애주기 가이드에서 지연된 상태의 판단을 구체적으로 다룹니다. 여기서는 어떤 수신 순서가 생산자가 선언한 순서 보장 범위를 충족하는지 살펴봅니다.
생산자 P가 문서 A에 대해 A1, A2 순서로 이벤트를 내보내고, 관련 없는 문서 B에 대해 B1을 내보낸다고 가정합니다. 이 가상의 규약은 문서 간 순서를 보장하지 않고 각 문서 안에서만 순번을 부여합니다. 소비자 X는 A1, B1, A2 순서로 수신합니다. 소비자 Y는 B1, A2, A1 순서로 수신합니다. 두 소비자의 도착 이력은 다르지만, A의 문서별 순서를 위반하는 것은 Y의 수신 순서뿐입니다.
| 소비자의 관찰 | 규약과 비교 | 허용되는 판단 |
|---|---|---|
| X: A1, B1, A2 | A1이 A2보다 먼저입니다. B는 A의 범위 밖에 있습니다. | 각 문서의 순서를 독립적으로 처리합니다. |
| Y: B1, A2, A1 | A2가 필수 선행 이벤트 A1보다 먼저 도착합니다. | A2의 의존적인 반응은 보류합니다. B1은 진행할 수 있습니다. |
| Y: 나중에 A1 수신 | 누락되었던 선행 이벤트가 이제 있습니다. | 소비자의 처리 규칙에 따라 A1을 평가한 뒤 보류한 A2를 평가합니다. |
| A2가 생산자를 Q로 표시함 | P의 순번으로 Q의 순서를 입증할 수 없습니다. | 순번을 합치기 전에 생산자 간 규약을 요청합니다. |
이 보류 정책은 직접 작성한 소비자 요구 사항이며, 플랫폼 기능이라는 주장이 아닙니다. 선행 이벤트를 수신했다고 이미 성공적으로 처리한 것은 아닙니다. A1의 반응이 실패하면, 그 반응에 의존하는 규칙 아래에서 A2는 계속 차단됩니다. 독립적인 감사 사실만 기록하는 소비자는 의존 관계가 다를 수 있으므로 전달 순서와 처리 순서를 따로 정의해야 합니다.
순번 규약이 중간의 모든 번호가 이 소비자의 스트림에 속한다고 명시하지 않는 한, 숫자가 건너뛰었다는 이유만으로 이벤트 누락을 추정하지 않습니다. 필터링으로 특정 이벤트 유형이 의도적으로 제거될 수도 있습니다. 순번이 한 문서, 한 생산자, 전체 피드 중 무엇을 포괄하는지, 소비자가 누락 레코드를 확보할 수 있는지 문서화합니다. 그렇지 않으면 보류를 해제할 근거가 무엇인지도 모른 채 영구적으로 보류될 수 있습니다.
AI Flowi Workflow의 구체적인 신뢰성 경계
상태: 테스트됨. 연결된 웹훅 신뢰성 레시피에 기록된 범위에 해당합니다. 웹훅 오류 처리 페이지는 다음 결과를 보고합니다. 같은 event_id를 사용한 동시 전달 5건이 모두 200을 반환했고 시트에 추가로 3개 행을 썼습니다
. HTTP 상태 확인에서는 5건 중 5건의 응답이 성공했지만, 하나의 이벤트가 세 행으로 기록되어 고유성 요구 사항을 충족하지 못했습니다. 이는 측정된 동시성 한계이며, 정확히 한 번 처리했다는 증거가 아닙니다.
리드 수집 레시피에는 순차적인 반복 전달이 두 번째 행을 추가하지 않고 같은 행을 갱신한 것으로 문서화되어 있습니다. 이 구성 요소 순서는 해당 레시피의 근거이지 브로커나 스트리밍 플랫폼의 근거는 아닙니다. 신뢰성 예시는 순차적인 중복 확인을 동시 전달 보장으로 확대해서는 안 되는 이유를 보여 줍니다.
이벤트 봉투의 표현 인터페이스는 JSON Object Builder 및 JSON Operations를 참고합니다. 제안된 이 용도는 카탈로그에 문서화되어 있으나 Ai Flowi의 프로덕션 테스트를 거치지 않았습니다.
다음은 설정 예시이며 기록된 테스트가 아닙니다. JSON Object Builder의 field_names에는 표의 봉투 필드 여섯 개를 넣습니다. 순서 규약에 필요하다면 직접 작성한 payload 안에 producer_id, document_id, document_sequence를 넣습니다. 생성된 레코드가 순서에 관한 근거를 담을 수는 있지만, 이를 해석하려면 소비자 정책이 필요합니다. JSON을 생성한다고 순서가 보장되는 큐나 원자적인 소비자 체크포인트가 구현되지는 않습니다.
흔한 실수와 관련 용어
지시를 사실로 부르거나, 알 수 없는 결과를 버리거나, 도착 순서를 업무 순서로 간주하거나, 하나가 응답했다는 이유로 모든 소비자가 성공했다고 가정하지 않습니다. 식별자 반복, 상충하는 페이로드, 늦은 개정본, 대상에 쓴 후의 실패를 별도 시나리오로 테스트합니다. 각 관찰이 어느 경계를 포괄하는지 기록합니다.
워크플로 오케스트레이션은 조정된 작업 안에서 의존 관계와 복구 상태를 다룹니다. API 게이트웨이는 진입 경로 라우팅과 정책을 다룹니다. Universal Webhook 참조 문서는 아키텍처의 전달 규약을 대체하지 않으면서 특정 HTTP 진입 메커니즘을 설명합니다.