우선 순위 큐 패턴

Azure Service Bus

우선 순위가 높은 요청을 우선 순위가 낮은 요청보다 먼저 받아서 처리하도록 서비스로 전송된 요청의 우선 순위를 지정합니다. 이 패턴은 개별 클라이언트에 서로 다른 서비스 수준 보장을 제공하는 애플리케이션에서 유용합니다.

컨텍스트 및 문제점

애플리케이션은 백그라운드 처리를 수행하거나 다른 애플리케이션 또는 서비스와 통합하기 위해 특정 작업을 다른 서비스에 위임할 수 있습니다. 클라우드에서 메시지 큐는 일반적으로 백그라운드 처리에 작업을 위임하는 데 사용됩니다. 대부분의 경우 서비스에서 요청을 받는 순서는 중요하지 않습니다. 그러나 경우에 따라 특정 요청의 우선 순위를 지정해야 합니다. 이러한 요청은 이전에 애플리케이션에서 보낸 낮은 우선 순위 요청보다 일찍 처리해야 합니다.

솔루션

큐는 일반적으로 FIFO(선결제) 구조이며, 소비자는 일반적으로 큐에 게시되는 순서와 동일한 순서로 메시지를 받습니다. 그러나 일부 메시지 큐는 우선 순위 메시징을 지원합니다. 메시지를 게시하는 애플리케이션은 우선 순위를 할당할 수 있습니다. 우선 순위가 더 높은 메시지는 우선 순위가 낮은 메시지보다 우선 순위가 높은 메시지를 받도록 큐의 메시지가 자동으로 다시 정렬됩니다. 이 다이어그램은 다음 프로세스를 보여 줍니다.

메시지 우선 순위를 지원하는 큐 메커니즘을 보여 주는 다이어그램

참고 항목

대부분의 메시지 큐 구현은 여러 소비자를 지원합니다. (다음을 참조하세요. 경쟁 소비자 패턴입니다.) 수요에 따라 소비자 프로세스 수를 확장 및 축소할 수 있습니다.

우선 순위 기반 메시지 큐를 지원하지 않는 시스템에서 대안은 각 우선 순위에 대해 별도의 큐를 기본 하는 것입니다. 애플리케이션은 적절한 큐에 메시지를 게시할 책임이 있습니다. 각 큐에는 별도의 소비자 풀이 있을 수 있습니다. 우선 순위가 높은 큐는 우선 순위가 낮은 큐보다 더 빠른 하드웨어에서 실행되는 더 큰 소비자 풀을 가질 수 있습니다. 이 다이어그램은 각 우선 순위에 대해 별도의 메시지 큐를 사용하는 방법을 보여 줍니다.

각 우선 순위에 대해 별도의 메시지 큐를 사용하는 방법을 보여 주는 다이어그램

이 전략의 변형은 우선 순위가 높은 큐의 메시지에 대해 먼저 검사 단일 소비자 풀을 구현하고 우선 순위가 낮은 큐에서 메시지를 가져오기 시작한 후에만 구현하는 것입니다. 단일 소비자 프로세스 풀을 사용하는 솔루션(우선 순위가 다른 메시지를 지원하는 단일 큐 또는 각 우선 순위의 메시지를 처리하는 여러 큐가 있는 경우) 솔루션과 각 큐에 대해 별도의 풀이 있는 여러 큐를 사용하는 솔루션 간에는 몇 가지 의미 체계 차이가 있습니다.

단일 풀 접근 방식에서 우선 순위가 높은 메시지는 우선 순위가 낮은 메시지보다 항상 수신되고 처리됩니다. 이론적으로 우선 순위가 낮은 메시지는 지속적으로 대체될 수 있으며 처리되지 않을 수 있습니다. 여러 풀 접근 방식에서 우선 순위가 낮은 메시지는 항상 처리되지만 우선 순위가 높은 메시지만큼 빠르지는 않습니다(풀의 상대적 크기와 사용할 수 있는 리소스에 따라 다름).

