Home 소프트웨어 아키텍처 101 - CHAPTER 14 이벤트 기반 아키텍처 스타일
Post
Cancel

소프트웨어 아키텍처 101 - CHAPTER 14 이벤트 기반 아키텍처 스타일

이벤트 기반 아키텍처(event-driven architecture)는 확장성이 뛰어난 고성능 애플리케이션 개발에 널리 쓰이는 비동기 분산 아키텍처 스타일입니다. 이벤트 기반 아키텍처는 이벤트를 비동기 수신/처리하는 별도의 이벤트 처리 컴포넌트들로 구성되며, 스탠드얼론 아키텍처 스타일로 사용하거나 다른 아키텍처 스타일(예: 이벤트 기반 마이크로 서비스 아키텍처)에 내장할 수도 있습니다.

14.1 토폴로지

이벤트 기반 아키텍처의 주요 토폴로지는 중재자 토폴로지(mediator topology)와 브로커 토폴로지(broker topology)입니다. 주로 중재자 토폴로지는 이벤트 처리 워크플로를 제어해야 할 경우에, 브로커 토폴로지는 신속한 응답과 동적인 이벤트 처리 제어가 필요할 때 각각 사용됩니다.

14.2 브로커 토폴로지

브로커 토폴로지는 중앙에 이벤트 중재자가 없다는 점에서 중재자 토폴로지와 다릅니다. 이 토폴로지는 비교적 이벤트 처리 흐름이 다눈하고 굳이 중앙에서 이벤트를 조정할 필요가 없을 때 유용합니다.

브로커 토폴로지는 네 가지 기본 아키텍처 컴포넌트, 즉 시작 이벤트, 이벤트 브로커, 이벤트 프로세서, 처리 이벤트로 구성됩니다. 시작 이벤트(initiating event)는 단순한 이벤트든, 복잡한 이벤트든 전체 이벤트 흐름을 개시하는 이벤트를 말합니다. 시작 이벤트는 이벤트 브로커의 이벤트 채널로 전송되어 처리됩니다. 단일 이벤트 프로세서는 이벤트 브로커에서 시작 이벤트를 받자마자 관련된 처리 작업을 마친 뒤 처리 이벤트(processing event)를 생성하고 시스템의 나머지 부분에 자신이 한 일을 비동기로 알립니다. 다른 이벤트 프로세서는 처리 이벤트를 리스닝하도 있다가 이벤트가 들어오면 그에 맞는 작업을 수행한 뒤 다시 새로운 처리 이벤트를 발행함으로써 자신이 한 일을 모두에게 알립니다. 이 과정은 최종 이벤트 프로세서가 한 일에 아무도 관심이 없을 때까지 되풀이됩니다.

브로커 토폴로지에서는 다른 이벤트 프로세서의 관심 여부와 무관하게 각 이벤트 프로세서가 자신이 한 일을 모두에게 알리는 게 항상 바람직합니다. 그래야 나중에 이벤트를 처리하는 과정에서 기능 추가각 필요하게 되더라도 아키텍처를 쉽게 확장할 수 있습니다.

브로커 토폴로지는 성능, 응답성, 확장성 측면에서 장점이 많지만 그만큼 단점도 적지 않습니다. 무엇보다 시작 이벤트와 연관된 전체 워크플로를 제어할 수 없습니다. 에러 처리 역시 어렵습니다.

스크린샷 2024-10-02 오후 5.32.43.png

14.3 중재자 토폴로지

중재자 토폴로지(mediator topology)는 브로커 토폴로지의 단점들을 일부 보완합니다. 여러 이벤트 프로세서 간의 조정이 필요한 시작 이벤트에 대하여 워크플로를 관리/제어하는 이벤트 중재자(event mediator)가 핵심입니다. 중재자 토폴로지는 시작 이벤트, 이벤트 큐, 이벤트 중재자, 이벤트 채널, 이벤트 프로세서, 이렇게 5개의 아키텍처 컴포넌트로 구성됩니다.

