Patroon voor wachtrij met prioriteit

Azure Service Bus

Prioriteit geven aan aanvragen die worden verzonden naar services, zodat aanvragen met een hogere prioriteit sneller worden ontvangen en verwerkt dan aanvragen met een lagere prioriteit. Dit patroon is nuttig voor toepassingen die verschillende garanties voor serviceniveau bieden voor verschillende klanten.

Context en probleem

Toepassingen kunnen specifieke taken delegeren naar andere services, bijvoorbeeld voor verwerking op de achtergrond of integratie met andere toepassingen of services. In de cloud wordt doorgaans een berichtenwachtrij gebruikt om taken te delegeren voor verwerking op de achtergrond. In veel gevallen is de volgorde waarin aanvragen worden ontvangen door een service niet belangrijk. In sommige gevallen kan het echter nodig zijn bepaalde aanvragen prioriteit te geven. Deze aanvragen moeten eerder worden verwerkt dan aanvragen met een lagere prioriteit die eerder door de toepassing zijn verzonden.

Oplossing

Een wachtrij is meestal een FIFO-structuur (first-in, first-out) en consumenten ontvangen meestal berichten in dezelfde volgorde als ze in de wachtrij worden geplaatst. Sommige berichtenwachtrijen ondersteunen echter berichten met prioriteit. De toepassing die een bericht plaatst, kan een prioriteit toewijzen. De berichten in de wachtrij worden automatisch opnieuw gerangschikt, zodat berichten met een hogere prioriteit worden ontvangen voor berichten met een lagere prioriteit. Dit diagram illustreert het proces:

Diagram dat een wachtrijmechanisme illustreert dat ondersteuning biedt voor prioriteitstelling van berichten.

Notitie

De meeste implementaties van berichtenwachtrijen ondersteunen meerdere consumenten. (Zie de Patroon concurrerende consumenten.) Het aantal consumentenprocessen kan omhoog en omlaag worden geschaald op basis van de vraag.

In systemen die geen berichtenwachtrijen op basis van prioriteit ondersteunen, bestaat een alternatieve oplossing eruit een afzonderlijke wachtrij te gebruiken voor elke prioriteit. De toepassing is ervoor verantwoordelijk berichten in de juiste wachtrij te plaatsen. Elke wachtrij kan een afzonderlijke groep consumenten hebben. Wachtrijen met een hogere prioriteit kunnen een grotere groep consumenten hebben die worden uitgevoerd op snellere hardware dan wachtrijen met lagere prioriteit. In dit diagram ziet u het gebruik van afzonderlijke berichtenwachtrijen voor elke prioriteit:

Diagram dat het gebruik van afzonderlijke berichtenwachtrijen voor elke prioriteit illustreert.

Een variant op deze strategie is het implementeren van één groep consumenten die eerst controleren op berichten in wachtrijen met hoge prioriteit en pas daarna berichten ophalen uit wachtrijen met een lagere prioriteit. Er zijn enkele semantische verschillen tussen een oplossing die gebruikmaakt van één groep consumentenprocessen (met één wachtrij die berichten ondersteunt die verschillende prioriteiten hebben of met meerdere wachtrijen die elk berichten met één prioriteit verwerken) en een oplossing die meerdere wachtrijen met een afzonderlijke groep voor elke wachtrij gebruikt.

In de benadering met één groep worden berichten met een hogere prioriteit altijd ontvangen en verwerkt voor berichten met een lagere prioriteit. In theorie kunnen berichten met een lage prioriteit voortdurend worden vervangen en kunnen ze nooit worden verwerkt. In de benadering met meerdere groepen worden berichten met een lagere prioriteit altijd verwerkt, maar niet zo snel als berichten met een hogere prioriteit (afhankelijk van de relatieve grootte van de pools en de resources die voor hen beschikbaar zijn).

