연출 패턴

Azure Event Grid
Azure Service Bus

워크플로 논리를 분산하고 시스템 내의 다른 구성 요소에 책임을 분산합니다.

컨텍스트 및 문제점

클라우드 기반 애플리케이션은 종종 비즈니스 트랜잭션을 엔드투엔드 처리하기 위해 함께 작동하는 여러 소규모 서비스로 나뉩니다. 단일 작업(트랜잭션 내)조차도 모든 서비스 간에 여러 지점 간 호출이 발생할 수 있습니다. 이상적으로는 이러한 서비스를 느슨하게 결합해야 합니다. 종종 복잡한 서비스 간 통신이 포함되기 때문에 분산되고 효율적이며 확장 가능한 워크플로를 설계하는 것은 어렵습니다.

통신의 일반적인 패턴은 중앙 집중식 서비스 또는 오케스트레이터를 사용하는 것입니다. 들어오는 요청은 해당 서비스에 작업을 위임할 때 오케스트레이터를 통해 흐릅니다. 각 서비스는 자신의 책임을 완료하고 전체 워크플로를 인식하지 못합니다.

중앙 오케스트레이터를 사용하여 요청을 처리하는 워크플로의 다이어그램입니다.

오케스트레이터 패턴은 일반적으로 사용자 지정 소프트웨어로 구현되며 해당 서비스의 책임에 대한 기본 지식이 있습니다. 이점은 오케스트레이터가 다운스트림 서비스에서 수행하는 개별 작업의 결과에 따라 트랜잭션의 상태 통합할 수 있다는 것입니다.

그러나 몇 가지 단점이 있습니다. 통신 경로의 일부를 다시 연결해야 하므로 서비스를 추가하거나 제거하면 기존 논리가 중단될 수 있습니다. 이러한 종속성은 오케스트레이터 구현을 복잡하고 기본 어렵게 만듭니다. 오케스트레이터는 워크로드의 안정성에 부정적인 영향을 미칠 수 있습니다. 부하 상태에서 성능 병목 상태를 발생시키고 단일 실패 지점이 될 수 있습니다. 또한 다운스트림 서비스에서 연속 오류가 발생할 수 있습니다.

솔루션

서비스 간에 트랜잭션 처리 논리를 위임합니다. 각 서비스가 비즈니스 운영을 위한 통신 워크플로를 결정하고 참여하도록 합니다.

이 패턴은 통신 워크플로를 중앙 집중화하는 사용자 지정 소프트웨어에 대한 종속성을 최소화하는 방법입니다. 구성 요소는 서로 직접 통신하지 않고 워크플로를 자체적으로 안무할 때 공통 논리를 구현합니다.

안무를 구현하는 일반적인 방법은 다운스트림 구성 요소가 요청을 클레임하고 처리할 때까지 요청을 버퍼링하는 메시지 브로커를 사용하는 것입니다. 이미지는 게시자-구독자 모델을 통한 요청 처리를 보여줍니다.

메시지 브로커를 사용하여 요청을 처리하는 방법을 보여 주는 다이어그램입니다.

  1. 클라이언트 요청은 메시지 브로커에서 메시지로 큐에 대기됩니다.

  2. 서비스 또는 구독자는 브로커를 폴링하여 구현된 비즈니스 논리에 따라 해당 메시지를 처리할 수 있는지 확인합니다. 브로커는 해당 메시지에 관심이 있는 구독자에게 메시지를 푸시할 수도 있습니다.

  3. 각 구독 서비스는 메시지에 표시된 대로 작업을 수행하고 작업의 성공 또는 실패로 브로커에 응답합니다.

  4. 성공하면 서비스가 메시지를 동일한 큐 또는 다른 메시지 큐로 다시 푸시하여 필요한 경우 다른 서비스가 워크플로를 계속할 수 있도록 할 수 있습니다. 작업이 실패하면 메시지 브로커는 다른 서비스와 함께 작동하여 해당 작업 또는 전체 트랜잭션을 보정합니다.