시작 이벤트가 전체 이벤트 프로세스를 개시하는 이벤트인 점은 브로커 토폴로지와 동일하지만, 중재자 토폴로지에서는 시작 이벤트 큐를 거쳐 이벤트 중재자로 전달되는 차이점이 있습니다. 이벤트 중재자는 이벤트 처리에 관한 단계 정보만 갖고 있으므로 점재점 메시징으로 각각의 이벤트 채널(대부분 큐)로 전달 되는 처리 이벤트를 생성합니다. 그러면 각 이벤트 프로세서는 자신의 이벤트 채널에서 이벤트를 받아 처리한 다음 중재자에게 작업을 완료했다고 응답합니다. 이벤트 프로세서가 다른 프로세서에게 자신이 한 일을 알리지 않는다는 것도 브로커 토폴로지와 다른 점입니다[그림 14-5].

스크린샷 2024-10-04 오후 7.55.19.png

중재자 토폴로지 구현체에는 대부분 특정 도메인이나 이벤트 그룹과 연관된 중재자가 여럿 존재하므로 토폴로지의 단일 장애점(single point of failure, SPF)을 줄이고 전체 처리량과 성능을 높일 수 있습니다.

스크린샷 2024-10-04 오후 8.01.17.png

스크린샷 2024-10-04 오후 8.01.39.png

스크린샷 2024-10-04 오후 8.02.12.png

스크린샷 2024-10-04 오후 8.02.40.png

스크린샷 2024-10-04 오후 8.03.14.png

중재자 컴포넌트는 브로커 토폴로지와는 달리 워크플로에 대해 잘 알고 있고 통제가 가능합니다. 중재자는 워크플로를 제어하므로 이벤트 상태를 유지하면서 필요시 에러 처리, 복구, 재시작을 할 수 있습니다.

두 토폴로지는 처리 이벤트의 의미와 사용 방법이 본질적으로 다릅니다. 브로커 토폴로지에서는 시스템에서 발생한 이벤트로서 처리 이벤트가 발생되고 이벤트 프로세서는 각자 맡은 일을 하면서 나머지 이벤트 프로세서는 그 액션에 반응하는 식으로 돌아갑니다.하지만 중재자 토폴로지에서 처리 이벤트는 사건(incident, 이미 일어난 일)이 아니라 커맨드(command, 일어나야 할 일)입니다. 따라서 중재자 토폴로지에서는 처리 이벤트가 반드시 처리되어야 할 이벤트인(커맨드) 반면, 브로커 토폴로지에서는 그냥 무시해도 됩니다(반응).

이처럼 중재자 토폴로지는 브로커 토폴로지에서 불가능한 문제를 해결할 수 있지만 그만큼 부정적인 요소도 있습니다. 첫째, 복잡한 이벤트 흐름 내에서 발생하는 동적인 처리를 선언적으로 모델링하기가 매우 어렵습니다. 그래서 보통은 중재자의 내부 워크플로는 일반적인 처리만 하고 복잡한 이벤트 처리의 변화무쌍한 부분은 중재자 + 브로커 형태의 하이브리드 모델로 처리합니다. 둘째, 이벤트 프로세서는 브로커 토폴로지와 동일한 방식으로 쉽게 확장할 수 있지만, 그러자면 중재자도 함께 확장해야 하므로 전체 이벤트 처리 흐름에 병목 지점이 생기기 쉽습니다. 셋째, 중재자 토폴로지는 이벤트 처리를 중재자가 제어하므로 이벤트 프로세서가 상대적으로 더 많이 커플링되어 성능은 브로커 토폴로지보다 좋지 않습니다.

스크린샷 2024-10-05 오후 4.04.58.png

브로커 토폴로지냐, 중재자 토폴로지냐, 결국 워크플로 제어와 에러 처리 기능이 우선인가, 아니면 고성능 확장성이 더 중요한가의 트레이드오프를 잘 따져 선택할 수밖에 없습니다. 중재자 토폴로지의 성능과 확장성도 그리 나쁜 편은 아니지만 아무래도 브로커 토폴로지만큼은 못 한 게 사실입니다.