Het gebruik van een wachtrijmechanisme met prioriteit kan de volgende voordelen bieden:

  • Hiermee kunnen toepassingen voldoen aan bedrijfsvereisten waarvoor de prioriteitstelling van beschikbaarheid of prestaties is vereist, zoals het aanbieden van verschillende serviceniveaus aan verschillende groepen klanten.

  • Het kan helpen de operationele kosten tot het minimum te beperken. Als u de benadering met één wachtrij gebruikt, kunt u het aantal consumenten terugschalen als dat nodig is. Berichten met een hoge prioriteit worden nog steeds eerst verwerkt (hoewel mogelijk langzamer) en berichten met een lagere prioriteit kunnen langer worden uitgesteld. Als u de benadering voor meerdere berichtenwachtrijen implementeert met afzonderlijke groepen consumenten voor elke wachtrij, kunt u de groep consumenten verminderen voor wachtrijen met lagere prioriteit. U kunt zelfs de verwerking voor een aantal wachtrijen met een zeer lage prioriteit onderbreken door alle gebruikers te stoppen die luisteren naar berichten in die wachtrijen.

  • De benadering met meerdere berichtenwachtrijen kan u helpen de prestaties en schaalbaarheid van de toepassing te optimaliseren door berichten te partitioneren op basis van verwerkingsvereisten. U kunt bijvoorbeeld prioriteit geven aan kritieke taken, zodat ze worden verwerkt door ontvangers die onmiddellijk worden uitgevoerd, en minder belangrijke achtergrondtaken kunnen worden verwerkt door ontvangers die zijn gepland om te worden uitgevoerd op tijdstippen die minder druk zijn.

Overwegingen

Houd rekening met de volgende punten wanneer u besluit hoe u dit patroon implementeert:

  • Definieer de prioriteiten in de context van de oplossing. Een bericht met hoge prioriteit kan bijvoorbeeld worden gedefinieerd als een bericht dat binnen 10 seconden moet worden verwerkt. Identificeer de vereisten voor het verwerken van items met hoge prioriteit en de resources die moeten worden toegewezen om aan uw criteria te voldoen.

  • Bepaal of alle items met hoge prioriteit moeten worden verwerkt voor items met een lagere prioriteit. Als de berichten door één groep consumenten worden verwerkt, moet u een mechanisme opgeven dat een taak die een bericht met lage prioriteit verwerkt, kan voorbereiden en onderbreken als een bericht met een hogere prioriteit in de wachtrij komt.

  • Wanneer u in de benadering met meerdere wachtrijen één groep consumentenprocessen gebruikt die luisteren naar alle wachtrijen in plaats van een toegewezen consumentengroep voor elke wachtrij, moet de consument een algoritme toepassen dat ervoor zorgt dat berichten van wachtrijen met een hogere prioriteit altijd worden verwerkt voordat berichten uit wachtrijen met lagere prioriteit worden verzonden.

  • Bewaak de verwerkingssnelheid voor wachtrijen met hoge en lage prioriteit om ervoor te zorgen dat berichten in die wachtrijen worden verwerkt tegen de verwachte tarieven.

  • Als u wilt garanderen dat berichten met een lage prioriteit worden verwerkt, implementeert u de benadering van meerdere berichtenwachtrijen met meerdere groepen consumenten. U kunt ook in een wachtrij die prioriteitsaanduiding van berichten ondersteunt, de prioriteit van een bericht in de wachtrij dynamisch verhogen naarmate het ouder wordt. Deze benadering is echter afhankelijk van de berichtenwachtrij die deze functie moet bieden.

  • De strategie voor het gebruik van afzonderlijke wachtrijen op basis van berichtprioriteit wordt aanbevolen voor systemen met een aantal goed gedefinieerde prioriteiten.

  • Het systeem kan berichtenprioriteiten logisch bepalen. In plaats van expliciete berichten met hoge en lage prioriteit te hebben, kunt u bijvoorbeeld berichten aanwijzen als 'betalende klant' of 'niet-betalende klant'. Uw systeem kan vervolgens meer resources toewijzen om berichten te verwerken van betalende klanten.

  • Er kunnen financiële kosten en verwerkingskosten zijn gekoppeld aan het controleren van een wachtrij voor een bericht. Sommige commerciële berichtensystemen brengen bijvoorbeeld een kleine vergoeding in rekening telkens wanneer een bericht wordt gepost of opgehaald, en telkens wanneer een wachtrij wordt opgevraagd voor berichten. Deze kosten nemen toe wanneer u meerdere wachtrijen controleert.

  • U kunt de grootte van een groep consumenten dynamisch aanpassen op basis van de lengte van de wachtrij die door de pool wordt onderhouden. Zie Richtlijnen voor automatisch schalen voor meer informatie.