우선 순위 큐 메커니즘을 사용하면 다음과 같은 이점이 있습니다.

  • 이를 통해 애플리케이션은 다양한 고객 그룹에 다양한 수준의 서비스를 제공하는 등 가용성 또는 성능의 우선 순위를 지정해야 하는 비즈니스 요구 사항을 충족할 수 있습니다.

  • 운영 비용을 최소화하는 데 도움이 될 수 있습니다. 단일 큐 방법을 사용하는 경우 필요한 경우 소비자 수를 축소할 수 있습니다. 우선 순위가 높은 메시지는 여전히 먼저 처리되며(더 느리게 처리될 수 있음), 우선 순위가 낮은 메시지는 더 오래 지연될 수 있습니다. 각 큐에 대해 별도의 소비자 풀을 사용하여 여러 메시지 큐 접근 방식을 구현하는 경우 우선 순위가 낮은 큐에 대한 소비자 풀을 줄일 수 있습니다. 해당 큐에서 메시지를 수신 대기하는 모든 소비자를 중지하여 우선 순위가 매우 낮은 큐에 대한 처리를 일시 중단할 수도 있습니다.

  • 여러 메시지 큐 접근 방식을 사용하면 처리 요구 사항에 따라 메시지를 분할하여 애플리케이션 성능 및 확장성을 극대화할 수 있습니다. 예를 들어 중요한 작업의 우선 순위를 지정하여 즉시 실행되는 수신기에서 처리하고 덜 바쁜 시간에 실행되도록 예약된 수신기에서 덜 중요한 백그라운드 작업을 처리할 수 있습니다.

고려 사항

이 패턴을 구현하는 방법을 결정할 때 다음 사항을 고려합니다.

  • 솔루션 컨텍스트에서 우선 순위를 정의합니다. 예를 들어 우선 순위높은 메시지를 10초 이내에 처리해야 하는 메시지로 정의할 수 있습니다. 우선 순위가 높은 항목을 처리하기 위한 요구 사항과 조건을 충족하기 위해 할당해야 하는 리소스를 식별합니다.

  • 우선 순위가 높은 모든 항목을 우선 순위가 낮은 항목보다 먼저 처리해야 하는지 여부를 결정합니다. 단일 소비자 풀에서 메시지를 처리하는 경우 우선 순위가 높은 메시지가 큐에 들어오는 경우 우선 순위가 낮은 메시지를 처리하는 작업을 선점하고 일시 중단할 수 있는 메커니즘을 제공해야 합니다.

  • 여러 큐 접근 방식에서 각 큐에 대한 전용 소비자 풀이 아닌 모든 큐에서 수신 대기하는 단일 소비자 프로세스 풀을 사용하는 경우 소비자는 우선 순위가 낮은 큐의 메시지보다 우선 순위가 높은 큐의 메시지를 항상 서비스하도록 하는 알고리즘을 적용해야 합니다.

  • 우선 순위가 높고 낮은 큐에서 처리 속도를 모니터링하여 해당 큐의 메시지가 예상 속도로 처리되는지 확인합니다.

  • 우선 순위가 낮은 메시지가 처리되도록 보장해야 하는 경우 여러 소비자 풀을 사용하여 여러 메시지 큐 접근 방식을 구현합니다. 또는 메시지 우선 순위를 지원하는 큐에서 대기 중인 메시지의 우선 순위가 오래되면 동적으로 늘릴 수 있습니다. 그러나 이 방식은 이 기능을 제공하는 메시지 큐에 따라 달라집니다.

  • 메시지 우선 순위에 따라 별도의 큐를 사용하는 전략은 몇 가지 잘 정의된 우선 순위가 있는 시스템에 권장됩니다.

  • 시스템은 메시지 우선 순위를 논리적으로 결정할 수 있습니다. 예를 들어 명시적으로 높은 우선 순위 및 낮은 우선 순위 메시지를 갖는 대신 메시지를 "유료 고객" 또는 "비지불 고객"으로 지정할 수 있습니다. 그러면 시스템에서 유료 고객의 메시지를 처리하는 데 더 많은 리소스를 할당할 수 있습니다.

  • 메시지에 대한 큐를 검사 것과 관련된 재무 및 처리 비용이 있을 수 있습니다. 예를 들어 일부 상용 메시징 시스템은 메시지를 게시하거나 검색할 때마다, 그리고 큐에서 메시지를 쿼리할 때마다 약간의 요금을 부과합니다. 이 비용은 여러 큐를 검사 때 증가합니다.

  • 풀이 서비스 중인 큐의 길이에 따라 소비자 풀의 크기를 동적으로 조정할 수 있습니다. 자세한 내용은 자동 크기 조정 지침을 참조하세요.

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

이 패턴은 다음과 같은 시나리오에서 유용합니다.

  • 시스템은 우선 순위가 다른 여러 작업을 처리해야 합니다.

  • 다른 사용자 또는 테넌트는 서로 다른 우선 순위로 제공되어야 합니다.

워크로드 디자인