14.4 비동기 통신

에벤트 기반 아키텍처 스타일은 (이벤트 컨슈머의 응답을 받아야 하는) 요청/응답 처리뿐만 아니라 (응답이 필요 없는) 파이어 앤드 포겟 처리 모두 비동기 통신만 사용한다는 점에서 다른 아키텍처 스타일과 차별화됩니다. 비동기 통신은 시스템 응답성을 전방적으로 높이는 강력한 기법으로 활용할 수 있습니다.

비동기 통신에서는 에러 처리가 가장 큰 문제입니다. 응답성은 엄청나게 개선되지만 에러를 제대로 처리하기가 쉽지 않기 때문에 이벤트 기반 시스템의 복잡도는 가중됩니다.

14.5 에러 처리

리액티브 아키텍처의 워크플로 이벤트 패턴은 비동기 워크플로에서 에러 처리 문제를 해결하는 한 가지 방법입니다. 시스템을 응답성에 영향을 미치지 않고 탄력적으로 에러를 처리할 수 있게 만드는 패턴이죠.

워크플로 이벤트 패턴은 워크플로 대리자(workflow delegate)를 통해 위임(delegation), 봉쇄(containment), 수리(repair) 작업을 합니다. 이벤트 프로듀서는 메시지 채널을 통해 데이터를 이벤트 컨슈머에게 비동기로 전송하고, 이벤트 컨슈머가 데이터를 처리하는 도중 에러가 발생하면 즉시 해당 에러를 워크플로 프로세서에게 위임한 뒤 이벤트 큐에 있는 다음 메시지로 넘어갑니다. 이렇게 에러가 발생해도 바로 다음 메시지를 처리하므로 전체 응답성은 영향을 받지 않습니다.

에러를 수신한 워크플로 프로세서는 메시지에 무엇이 잘못됐는지 살펴봅니다. 워크플로 프로세서는 (사람의 개입 없이) 프로그래밍 방식으로 원 데이터를 변경해서 긴급 조치한 후 원래 큐로 돌려보냅니다. 이벤트 컨슈머는 이 메시지를 새로운 메시지로 간주하여 이번에는 성공을 기대하며 재처리를 시도합니다. 물론 끝내 워크플로 프로세서가 메시지의 문제점을 파악할 수 없는 경우도 있을 것입니다. 이럴 때에는 메시지를 다른 큐로 보내 ‘대시보드(dashboard)’라고 부르는 애플리케이션(예: 마이크로 소프트 아웃룩(Microsoft Outlook)이나 애플 메일(Apple Mail))이 받습니다. 대시보드는 보통 업무 담당자의 데스크탑에 위치하는데, 담당자는 직접 메시지를 확인해 조치하고 원래 큐로 다시 전송합니다.

스크린샷 2024-10-06 오전 11.53.57.png

워크플로 이벤트 패턴의 예를 하나 들어보겠습니다. 어떤 지역의 거래 자문가(trading advisor)가 다른 지역에 있는 대형 트레이딩펌(trading firm)를 대신하여 거래 주문을 받는다고 합시다.

스크린샷 2024-10-06 오전 11.56.01.png

워크플로 이벤트 패턴에서 한 가지 주의할 점은, 에러가 발생한 메시지를 조치 후 다시 제출하면 처리 순서가 바뀌는 것입니다.

14.6 데이터 소실 방지

비동기 통신을 할 때 데이터 소실(data loss)은 언제나 중요한 관심사인데, 불행하게도 이벤트 기반 아키텍처는 데이터가 소실될 만한 곳이 참 많습니다.

스크린샷 2024-10-06 오후 10.13.57.png

1번 이슈(메시지가 큐에 전달되지 않음)는 동기 전송(synchronous send)과 퍼시스턴트 메시지 큐를 이용하면 쉽게 해결됩니다. 퍼시스턴스 메시지 큐는 이른바 전달 보장(guaranteed delivery)도 지원합니다.