Wanneer dit patroon gebruiken

Dit patroon is bruikbaar voor scenario's waarbij:

  • Het systeem meerdere taken met verschillende prioriteiten moet verwerken.

  • Verschillende gebruikers of tenants moeten worden bediend met verschillende prioriteiten.

Workloadontwerp

Een architect moet evalueren hoe het patroon Prioriteitswachtrij kan worden gebruikt in het ontwerp van hun workload om de doelstellingen en principes te verhelpen die worden behandeld in de pijlers van het Azure Well-Architected Framework. Voorbeeld:

Pijler Hoe dit patroon ondersteuning biedt voor pijlerdoelen
Beslissingen over betrouwbaarheidsontwerp helpen uw workload bestand te worden tegen storingen en ervoor te zorgen dat deze herstelt naar een volledig functionerende status nadat er een fout is opgetreden. Door items te scheiden op basis van bedrijfsprioriteit kunt u de betrouwbaarheidsinspanningen richten op het meest kritieke werk.

- RE:02 Kritieke stromen
- RE:07 Achtergrondtaken
Prestatie-efficiëntie helpt uw workload efficiënt te voldoen aan de vereisten door optimalisaties in schalen, gegevens, code. Door items te scheiden op basis van bedrijfsprioriteit kunt u zich richten op prestatie-inspanningen voor het meest tijdgevoelige werk.

- PE:09 Kritieke stromen

Net als bij elke ontwerpbeslissing moet u rekening houden met eventuele compromissen ten opzichte van de doelstellingen van de andere pijlers die met dit patroon kunnen worden geïntroduceerd.

Opmerking

Azure biedt geen wachtrijmechanisme dat systeemeigen ondersteuning biedt voor automatische prioriteitstelling van berichten via sortering. Het biedt echter Wel Azure Service Bus-onderwerpen, Service Bus-abonnementen die ondersteuning bieden voor een wachtrijmechanisme dat berichtfiltering biedt en een scala aan flexibele mogelijkheden die Azure ideaal maken voor de meeste implementaties van wachtrijen met prioriteit.

Een Azure-oplossing kan een Service Bus-onderwerp implementeren waarnaar een toepassing berichten kan posten, net zoals in een wachtrij. Berichten kunnen metagegevens bevatten in de vorm van door de toepassing gedefinieerde eigenschappen. U kunt Service Bus-abonnementen koppelen aan het onderwerp en de abonnementen kunnen berichten filteren op basis van hun eigenschappen. Wanneer een toepassing een bericht naar een onderwerp verzendt, wordt het bericht omgeleid naar het juiste abonnement, waar een consument het kan lezen. Consumentenprocessen kunnen berichten uit een abonnement ophalen met behulp van dezelfde semantiek die ze zouden gebruiken met een berichtenwachtrij. (Een abonnement is een logische wachtrij.) In dit diagram ziet u hoe u een prioriteitswachtrij implementeert met behulp van Service Bus-onderwerpen en -abonnementen:

Diagram waarin wordt getoond hoe u een prioriteitswachtrij implementeert met behulp van Service Bus-onderwerpen en -abonnementen.

In het voorgaande diagram maakt de toepassing verschillende berichten en wijst een aangepaste eigenschap toe die in elk bericht wordt aangeroepen Priority . Priority heeft een waarde van High of Low. De toepassing plaatst deze berichten in een onderwerp. Het onderwerp heeft twee gekoppelde abonnementen waarmee berichten worden gefilterd op basis van de Priority eigenschap. Eén abonnement accepteert berichten met de Priority eigenschap ingesteld op High. De andere accepteert berichten waarvoor de Priority eigenschap is ingesteld op Low. Een groep consumenten leest berichten van elk abonnement. Het abonnement met hoge prioriteit heeft een grotere groep en deze consumenten worden mogelijk uitgevoerd op krachtigere computers met meer beschikbare resources dan de computers voor de pool met lage prioriteit.