설계자는 워크로드 디자인에서 우선 순위 큐 패턴을 사용하여 Azure 잘 설계된 프레임워크 핵심 요소에서 다루는 목표와 원칙을 해결하는 방법을 평가해야 합니다. 예시:

핵심 요소 이 패턴이 핵심 목표를 지원하는 방법
안정성 디자인 결정은 워크로드가 오작동에 대한 복원력을 갖도록 하고 오류가 발생한 후 완전히 작동하는 상태로 복구 되도록 하는 데 도움이 됩니다. 비즈니스 우선 순위에 따라 항목을 분리하면 가장 중요한 작업에 안정성 노력을 집중할 수 있습니다.

- RE:02 중요 흐름
- RE:07 백그라운드 작업
성능 효율성은 크기 조정, 데이터, 코드의 최적화를 통해 워크로드가 수요를 효율적으로 충족하는 데 도움이 됩니다. 비즈니스 우선 순위에 따라 항목을 분리하면 가장 시간이 중요한 작업에 성능 노력을 집중할 수 있습니다.

- PE:09 중요 흐름

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

예시

Azure는 정렬을 통해 메시지의 자동 우선 순위를 기본적으로 지원하는 큐 메커니즘을 제공하지 않습니다. 그러나 Azure Service Bus 토픽, 메시지 필터링을 제공하는 큐 메커니즘을 지원하는 Service Bus 구독 및 Azure를 대부분의 우선 순위 큐 구현에 적합하게 만드는 다양한 유연한 기능을 제공합니다.

Azure 솔루션은 애플리케이션이 메시지를 큐에 게시하는 것처럼 메시지를 게시할 수 있는 Service Bus 토픽을 구현할 수 있습니다. 메시지에는 애플리케이션에서 정의한 사용자 지정 속성 형식의 메타데이터가 포함될 수 있습니다. Service Bus 구독을 토픽과 연결할 수 있으며 구독은 해당 속성에 따라 메시지를 필터링할 수 있습니다. 애플리케이션이 토픽에 메시지를 보내면 메시지가 소비자가 읽을 수 있는 적절한 구독으로 전달됩니다. 소비자 프로세스는 메시지 큐와 함께 사용하는 것과 동일한 의미 체계를 사용하여 구독에서 메시지를 검색할 수 있습니다. (구독은 논리적 큐입니다.) 이 다이어그램에서는 Service Bus 토픽 및 구독을 사용하여 우선 순위 큐를 구현하는 방법을 보여 줍니다.

Service Bus 토픽 및 구독을 사용하여 우선 순위 큐를 구현하는 방법을 보여 주는 다이어그램

이전 다이어그램에서 애플리케이션은 여러 메시지를 만들고 각 메시지에서 호출 Priority 된 사용자 지정 속성을 할당합니다. Priority의 값 High 이 있습니다.Low 애플리케이션은 이러한 메시지를 토픽에 게시합니다. 이 항목에는 속성에 따라 메시지를 필터링하는 두 개의 연결된 구독이 있습니다 Priority . 한 구독은 속성이 Priority .로 설정된 메시지를 수락합니다 High. 다른 하나는 속성이 .로 Priority 설정된 메시지를 허용합니다 Low. 소비자 풀은 각 구독에서 메시지를 읽습니다. 우선 순위가 높은 구독에는 더 큰 풀이 있으며, 이러한 소비자는 우선 순위가 낮은 풀의 컴퓨터보다 사용 가능한 리소스가 더 많은 더 강력한 컴퓨터에서 실행될 수 있습니다.

이 예제에서는 우선 순위가 높고 낮은 메시지를 지정하는 데 특별한 것은 없습니다. 각 메시지의 속성으로 지정된 레이블일 뿐입니다. 특정 구독으로 메시지를 보내는 데 사용됩니다. 추가 우선 순위가 필요한 경우 이러한 우선 순위를 처리하기 위해 더 많은 구독 및 소비자 프로세스 풀을 비교적 쉽게 만들 수 있습니다.

GitHub의 PriorityQueue 솔루션은 이 방법을 기반으로 합니다. 이 솔루션에는 PriorityQueueConsumerHighPriorityQueueConsumerLow라는 이름의 Azure Function 프로젝트가 포함됩니다. 이러한 Azure Function 프로젝트는 트리거 및 바인딩을 통해 Service Bus와 통합됩니다. 정의된 다른 구독에 ServiceBusTrigger 연결하고 들어오는 메시지에 반응합니다.