2번 이슈(이벤트 프로세서 B가 큐에서 다음 메시지를 꺼내 이벤트를 처리하기 전에 고장) 역시 클라이언트 확인응답 모드(client acknowledge mode)라는 기본적인 메시징 기술을 이용하면 해결 가능합니다.

3번 이슈(데이터 에러 때문에 이벤트 프로세서 B가 메시지를 데이터베이스에 저장할 수 없음)는 데이터베이스 본연의 ACID(원자성, 일관성, 격리성, 내구성) 트랜잭션의 커밋으로 해결 가능합니다.

스크린샷 2024-10-06 오후 10.23.34.png

14.7 브로드캐스팅

이벤트 기반 아키텍처는 메시지를 누가 받든(컨슈머가 있다면), 그 메시지로 무슨 일을 하든 상관없이 이벤트를 브로드캐스트(broadcast, 전파)할 수 있습니다.

메시지 프로듀서는 자신이 보낸 메시지를 어느 이벤트 프로세서가 수신할지, 또 메시지를 받아 무슨 일을 할지 모릅니다. 그러므로 어쩌면 브로드캐스팅은 여러 이벤트 프로세서를 가장 높은 수준으로 디커플링하는 수단이며, 최종 일관성, 복잡한 이벤트 처리(complex event, processing, CEP) 등 다양한 쓰임새를 지닌 필수 기능입니다.

14.8 요청-응답

이벤트 기반 아키텍처는 동기 통신을 요청-응탑 메시징(request-response messaging, 의사 동기 통신(pseudosynchronous communication 이라고도 함)) 방식으로 수행합니다. 요청-응답 메시징 내부의 각 이벤트 채널은 요청 큐, 응답 큐로 구성됩니다. 처음 정보를 요청하면 요청 규에 비동기 전송된 후 메시지 프로듀서에게 제어권이 반환되며, 메시지 프로듀서는 응답 큐에 응답이 도착하길 기다리며 차단 대기(blocking wait) 상태가 됩니다. 메시지 컨슈머가 메시지를 받아 처리한 후 응답 큐에 응답을 보내면 이벤트 프로듀서는 응답 데이터가 포함된 메시지를 수신합니다[그림 14-19].

스크린샷 2024-10-07 오후 4.01.05.png

요청-응답 메시징을 구현하는 주요한 기술은 두 가지입니다. 첫째, 가장 일반적인 기술로, 메시지 헤더에 상관(conrrelation) ID를 사용하는 것입니다. 상관 ID는 응답 메시지의 필드로, 대부분 원요청 메시지의 메시지 ID로 세팅됩니다.

스크린샷 2024-10-07 오후 4.04.10.png

둘째, 응답 큐에 임시 큐(temporary queue)를 두고 요청-응답 메시징을 구현하는 방법입니다. 임시 큐는 지정된 요청에만 사용되는데, 요청이 들어오면 생성되고 요청이 종료되면 삭제됩니다.

스크린샷 2024-10-07 오후 4.05.57.png

기술적으로는 임시 큐가 훨씬 단순하지만 메시지 브로커는 매번 요청을 할 때마다 임시 큐를 생성/폐기하는 일을 반복해야 합니다. 따라서 대용량 메시지 처리시 메시지 브로커의 속도가 크게 떨어지고 전체 성능과 응답성 역시 영향을 받을 수 있습니다. 그래서 우리는 대체로 상관 ID를 사용하는 방법을 권장합니다.

14.9 요청 기반이냐, 이벤트 기반이냐

워크플로의 확장성과 제어가 중요하면 체계적인 데이터 기반 요청에 특화된 요청 기반 모델을, 복잡하고 동적인 유저 처리 등 주로 고도의 응답성과 확장성을 요하는, 유연한 액션 단위의 이벤트를 처리한다면 이벤트 기반 모델이 좋은 선택입니다.

스크린샷 2024-10-07 오후 11.50.55.png

