여러 동시 소비자가 동일한 메시징 채널에 수신된 메시지를 처리할 수 있게 해 줍니다. 동시 소비자가 여러 개인 경우 시스템은 동시에 여러 메시지를 처리하여 처리량을 최적화하고, 확장성 및 가용성을 개선하고, 워크로드의 균형을 맞출 수 있습니다.
컨텍스트 및 문제점
클라우드 애플리케이션은 종종 많은 수의 요청을 처리합니다. 애플리케이션은 각 요청을 동기적으로 처리하는 대신 메시징 시스템을 통해 비동기적으로 처리하는 소비자 서비스에 요청을 전달할 수 있습니다. 이 전략은 요청 처리가 애플리케이션 비즈니스 논리를 차단하는 것을 방지하는 데 도움이 됩니다.
요청 수는 시간에 따라 크게 달라질 수 있습니다. 사용자 활동이 급격하게 증가하거나 여러 테넌트에서 집계된 요청이 증가하면 예측할 수 없는 워크로드가 생성될 수 있습니다. 사용량이 많은 시간에 시스템은 초당 수백 개의 요청을 처리해야 할 수 있습니다. 다른 경우에는 숫자가 작을 수 있습니다. 또한 이러한 요청을 처리하는 데 필요한 작업은 매우 다양할 수 있습니다. 단일 소비자 서비스 인스턴스를 사용하는 경우 요청이 해당 인스턴스에 과부하가 될 수 있습니다. 또는 애플리케이션 메시지의 유입은 메시징 시스템을 오버로드할 수 있습니다.
이 변동하는 워크로드를 처리하기 위해 시스템은 여러 소비자 서비스 인스턴스를 실행할 수 있습니다. 그러나 시스템은 각 메시지가 하나의 소비자에게만 전달되도록 이러한 소비자를 조정해야 합니다. 또한 시스템은 한 인스턴스가 병목 상태가 되지 않도록 소비자 간에 워크로드의 균형을 유지해야 합니다.
해결 방법
메시지 큐를 사용하여 애플리케이션과 소비자 서비스 인스턴스 간의 통신 채널을 구현합니다. 애플리케이션은 요청을 큐에 메시지로 게시하고 소비자 서비스 인스턴스는 큐에서 메시지를 수신하고 처리합니다. 이 방법을 사용하면 동일한 소비자 서비스 인스턴스 풀에서 애플리케이션 인스턴스의 메시지를 처리할 수 있습니다. 다음 다이어그램에서는 메시지 큐가 서비스 인스턴스에 작업을 배포하는 방법을 보여 줍니다.
메모
여러 소비자가 이러한 메시지를 수신하지만 경쟁 소비자 패턴은 Publisher-Subscriber 패턴과 다릅니다. 경쟁 소비자 패턴에서 한 소비자는 처리를 위해 각 메시지를 받습니다. Publisher-Subscriber 패턴에서 모든 소비자는 모든 메시지를 받습니다.
이 솔루션에는 다음과 같은 이점이 있습니다.
애플리케이션 인스턴스에서 요청 볼륨의 다양한 변형을 처리할 수 있는 부하 수준 시스템을 제공합니다. 큐는 애플리케이션 인스턴스와 소비자 서비스 인스턴스 간의 버퍼로 작동합니다. 이 버퍼는 애플리케이션 및 서비스 인스턴스 모두에 대한 가용성 및 응답성에 미치는 영향을 최소화할 수 있습니다. 자세한 내용은 큐 기반 부하 평준화 패턴을 참조하세요. 일부 장기 실행 처리가 필요한 메시지는 다른 소비자 서비스 인스턴스가 다른 메시지를 동시에 처리하는 것을 방지하지 않습니다.
안정성을 향상시킵니다. 생산자가 이 패턴을 사용하는 대신 소비자와 직접 통신하고 소비자를 모니터링하지 않으면 메시지가 손실되거나 소비자가 실패할 때 처리하지 못할 가능성이 높습니다. 이 패턴에서 시스템은 특정 서비스 인스턴스에 메시지를 보내지 않습니다. 실패한 서비스 인스턴스는 생산자를 차단하지 않으며 모든 작업 서비스 인스턴스는 메시지를 처리할 수 있습니다.
소비자 간 또는 생산자와 소비자 인스턴스 간에 복잡한 조정이 필요하지 않습니다. 메시지 큐는 각 메시지가 한 번 이상 전달되는 것을 보장합니다.
규모가 조정됩니다. 자동 크기 조정을 적용하면 메시지 볼륨이 변동함에 따라 시스템에서 소비자 서비스 인스턴스 수를 동적으로 늘리거나 줄일 수 있습니다.
메시지 큐가 트랜잭션 읽기 작업을 제공하는 경우 복원력을 향상시킬 수 있습니다. 소비자 서비스 인스턴스가 트랜잭션 작업의 일부로 메시지를 읽고 처리하고 실패하는 경우 이 패턴은 다른 소비자 서비스 인스턴스가 메시지를 처리할 수 있도록 메시지가 큐에 반환되도록 할 수 있습니다. 지속적인 메시지 오류의 위험을 완화하려면 배달 못 한 편지 큐를 사용하는 것이 좋습니다.
문제 및 고려 사항
이 패턴을 구현하는 방법을 결정할 때 다음 사항을 고려합니다.
메시지 순서: 소비자 서비스 인스턴스가 메시지를 받는 순서는 보장되지 않으며 메시지가 만들어진 순서를 반드시 표시하지는 않습니다. 메시지를 멱등하게 처리할 수 있도록 시스템을 디자인합니다. 이 디자인은 처리 순서 종속성을 제거하는 데 도움이 됩니다.
Azure Service Bus는 메시지 세션을 사용하여 메시지 및 기타 패턴의 보장된 선점 순서를 구현할 수 있습니다.
서비스 복원력 요구 사항: 시스템이 실패한 서비스 인스턴스를 검색하고 다시 시작하는 경우 해당 서비스 인스턴스가 멱등원으로 수행하는 작업을 구현하여 단일 메시지를 두 번 이상 검색하고 처리할 때의 효과를 최소화해야 할 수 있습니다.
포이즌 메시지 검색: 잘못된 형식의 메시지 또는 사용할 수 없는 리소스에 액세스해야 하는 작업으로 인해 서비스 인스턴스가 실패할 수 있습니다. 시스템은 이러한 메시지가 큐로 무기한 반환되지 않도록 방지하고, 필요한 경우 분석을 위해 다른 곳에서 해당 세부 정보를 캡처하고 저장해야 합니다. Service Bus는 전송 횟수가 구성된 임계값을 초과하면 죽은 편지 큐로 메시지를 자동으로 보낼 수 있습니다.
결과 처리: 메시지를 처리하는 서비스 인스턴스는 메시지를 생성하는 애플리케이션 논리에서 완전히 분리되므로 직접 통신할 수 없습니다. 서비스 인스턴스가 애플리케이션 논리로 돌아가야 하는 결과를 생성하는 경우 이 정보를 두 구성 요소가 모두 액세스할 수 있는 위치에 저장합니다. 애플리케이션 논리가 불완전한 데이터를 검색하지 못하도록 하려면 처리가 완료될 때 시스템이 표시해야 합니다. 작업자 프로세스는 전용 메시지 회신 큐를 통해 결과를 애플리케이션 논리로 다시 전달할 수 있습니다. 애플리케이션 논리는 이러한 결과를 원래 메시지와 상관시킬 수 있어야 합니다.
메시징 시스템 크기 조정: 대규모 솔루션에서 메시지 볼륨이 높으면 단일 메시지 큐가 과부하가 발생하여 시스템 병목 현상이 발생할 수 있습니다. 이 경우 메시징 시스템을 분할하여 특정 생산자의 메시지를 특정 큐로 보내거나 부하를 분산하여 여러 메시지 큐에 메시지를 분산하는 것이 좋습니다.
메시징 시스템 안정성: 신뢰할 수 있는 메시징 시스템을 사용하여 애플리케이션이 메시지를 큐에 추가한 후 메시지가 손실되지 않도록 보장합니다. 이 기능은 모든 메시지가 한 번 이상 배달되도록 하는 데 필수적입니다.
이 패턴을 사용하는 경우
다음 경우에 이 패턴을 사용합니다.
애플리케이션 워크로드는 비동기적으로 실행할 수 있는 작업으로 나뉩니다.
작업이 독립적이고 동시에 실행할 수 있는 경우
작업 볼륨은 매우 가변적이며 확장 가능한 솔루션이 필요합니다.
솔루션은 고가용성을 제공하고 작업 처리에 실패할 때 복원력을 유지해야 합니다.
이 패턴은 다음과 같은 경우에 적합하지 않을 수 있습니다.
애플리케이션 워크로드를 개별 작업으로 쉽게 구분할 수 없거나 태스크 간에 높은 수준의 의존도가 있습니다.
태스크는 동기적으로 실행되어야 하며, 애플리케이션 논리는 각 작업이 완료될 때까지 기다렸다가 계속 진행해야 합니다.
태스크는 특정 시퀀스에서 실행해야 합니다.
메모
일부 메시징 시스템은 생산자 그룹 메시지를 함께 허용하고 동일한 소비자가 그룹의 모든 메시지를 처리하도록 하는 세션을 지원합니다. 메시지 순서를 적용하고 생산자에서 단일 소비자로 순서대로 메시지를 배달하도록 지원되는 경우 우선 순위가 지정된 메시지와 함께 이 메커니즘을 사용할 수 있습니다.
워크로드 디자인
워크로드 디자인에서 경쟁 소비자 패턴을 사용하여 Azure Well-Architected Framework 핵심 요소에서 다루는 목표와 원칙을 해결하는 방법을 평가합니다. 다음 표에서는 이 패턴이 각 핵심 요소의 목표를 지원하는 방법에 대한 지침을 제공합니다.
| 핵심 요소 | 이 패턴으로 핵심 목표를 지원하는 방법 |
|---|---|
| 안정성 설계 결정을 통해 워크로드가 오작동에 대한 복원력을 높일 수 있으며 오류가 발생한 후 완전히 작동하는 상태로 복구 되도록 할 수 있습니다. | 이 패턴은 소비자를 복제본으로 처리하여 큐 처리에서 중복성을 구축하므로 인스턴스 오류로 인해 다른 소비자가 큐 메시지를 처리하지 못하게 됩니다. - RE:05 중복성 - 백그라운드 작업 |
| 비용 최적화는 워크로드의 투자 수익률을 유지하고 개선하는 데 중점을 둡니다. | 이 패턴은 큐 깊이에 따라 크기가 조정되고 큐가 비어 있을 때 0으로 축소할 수 있으므로 비용을 최적화하는 데 도움이 될 수 있습니다. 최대 동시 소비자 인스턴스 수를 제한할 수 있으므로 비용을 최적화할 수도 있습니다. - CO:05 속도 최적화 - CO:07 구성 요소 비용 |
| 성능 효율성은 크기 조정, 데이터 및 코드의 최적화를 통해 워크로드가 수요를 효율적으로 충족 하는 데 도움이 됩니다. | 이 패턴은 사용률을 높이기 위해 소비자 노드 간에 부하를 분산하고, 큐 깊이를 기반으로 하는 동적 크기 조정은 오버프로비전을 최소화합니다. - PE:05 크기 조정 및 분할 - PE:07 코드 및 인프라 |
이 패턴이 하나의 기둥 내에서 절충을 도입하는 경우, 이를 다른 기둥의 목표와 비교해서 고려해 보세요.
예시
Azure는 이 클라우드 디자인 패턴을 직접 구현하는 Service Bus 큐 및 Azure Functions 큐 트리거를 제공합니다. 함수는 트리거 및 바인딩을 통해 Service Bus와 통합됩니다. 이 통합을 통해 게시자의 큐 메시지를 사용하는 함수를 빌드할 수 있습니다. 애플리케이션은 메시지를 큐에 게시하고, Functions로 구현된 컨슈머는 해당 메시지를 검색하여 처리할 수 있습니다.
복원력을 위해 Service Bus 큐를 사용하면 소비자가 큐에서 메시지를 검색할 때 PeekLock 모드 를 사용할 수 있습니다. 이 모드는 메시지를 유지하지만 다른 소비자로부터 메시지를 숨깁니다. Functions 런타임은 PeekLock 모드에서 메시지를 받습니다. 함수가 성공적으로 완료되면 런타임이 메시지에 대해 Complete를 호출합니다. 함수가 실패하면 다른 소비자가 검색할 수 있도록 런타임에서 메시지를 호출 Abandon 하고 다시 표시할 수 있습니다. 함수가 PeekLock 시간 제한보다 오래 실행되는 경우 함수가 실행되는 한 런타임은 잠금을 자동으로 갱신합니다.
함수는 큐 깊이 및 트래픽에 따라 소비자 인스턴스 수를 자동으로 조정합니다. 이 크기 조정을 통해 솔루션은 적은 볼륨 기간 동안 비용을 최소화하면서 작업의 버스트를 처리할 수 있습니다. Functions가 여러 인스턴스를 만드는 경우 독립적으로 메시지를 끌어와서 처리하여 경쟁합니다. 자세한 내용은 Service Bus 큐, 토픽 및 구독과 Functions용 Service Bus 트리거를 참조하세요.
.NET용 Service Bus 클라이언트 라이브러리를 사용하여 Service Bus 큐에 메시지를 보내는 방법에 대한 자세한 내용은 게시된 예제를 참조하세요.
다음 단계
Azure에서 메시징 서비스 선택: Service Bus, Azure Storage 큐, Azure Event Hubs 및 Azure Event Grid와 같은 다양한 Azure 메시징 서비스가 비동기 통신 패턴을 지원하는 방법과 시나리오에 적합한 서비스 및 메시징 모델을 선택하는 방법을 알아봅니다.
자동 크기 조정 모범 사례: 낮은 작업 기간 동안 최대 부하 및 제어 비용을 처리할 수 있도록 큐 길이 또는 메시지 처리량과 같은 워크로드에 따라 소비자 인스턴스를 스케일 아웃하는 솔루션을 디자인하는 방법을 알아봅니다.
관련 리소스
컴퓨팅 리소스 통합 패턴: 소비자 서비스의 여러 인스턴스를 단일 프로세스로 통합하여 비용 및 관리 오버헤드를 줄일 수 있습니다. 컴퓨팅 리소스 통합 패턴은 이 방법의 이점과 장차를 설명합니다.
큐 기반 부하 평준화 패턴: 메시지 큐는 시스템에 복원력을 추가할 수 있습니다. 복원력을 통해 서비스 인스턴스는 애플리케이션 인스턴스의 다양한 요청 볼륨을 처리할 수 있습니다. 메시지 큐는 부하 수준을 지정하는 버퍼로 작동합니다. 큐 기반 부하 평준화 패턴에서 이 시나리오를 자세히 설명합니다.