문제 및 고려 사항

오케스트레이터를 분산하면 워크플로를 관리하는 동안 문제가 발생할 수 있습니다.

  • 실패를 전달하는 것은 어려울 수 있습니다. 애플리케이션의 구성 요소는 원자성 작업을 수행할 수 있지만 여전히 종속성 수준이 있을 수 있습니다. 한 구성 요소의 실패는 다른 구성 요소에 영향을 줄 수 있으므로 전체 요청을 완료하는 데 지연이 발생할 수 있습니다.

    오류를 정상적으로 처리하기 위해 보상 트랜잭션을 구현하면 복잡성이 발생할 수 있습니다.

    안무 패턴의 오류 처리를 보여 주는 순서도입니다.

  • 이 패턴은 독립적인 비즈니스 작업이 병렬로 처리되는 워크플로에 적합합니다. 안무가 시퀀스에서 발생해야 하는 경우 워크플로가 복잡해질 수 있습니다. 예를 들어 서비스 D는 서비스 B 및 서비스 C가 성공적으로 작업을 완료한 후에만 작업을 시작할 수 있습니다.

    병렬 및 이후에 집안일 패턴을 구현하는 메시징 시스템의 워크플로 다이어그램입니다.

  • 서비스 수가 빠르게 증가하면 패턴이 문제가 됩니다. 독립적인 이동 부품 수가 많을 경우 서비스 간의 워크플로가 복잡해지는 경향이 있습니다. 또한 분산 추적이 어려워집니다.

  • 오케스트레이터 주도 디자인에서 중앙 구성 요소는 부분적으로 참여하고 복원력 논리를 다른 구성 요소에 위임하여 일시적, 비정형 및 시간 제한 오류를 일관되게 다시 시도합니다. 안무 패턴에서 오케스트레이터가 해체되면 다운스트림 구성 요소는 이러한 복원력 작업을 선택해서는 안 됩니다. 복원력 처리기는 여전히 처리해야 합니다. 하지만 이제 다운스트림 구성 요소는 복원력 처리기와 직접 통신하여 지점 간 통신을 늘려야 합니다.

이 패턴을 사용해야 하는 경우

다음 경우에 이 패턴을 사용합니다.

  • 다운스트림 구성 요소는 원자성 작업을 독립적으로 처리합니다. 그것을 '불과 잊어버리는' 메커니즘으로 생각하십시오. 구성 요소는 적극적으로 관리할 필요가 없는 작업을 담당합니다. 작업이 완료되면 다른 구성 요소에 알림을 보냅니다.

  • 구성 요소는 자주 업데이트되고 교체될 것으로 예상됩니다. 이 패턴을 사용하면 기존 서비스에 대한 작업 및 중단을 최소화하면서 애플리케이션을 수정할 수 있습니다.

  • 이 패턴은 간단한 워크플로에 적합한 서버리스 아키텍처에 적합합니다. 구성 요소는 수명이 짧고 이벤트 기반일 수 있습니다. 이벤트가 발생하면 구성 요소가 회전하고 작업을 수행하며 작업이 완료되면 제거됩니다.

  • 중앙 오케스트레이터에서 발생하는 성능 병목 현상이 있습니다.

다음의 경우에는 이 패턴이 유용하지 않습니다.

  • 애플리케이션은 복잡하며 다운스트림 구성 요소를 경량으로 유지하기 위해 공유 논리를 처리하는 중앙 구성 요소가 필요합니다.

  • 구성 요소 간의 지점 간 통신이 불가피한 상황이 있습니다.

  • 비즈니스 논리를 사용하여 다운스트림 구성 요소에서 처리하는 모든 작업을 통합해야 합니다.

워크로드 디자인