14.10 하이브리드 이벤트 기반 아키텍처

이벤트 기반 아키텍처를 다른 아키텍처 스타일의 일부로 활용하는 아키텍처 스타일로는 마이크로 서비스 아키텍처, 공간 기반 아키텍처가 대표적입니다.

어떤 아키텍처 스타일리든지 이벤트 기반 아키텍처를 추가하면 병목 지점을 제거하고 이벤트 요청을 백업하는 배압 지점(back pressure point)을 확보하는 데 유용하며, 다른 아키텍처 스타일에서는 찾아볼 수 없는 유저 응답성이 보장됩니다.

14.11 아키텍처 특성 등급

스크린샷 2024-10-07 오후 11.59.01.png

이벤트 기반 아키텍처는 특정 도메인이 여러 이벤트 프로세서에 분산되어 있고 중재자, 큐, 토픽을 통해 서로 묶여 있는, 기술 분할된 아키텍처입니다. 한 도메인에 변경이 발생하면 많은 이벤트 프로세서, 중재자, 다른 메시징 아티팩트에도 영향을 미치므로 이벤트 기반 아키텍처는 도메인 분할 아키텍처는 아닙니다.

이벤트 프로세서(경쟁 컨슈머(competing consumer)라고도 함)는 프로그래밍 방식의 로드 밸런싱이 가능하며 확장성이 매우 뛰어납니다.

이 아키텍처는 특유의 비결정적, 동적인 이벤트 흐름 때문에 단순성과 시험성이 상대적으로 낮은 편입니다. 이벤트 프로세서가 동적 이벤트에 어떻게 반응할지, 어떤 메시지를 생성할지 알 수 없는 때가 더 많습니다. 따라서 ‘이벤트 트리 다이어그램(event tree diagram)’이 매우 복잡해질 수 있고 시나리오 가짓수만 수백~수천 개에 달하므로 관리 및 테스트가 아주 어렵습니다.

요약

14.1 토폴로지

  • 이벤트 기반 아키텍처의 주요 토폴로지
    • 중재자 토폴로지 (Mediator Topology)
      • 이벤트 처리 워크플로를 제어해야 할 때 사용
    • 브로커 토폴로지 (Broker Topology)
      • 신속한 응답과 동적인 이벤트 처리 제어가 필요할 때 사용

14.2 브로커 토폴로지

  • 중앙 이벤트 중재자가 없음
  • 구성 요소
    • 시작 이벤트 (Initiating Event): 전체 이벤트 흐름을 개시
    • 이벤트 브로커 (Event Broker): 이벤트 채널로 이벤트를 전송 및 처리
    • 이벤트 프로세서 (Event Processor): 이벤트를 처리하고 처리 이벤트를 생성
    • 처리 이벤트 (Processing Event): 이벤트 프로세서가 생성하여 시스템에 알림
  • 특징
    • 각 이벤트 프로세서는 자신이 한 일을 모두에게 알림
    • 성능, 응답성, 확장성 측면에서 우수
  • 단점
    • 워크플로 제어가 어려움
    • 에러 처리 복잡

14.3 중재자 토폴로지

  • 브로커 토폴로지의 단점을 보완
  • 이벤트 중재자 (Event Mediator)가 워크플로를 관리/제어
  • 구성 요소
    • 시작 이벤트: 이벤트 프로세스를 개시
    • 이벤트 큐: 시작 이벤트를 중재자로 전달
    • 이벤트 중재자: 워크플로를 관리하고 처리 이벤트를 생성
    • 이벤트 채널: 처리 이벤트를 이벤트 프로세서에게 전달
    • 이벤트 프로세서: 이벤트를 처리하고 중재자에게 완료를 알림
  • 특징
    • 이벤트 프로세서는 다른 프로세서에게 자신이 한 일을 알리지 않음
    • 여러 중재자가 존재하여 단일 장애점(SPOF)을 줄이고 성능 향상
  • 장점
    • 워크플로 제어 및 에러 처리 가능
  • 단점
    • 복잡한 이벤트 흐름의 동적 처리 어려움
    • 중재자의 확장이 필요하여 병목 현상 발생 가능
    • 성능과 확장성이 브로커 토폴로지만큼 우수하지 않음

