이벤트 기반 아키텍처는 이벤트 스트림을 생성하는 이벤트 생산자, 이러한 이벤트를 수신 대기하는 이벤트 소비자 및 생산자에서 소비자로 이벤트를 전송하는 이벤트 채널로 구성됩니다.
이벤트는 거의 실시간으로 전달되므로 이벤트가 발생하는 즉시 소비자가 이벤트에 응답할 수 있습니다. 생산자와 소비자가 분리되므로 생산자는 수신 대기 중인 소비자를 알 수 없습니다. 소비자도 서로 분리되며 각 소비자에게 모든 이벤트가 표시됩니다. 이는 소비자가 큐에서 메시지를 끌어오고 오류가 없다고 가정할 경우 메시지가 한 번만 처리되는 경쟁 소비자 패턴과 다릅니다. IoT와 같은 일부 시스템에서는 매우 높은 볼륨으로 이벤트를 수집해야 합니다.
이벤트 기반 아키텍처는 게시/구독(pub/sub라고도 함) 모델 또는 이벤트 스트림 모델을 사용할 수 있습니다.
게시자/구독자: 메시징 인프라에서 구독을 추적합니다. 이벤트가 게시되면 각 구독자에게 이벤트를 보냅니다. 이벤트를 받은 뒤에는 재생이 불가능하고, 이벤트가 새 구독자에게 표시되지 않습니다.
이벤트 스트리밍: 이벤트가 로그에 기록됩니다. 이벤트가 파티션 내에 엄격하게 정렬되며 지속 가능합니다. 클라이언트는 스트림을 구독하지 않고, 대신 스트림의 일부에서 읽을 수 있습니다. 클라이언트가 스트림에서 해당 위치를 진행해야 합니다. 즉, 클라이언트가 언제든지 연결하고 이벤트를 재생할 수 있습니다.
소비자 측면에서 다음과 같은 몇 가지 일반적인 변형이 있습니다.
단순 이벤트 처리. 이벤트가 즉시 소비자에서 작업을 트리거합니다. 예를 들어 서비스 버스 토픽에 메시지를 게시할 때마다 함수가 실행되도록 서비스 버스 트리거와 함께 Azure Functions를 사용할 수 있습니다.
기본 이벤트 상관 관계. 일반적으로 소비자는 이후 이벤트를 처리할 때 사용할 이전 이벤트의 일부 정보를 유지하기 위해 일부 식별자와 상관 관계가 있는 소수의 개별 비즈니스 이벤트를 처리해야 합니다. NServiceBus 및 MassTransit 등의 라이브러리에서 이 패턴이 지원됩니다.
복합 이벤트 처리. 소비자는 이벤트 데이터에서 패턴을 찾는 동시에 일련의 이벤트를 처리하기 위해 Azure Stream Analytics 등의 기술을 사용합니다. 예를 들어 포함된 디바이스에서 일정 기간 동안 읽은 값을 집계하고 이동 평균이 특정 임계값을 초과하면 알림을 생성할 수 있습니다.
이벤트 스트림 처리. Azure IoT Hub 또는 Apache Kafka와 같은 데이터 스트리밍 플랫폼을 파이프라인으로 사용하여 이벤트를 수집하고 스트림 프로세서에 공급합니다. 스트림 프로세서는 스트림을 처리하거나 변환합니다. 애플리케이션의 각 하위 시스템에 사용되는 여러 스트림 프로세서가 있을 수 있습니다. 이 접근 방법은 IoT 워크로드에 적합합니다.
이벤트의 소스가 IoT 솔루션의 물리적 디바이스와 같이 시스템 외부에 있을 수도 있습니다. 이 경우 시스템이 데이터 원본에 필요한 볼륨 및 처리량으로 데이터를 수집할 수 있어야 합니다.
이벤트 페이로드를 구조화하는 두 가지 주요 방법이 있습니다. 이벤트 소비자를 제어할 수 있는 경우 소비자별로 이 페이로드 구조를 결정합니다. 단일 워크로드 내에서 필요에 따라 접근 방식을 혼합합니다.
페이로드에 필요한 모든 특성 포함: 이 방법은 소비자가 외부 데이터 원본을 쿼리할 필요 없이 사용 가능한 모든 정보를 포함하도록 할 때 사용됩니다. 그러나 특히 업데이트 후 여러 레코드 시스템으로 인해 데이터 일관성 문제가 발생할 수 있습니다. 계약 관리 및 버전 관리도 복잡해질 수 있습니다.
페이로드에 키만 포함: 이 방법에서 소비자는 기본 키와 같은 필요한 특성을 검색하여 데이터 원본에서 나머지 데이터를 독립적으로 가져옵니다. 이 메서드는 단일 레코드 시스템으로 인해 더 나은 데이터 일관성을 제공하지만 소비자가 데이터 원본을 자주 쿼리해야 하므로 첫 번째 방법보다 성능이 저하됩니다. 이벤트가 더 작고 계약이 더 간단하기 때문에 결합, 대역폭, 계약 관리 또는 버전 관리와 관련된 우려가 적습니다.
위의 논리 다이어그램에서 각 소비자 유형은 단일 상자로 표시됩니다. 실제로는 소비자가 시스템의 단일 실패 지점이 되지 않도록 한 소비자의 여러 인스턴스가 있는 것이 일반적입니다. 이벤트의 볼륨 및 빈도를 처리하기 위해 여러 인스턴스가 필요할 수도 있습니다. 또한 단일 소비자가 여러 스레드의 이벤트를 처리할 수 있습니다. 이벤트가 순서대로 처리되어야 하거나 정확히 한 번 처리되어야 하는 경우 이것이 문제가 될 수 있습니다. 조정 최소화를 참조하세요.
두 가지 기본 토폴로지가 여러 이벤트 기반 아키텍처 내에 존재합니다.
Broker 토폴로지. 구성 요소는 발생한 일을 이벤트로 전체 시스템에 브로드캐스트하고, 다른 구성 요소는 해당 이벤트에 대해 행동을 취하거나 무시합니다. 이벤트 처리 흐름이 비교적 간단한 경우 이 토폴로지가 유용합니다. 이 토폴로지는 매우 동적일 수 있으며, 이는 중앙 조정 또는 오케스트레이션이 없기 때문입니다. 이 토폴로지는 확장성, 응답성 및 구성 요소 내결함성을 제공하기 위해 고도로 분리됩니다. 다단계 비즈니스 트랜잭션의 상태를 소유 또는 인식하지 않는 구성 요소가 없으며, 작업은 비동기적으로 수행됩니다. 이후, 분산 트랜잭션은 위험하며, 이는 다시 시작하거나 재생할 기본 방법이 없기 때문입니다. 오류 처리 및 수동 개입 전략을 신중하게 고려해야 하며, 이는 이 토폴로지가 데이터 불일치의 원인일 수 있기 때문입니다.
중재자 토폴로지. 브로커 토폴로지의 몇 가지 단점을 이 토폴로지가 해결합니다. 이벤트 중재자는 이벤트 흐름을 관리하고 제어하기 위해 존재합니다. 이벤트 중재자는 상태를 유지하며 오류 처리 및 다시 시작 기능을 관리합니다. 구성 요소는 broker 토폴로지와 달리, 명령으로 발생 항목을 브로드캐스트하며, 일반적으로 메시지 큐에 해당하는 지정된 채널에만 브로드캐스트합니다. 이러한 명령은 소비자에 의해 무시될 것으로 예상되지 않습니다. 보다 많은 제어, 더욱 나은 분산 오류 처리 및 잠재적으로 더욱 나은 데이터 일관성을 이 토폴로지가 제공합니다. 이 토폴로지는 구성 요소 간의 결합을 증가시키며, 이벤트 중재자는 병목 상태 또는 안정성 문제가 될 수 있습니다.
이 아키텍처를 사용하는 경우
- 여러 하위 시스템이 동일한 이벤트를 처리해야 하는 경우.
- 최소 시간 지연의 실시간 처리.
- 패턴 일치 또는 일정 기간의 집계와 같은 복합 이벤트 처리.
- 높은 볼륨 및 높은 데이터 개발속도(예: IoT).
이점
- 생산자와 소비자가 분리됩니다.
- 지점 간 통합이 없습니다. 시스템에 새 소비자를 쉽게 추가할 수 있습니다.
- 이벤트가 도착하는 즉시 소비자가 이벤트에 응답할 수 있습니다.
- 확장성이 뛰어나고 탄력적이며 분산되어 있습니다.
- 하위 시스템에서 이벤트 스트림을 독립적으로 확인할 수 있습니다.
과제
배달 보장.
일부 시스템, 특히 IoT 시나리오에서는 이벤트가 배달되도록 보장하는 것이 중요합니다.
이벤트를 순서대로 또는 한 번만 처리.
복원 및 확장성을 위해 일반적으로 각 소비자 유형이 여러 인스턴스에서 실행됩니다. 이는 이벤트가 (소비자 유형 내에서) 순서대로 처리되어야 하거나, 멱등 메시지 처리 논리가 구현되지 않은 경우에 문제가 될 수 있습니다.
서비스 간에 메시지 조정하기
전체 워크로드에서 일관된 결과를 얻기 위해 메시지를 게시하고 구독하는 여러 서비스가 비즈니스 프로세스에 포함되는 경우가 많습니다. 다양한 서비스에서 메시지 흐름을 안정적으로 관리하기 위해 연출 패턴 및 Saga 오케스트레이션 등의 워크플로 패턴을 사용할 수 있습니다.
오류 처리.
이벤트 기반 아키텍처는 비동기 통신을 주로 사용합니다. 오류 처리는 비동기 통신의 과제입니다. 별도의 오류 처리기 프로세서 사용은 이 문제를 해결하는 한 가지 방법입니다. 그러므로 이벤트 소비자가 오류를 경험하는 경우, 잘못된 이벤트를 즉시 오류 처리기 프로세서에 비동기적으로 보낸 다음 계속 진행합니다. 오류 처리기 프로세서는 오류를 수정하고자 시도하며, 원래 수집 채널로 이벤트를 다시 전송합니다. 하지만 오류 처리기 프로세서가 실패하는 경우, 잘못된 이벤트를 관리자에게 송신하여 추가 검사를 수행할 수 있습니다. 오류 처리기 프로세서를 사용하는 경우, 잘못된 이벤트는 다시 제출될 시 순서대로 처리됩니다.
데이터 손실.
비동기 통신의 또 다른 과제는 데이터 손실입니다. 이벤트를 성공적으로 처리하고 다음 구성 요소에 전달하기 전에 구성 요소가 충돌하는 경우 이벤트가 삭제되고 최종 대상으로 전달되지 않습니다. 데이터 손실 가능성을 최소화하려면 전송 중인 이벤트를 지속하고 다음 구성 요소가 이벤트 수신을 승인한 경우에만 이벤트를 제거하거나 큐에서 제거합니다. 이러한 기능을 일반적으로 클라이언트 승인 모드 및 마지막 참가자 지원이라고 합니다.
기존 요청-응답 패턴 구현
경우에 따라 이벤트 생산자는 주문을 진행하기 전에 고객 자격 획득과 같은 이벤트 소비자의 즉각적인 응답을 요구합니다. 이벤트 기반 아키텍처에서 요청-응답 메시징을 통해 동기 통신을 수행할 수 있습니다.
이 패턴은 일반적으로 요청 큐 및 응답 큐와 같은 여러 큐를 활용하여 구현됩니다. 이벤트 생산자는 요청 큐에 비동기 요청을 보내고, 해당 작업에 대한 다른 작업을 일시 중지하고, 회신 큐에서 응답을 기다립니다. 를 효과적으로 동기 프로세스로 전환합니다. 그런 다음 이벤트 소비자는 요청을 처리하고 응답 큐를 통해 회신을 다시 보냅니다. 이 방법은 일반적으로 추적을 위해 세션 ID를 활용하므로 이벤트 생산자는 특정 요청과 관련된 응답 큐의 메시지를 알 수 있습니다. 원래 요청은 회신 헤더 또는 상호 합의된 다른 사용자 지정 특성에서 응답 큐의 이름(잠재적으로 임시)을 지정할 수도 있습니다.
적절한 수의 이벤트를 유지 관리합니다.
과도한 수의 세분화된 이벤트를 생성하면 시스템이 포화되고 과부하가 발생하여 이벤트의 전체 흐름을 효과적으로 분석하기가 어려울 수 있습니다. 이 문제는 변경 내용을 롤백해야 할 때 더욱 악화됩니다. 반대로, 이벤트를 과도하게 통합하면 문제가 발생하여 이벤트 소비자의 불필요한 처리 및 응답이 발생할 수 있습니다.
적절한 균형을 달성하려면 이벤트의 결과와 소비자가 이벤트 페이로드를 검사하여 응답을 확인해야 하는지 여부를 고려합니다. 예를 들어 규정 준수 검사 구성 요소가 있는 경우 규격 및 비규격의 두 가지 이벤트 유형만 게시하는 것으로 충분할 수 있습니다. 이 방법을 사용하면 각 이벤트를 관련 소비자만 처리하여 불필요한 처리를 방지할 수 있습니다.
기타 고려 사항
- 이벤트에 포함할 데이터의 양은 성능과 비용 모두에 영향을 주는 중요한 고려 사항일 수 있습니다. 이벤트 자체에서 처리하는 데 필요한 모든 관련 정보를 배치하면 처리 코드를 간소화하고 추가 조회를 저장할 수 있습니다. 몇 개의 식별자와 같은 최소한의 정보를 이벤트에 배치하면 전송 시간과 비용이 줄어들지만 필요한 추가 정보를 조회하려면 처리 코드가 필요합니다. 이에 대한 자세한 내용은 이 블로그 게시물을 참조하세요.
- 요청 처리 구성 요소에만 요청이 보이는 반면, 이벤트는 해당 구성 요소들이 소비하지 않거나 소비할 의도가 없더라도 워크로드 내 여러 구성 요소에 보이는 경우가 많습니다. "위반 가정" 사고방식을 사용하여 운영하는 경우, 이벤트에 포함되는 정보를 염두에 두어 의도하지 않은 정보 노출을 방지해야 합니다.
- 많은 애플리케이션은 이벤트 기반 아키텍처를 기본 아키텍처로 사용합니다. 그러나 이 방법은 다른 아키텍처 스타일과 결합되어 하이브리드 아키텍처를 생성할 수 있습니다. 일반적인 조합에는 마이크로 서비스, 파이프 및 필터가 포함됩니다. 이벤트 기반 아키텍처를 통합하면 병목 상태를 제거하고 요청량이 많은 동안 다시 압력을 제공하여 시스템 성능을 향상시킵니다.
- 특정 도메인은 여러 이벤트 생산자, 소비자 또는 이벤트 채널에 걸쳐 있는 경우가 많습니다. 특정 도메인을 변경하면 많은 구성 요소에 영향을 미칠 수 있습니다.
관련 참고 자료
- 연출 및 오케스트레이션 사이에서 선택하는 고려 사항에 관한 커뮤니티 토론 비디오.