설계자는 워크로드 디자인에서 안무 패턴을 사용하여 Azure Well-Architected Framework 핵심 요소에서 다루는 목표와 원칙을 해결하는 방법을 평가해야 합니다. 예시:

핵심 요소 이 패턴이 핵심 목표를 지원하는 방법
운영 우수성은 표준화된 프로세스와 팀 응집력을 통해 워크로드 품질을 제공하는 데 도움이 됩니다. 이 패턴의 분산 구성 요소는 자율적이고 교체 가능하도록 설계되었으므로 시스템에 대한 전반적인 변경 내용이 적어 워크로드를 수정할 수 있습니다.

- OE:04 도구 및 프로세스
성능 효율성은 크기 조정, 데이터, 코드의 최적화를 통해 워크로드가 수요를 효율적으로 충족하는 데 도움이 됩니다. 이 패턴은 중앙 집중식 오케스트레이션 토폴로지에서 성능 병목 현상이 발생하는 경우의 대안을 제공합니다.

- PE:02 용량 계획
- PE:05 크기 조정 및 분할

디자인 결정과 마찬가지로 이 패턴으로 도입될 수 있는 다른 핵심 요소의 목표에 대한 절충을 고려합니다.

예시

이 예제에서는 마이크로 서비스와 함께 함수를 실행하는 이벤트 구동 클라우드 네이티브 워크로드를 만들어 안무 패턴을 보여 줍니다. 클라이언트가 패키지를 배송하도록 요청하면 워크로드는 드론을 할당합니다. 예약된 드론에서 패키지를 픽업할 준비가 되면 배달 프로세스가 시작됩니다. 전송 중에 워크로드는 배송된 상태 얻을 때까지 배달을 처리합니다.

이 예제는 오케스트레이터 패턴을 안무 패턴으로 대체하는 드론 배달 구현의 리팩터링입니다.

안무 패턴을 구현하는 이벤트 기반 클라우드 네이티브 예제 워크로드 다이어그램

수집 서비스는 클라이언트 요청을 처리하고 배달 세부 정보를 포함한 메시지로 변환합니다. 비즈니스 트랜잭션은 이러한 새 메시지를 사용한 후에 시작됩니다.

단일 클라이언트 비즈니스 트랜잭션에는 다음과 같은 세 가지 고유한 비즈니스 작업이 필요합니다.

  1. 패키지 만들기 또는 업데이트
  2. 패키지를 배달하는 드론 할당
  3. 배송 시 검사 및 결국 인식 제고로 구성된 배달을 처리합니다.

3개의 마이크로 서비스는 패키지, 드론 스케줄러 및 배달 서비스라는 비즈니스 처리를 수행합니다. 서비스는 중앙 오케스트레이터 대신 메시징을 사용하여 서로 통신합니다. 각 서비스는 비즈니스 워크플로를 분산된 방식으로 조정하는 프로토콜을 미리 구현해야 합니다.

디자인

비즈니스 트랜잭션은 여러 홉을 통해 순서대로 처리됩니다. 각 홉은 모든 비즈니스 서비스 간에 단일 메시지 버스를 공유합니다.

클라이언트가 HTTP 엔드포인트를 통해 배달 요청을 보내면 수집 서비스는 이를 수신하고, 이러한 요청을 메시지로 변환한 다음, 메시지를 공유 메시지 버스에 게시합니다. 구독된 비즈니스 서비스는 버스에 추가된 새 메시지를 사용합니다. 메시지를 받으면 비즈니스 서비스가 성공, 실패 또는 요청 시간이 초과된 작업을 완료할 수 있습니다. 성공하면 서비스는 Ok 상태 코드로 버스에 응답하고, 새 작업 메시지를 발생시키고, 메시지 버스로 보냅니다. 오류 또는 시간 초과가 있는 경우 서비스는 메시지 버스에 이유 코드를 전송하여 오류를 보고합니다. 또한 메시지는 배달 못 한 편지 큐에 추가됩니다. 합리적이고 적절한 시간 내에 수신하거나 처리할 수 없는 메시지도 DLQ로 이동됩니다.