14.4 비동기 통신

  • 이벤트 기반 아키텍처는 비동기 통신만 사용
  • 비동기 통신의 장점
    • 시스템 응답성(responsiveness) 향상
  • 주의점
    • 에러 처리가 어려워 시스템 복잡도 증가

14.5 에러 처리

  • 워크플로 이벤트 패턴을 활용한 에러 처리
    • 워크플로 대리자(Workflow Delegate)를 통해 위임(delegation), 봉쇄(containment), 수리(repair) 작업 수행
  • 처리 방식
    • 이벤트 컨슈머에서 에러 발생 시 워크플로 프로세서에게 에러를 위임하고 다음 메시지 처리
    • 워크플로 프로세서는 에러 원인을 분석하고 조치 후 원래 큐로 메시지 반환
    • 필요 시 대시보드를 통해 사람이 직접 메시지를 확인하고 조치

14.6 데이터 소실 방지

  • 비동기 통신에서 데이터 소실은 중요한 문제
  • 데이터 소실 이슈와 해결 방법
    1. 메시지가 큐에 전달되지 않음
      • 동기 전송과 퍼시스턴트 메시지 큐 사용으로 해결
    2. 이벤트 프로세서가 처리 전에 고장
      • 클라이언트 확인응답 모드(Client Acknowledge Mode) 사용
    3. 데이터 에러로 데이터베이스 저장 실패
      • 데이터베이스의 ACID 트랜잭션 커밋으로 해결

14.7 브로드캐스팅

  • 메시지를 컨슈머가 누구든 상관없이 전파 가능
  • 특징
    • 이벤트 프로듀서는 메시지 수신자나 처리 방법을 모름
    • 이벤트 프로세서 간 디커플링(decoupling) 강화
  • 사용 사례
    • 최종 일관성, 복잡한 이벤트 처리 등 다양한 분야에 활용

14.8 요청-응답

  • 동기 통신을 요청-응답 메시징 방식으로 수행
  • 구성 요소
    • 요청 큐와 응답 큐로 구성된 이벤트 채널
  • 구현 기술
    • 상관 ID(Correlation ID) 사용
      • 응답 메시지의 헤더에 원 요청 메시지의 ID를 설정
    • 임시 큐(Temporary Queue) 사용
      • 요청마다 생성되고 처리 후 삭제되는 큐
  • 권장 사항
    • 성능상의 이유로 상관 ID 사용을 권장

14.9 요청 기반 vs 이벤트 기반

  • 요청 기반 모델
    • 워크플로의 확장성과 제어가 중요할 때 적합
  • 이벤트 기반 모델
    • 고도의 응답성과 확장성이 필요할 때 적합

14.10 하이브리드 이벤트 기반 아키텍처

  • 다른 아키텍처 스타일에 이벤트 기반 아키텍처를 결합
    • 예: 마이크로서비스 아키텍처, 공간 기반 아키텍처
  • 장점
    • 병목 지점 제거
    • 배압 지점(Back Pressure Point) 확보
    • 사용자 응답성 보장

14.11 아키텍처 특성 등급

  • 이벤트 기반 아키텍처의 특성
    • 기술 분할된 아키텍처로 도메인 분할 아키텍처는 아님
    • 이벤트 프로세서는 로드 밸런싱이 가능하여 확장성이 뛰어남
  • 단점
    • 비결정적이고 동적인 이벤트 흐름으로 단순성과 시험성이 낮음
    • 이벤트 트리 다이어그램이 복잡하여 관리 및 테스트 어려움
This post is licensed under CC BY 4.0 by the author.

소프트웨어 아키텍처 101 - CHAPTER 13 서비스 기반 아키텍처 스타일

소프트웨어 아키텍처 101 - CHAPTER 15 공간 기반 아키텍처 스타일