public static class PriorityQueueConsumerHighFn
{
    [FunctionName("HighPriorityQueueConsumerFunction")]
    public static void Run(
      [ServiceBusTrigger("messages", "highPriority", Connection = "ServiceBusConnection")]string highPriorityMessage,
      ILogger log)
    {
        log.LogInformation($"C# ServiceBus topic trigger function processed message: {highPriorityMessage}");
    }
}

관리자는 Azure 앱 Service의 함수를 확장할 수 있는 인스턴스 수를 구성할 수 있습니다. Azure Portal에서 Scale Out 제한 적용 옵션을 구성하고 각 함수에 대한 최대 스케일 아웃 제한을 설정하여 이 작업을 수행할 수 있습니다. 일반적으로 함수의 인스턴스가 PriorityQueueConsumerHigh 함수보다 PriorityQueueConsumerLow 더 많이 있어야 합니다. 이 구성을 사용하면 우선 순위가 높은 메시지를 낮은 우선 순위 메시지보다 더 빨리 큐에서 읽을 수 있습니다.

또 다른 프로젝트에는 PriorityQueueSender30초마다 실행되도록 구성된 시간 트리거 Azure 함수가 포함되어 있습니다. 이 함수는 출력 바인딩을 통해 Service Bus와 통합되고 우선 순위가 낮은 메시지와 높은 우선 순위 메시지의 일괄 처리를 개체에 IAsyncCollector 보냅니다. 함수가 및 함수에서 사용하는 구독과 연결된 토픽에 PriorityQueueConsumerHighPriorityQueueConsumerLow 메시지를 게시하는 경우 다음과 같이 사용자 지정 속성을 사용하여 Priority 우선 순위를 지정합니다.

public static class PriorityQueueSenderFn
{
    [FunctionName("PriorityQueueSenderFunction")]
    public static async Task Run(
        [TimerTrigger("0,30 * * * * *")] TimerInfo myTimer,
        [ServiceBus("messages", Connection = "ServiceBusConnection")] IAsyncCollector<ServiceBusMessage> collector)
    {
        for (int i = 0; i < 10; i++)
        {
            var messageId = Guid.NewGuid().ToString();
            var lpMessage = new ServiceBusMessage() { MessageId = messageId };
            lpMessage.ApplicationProperties["Priority"] = Priority.Low;
            lpMessage.Body = BinaryData.FromString($"Low priority message with Id: {messageId}");
            await collector.AddAsync(lpMessage);

            messageId = Guid.NewGuid().ToString();
            var hpMessage = new ServiceBusMessage() { MessageId = messageId };
            hpMessage.ApplicationProperties["Priority"] = Priority.High;
            hpMessage.Body = BinaryData.FromString($"High priority message with Id: {messageId}");
            await collector.AddAsync(hpMessage);
        }
    }
}

다음 단계

다음 리소스는 이 패턴을 구현할 때 유용할 수 있습니다.

  • GitHub에서 이 패턴을 보여 주는 샘플입니다.

  • 비동기 메시징 입문서입니다. 요청을 처리하는 소비자 서비스에서 해당 요청을 게시한 애플리케이션의 인스턴스에 응답을 보내야 할 수도 있습니다. 이 문서에서는 요청/응답 메시징을 구현하는 데 사용할 수 있는 전략에 대한 정보를 제공합니다.

  • 자동 크기 조정 지침입니다. 경우에 따라 큐의 길이에 따라 큐를 처리하는 소비자 프로세스 풀의 크기를 조정할 수 있습니다. 이 전략은 특히 우선 순위가 높은 메시지를 처리하는 풀의 성능을 향상시키는 데 도움이 될 수 있습니다.

다음 패턴은 이 패턴을 구현할 때 유용할 수 있습니다.

  • 경쟁 소비자 패턴 큐의 처리량을 늘리려면 동일한 큐에서 수신 대기하고 작업을 병렬로 처리하는 여러 소비자를 구현할 수 있습니다. 이러한 소비자는 메시지를 위해 경쟁하지만 각 메시지를 하나만 처리할 수 있어야 합니다. 이 문서에서는 이 방법을 구현할 때의 이점과 단점에 대해 자세히 설명합니다.

  • 제한 패턴. 큐를 사용하여 제한을 구현할 수 있습니다. 우선 순위 메시징을 사용하여 중요한 애플리케이션 또는 높은 가치의 고객이 실행하는 애플리케이션의 요청이 덜 중요한 애플리케이션의 요청보다 우선 순위가 부여되도록 할 수 있습니다.