디자인은 여러 메시지 버스를 사용하여 전체 비즈니스 트랜잭션을 처리합니다. Microsoft Azure Service BusMicrosoft Azure Event Grid 는 이 디자인에 대한 메시징 서비스 플랫폼을 제공하도록 구성됩니다. 워크로드는 수집을 위해 Azure Functions를 호스팅하는 Azure Container Apps 및 비즈니스 논리를 실행하는 이벤트 기반 처리를 처리하는 앱에 배포됩니다.

디자인은 안무가 시퀀스에서 발생하도록 보장합니다. 단일 Azure Service Bus 네임스페이스에는 두 개의 구독과 세션 인식 큐가 있는 토픽이 포함되어 있습니다. 수집 서비스는 토픽에 메시지를 게시합니다. 패키지 서비스 및 드론 스케줄러 서비스는 토픽을 구독하고 성공을 큐에 전달하는 메시지를 게시합니다. 배달 식별자에 연결된 GUID가 있는 공통 세션 식별자를 포함하면 관련 메시지의 바인딩되지 않은 시퀀스를 순서대로 처리할 수 있습니다. 배달 서비스는 트랜잭션당 두 개의 관련 메시지를 대기합니다. 첫 번째 메시지는 패키지를 배송할 준비가 되었음을 나타내고 두 번째 메시지는 드론이 예약되었음을 나타냅니다.

이 디자인은 Azure Service Bus를 사용하여 전체 배달 프로세스 중에 손실되거나 중복될 수 없는 고가의 메시지를 처리합니다. 패키지가 배송되면 Azure Event Grid로 상태 변경도 게시됩니다. 이 디자인에서 이벤트 발신자는 상태 변경이 처리되는 방식에 대해 전혀 기대하지 않습니다. 이 디자인의 일부로 포함되지 않은 다운스트림 조직 서비스는 이 이벤트 유형을 수신 대기하고 특정 비즈니스 목적 논리를 실행하는 데 반응할 수 있습니다(즉, 배송된 주문 상태 사용자에게 메일 보내기).

AKS pub-sub 패턴 애플리케이션 상용구와 같은 다른 컴퓨팅 서비스에 배포하려는 경우 동일한 Pod에 두 개의 컨테이너를 사용하여 구현할 수 있습니다. 한 컨테이너는 기본 설정의 메시지 버스와 상호 작용하는 앰배서더 를 실행하고 다른 컨테이너는 비즈니스 논리를 실행합니다. 동일한 Pod에 두 개의 컨테이너를 사용하는 접근 방식은 성능 및 확장성을 향상시킵니다. 앰배서더와 비즈니스 서비스는 동일한 네트워크를 공유하여 짧은 대기 시간과 높은 처리량을 허용합니다.

여러 작업으로 이어질 수 있는 연속적인 재시도 작업을 방지하려면 비즈니스 서비스에서 허용되지 않는 메시지에 즉시 플래그를 지정해야 합니다. 잘 알려진 이유 코드 또는 정의된 애플리케이션 코드를 사용하여 이러한 메시지를 보강할 수 있으므로 DLQ(배달 못 한 편지 큐)로 이동할 수 있습니다. 다운스트림 서비스에서 Saga를 구현하는 일관성 문제를 관리하는 것이 좋습니다. 예를 들어 다른 서비스는 보정, rety 또는 피벗 트랜잭션을 실행해야만 수정 목적으로 배달 못한 메시지를 처리할 수 있습니다.

재시도 작업으로 인해 리소스가 중복되지 않도록 비즈니스 서비스는 idempotent입니다. 예를 들어 패키지 서비스는 upsert 작업을 사용하여 데이터 저장소에 데이터를 추가합니다.

연출을 위해 디자인에서 이러한 패턴을 고려해 보세요.