Er is niets bijzonders aan de aanduiding van berichten met een hoge en lage prioriteit in dit voorbeeld. Ze zijn gewoon labels die in elk bericht als eigenschappen zijn opgegeven. Ze worden gebruikt om berichten naar een specifiek abonnement te sturen. Als er extra prioriteiten nodig zijn, is het relatief eenvoudig om meer abonnementen en groepen consumentenprocessen te maken om deze prioriteiten af te handelen.

De PriorityQueue-oplossing op GitHub is gebaseerd op deze benadering. Deze oplossing bevat Azure Function-projecten met de naam PriorityQueueConsumerHigh en PriorityQueueConsumerLow. Deze Azure Function-projecten kunnen worden geïntegreerd met Service Bus via triggers en bindingen. Ze maken verbinding met verschillende abonnementen die zijn gedefinieerd in ServiceBusTrigger en reageren op de binnenkomende berichten.

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}");
    }
}

Als beheerder kunt u configureren naar hoeveel exemplaren de functies op Azure-app Service kunnen worden uitgeschaald. U kunt dit doen door de optie Uitschalingslimiet afdwingen vanuit Azure Portal te configureren en een maximale uitschalingslimiet in te stellen voor elke functie. Doorgaans moet u meer exemplaren van de PriorityQueueConsumerHigh functie hebben dan de PriorityQueueConsumerLow functie. Deze configuratie zorgt ervoor dat berichten met een hoge prioriteit sneller uit de wachtrij worden gelezen dan berichten met een lage prioriteit.

Een ander project, PriorityQueueSenderbevat een door tijd geactiveerde Azure-functie die elke 30 seconden wordt uitgevoerd. Deze functie kan worden geïntegreerd met Service Bus via een uitvoerbinding en verzendt batches met berichten met een lage en hoge prioriteit naar een IAsyncCollector object. Wanneer de functie berichten plaatst in het onderwerp dat is gekoppeld aan de abonnementen die door de PriorityQueueConsumerHigh en PriorityQueueConsumerLow functies worden gebruikt, wordt de prioriteit opgegeven met behulp van de Priority aangepaste eigenschap, zoals hier wordt weergegeven:

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);
        }
    }
}

Volgende stappen

De volgende resources kunnen nuttig zijn voor u wanneer u dit patroon implementeert:

  • Een voorbeeld van dit patroon, op GitHub.

  • Asynchrone berichten primer. Een consumentenservice die een aanvraag verwerkt, moet mogelijk een antwoord sturen naar het exemplaar van de toepassing dat de aanvraag heeft geplaatst. Dit artikel bevat informatie over de strategieën die u kunt gebruiken om aanvraag-/antwoordberichten te implementeren.

  • Richtlijnen voor automatisch schalen. U kunt soms de grootte van de groep consumentenprocessen schalen die een wachtrij verwerken op basis van de lengte van de wachtrij. Deze strategie kan u helpen de prestaties te verbeteren, met name voor pools die berichten met hoge prioriteit verwerken.

De volgende patronen kunnen nuttig zijn voor u wanneer u dit patroon implementeert:

  • Patroon Concurrerende consumenten. Als u de doorvoer van de wachtrijen wilt verhogen, kunt u meerdere consumenten implementeren die parallel luisteren naar dezelfde wachtrij- en procestaken. Deze consumenten concurreren voor berichten, maar slechts één moet elk bericht kunnen verwerken. Dit artikel bevat meer informatie over de voor- en nadelen van het implementeren van deze aanpak.

  • Patroon voor beperking. U kunt aanvraagbeperking implementeren met behulp van wachtrijen. U kunt prioriteitsberichten gebruiken om ervoor te zorgen dat aanvragen van kritieke toepassingen of toepassingen die worden uitgevoerd door klanten met een hoge waarde, prioriteit krijgen ten opzichte van aanvragen van minder belangrijke toepassingen.