Model prioritní fronty

Určuje prioritu požadavků odeslaných službám, aby se požadavky s vyšší prioritou přijímaly a zpracovávaly rychleji než požadavky s nižší prioritou. Tento model je užitečný v aplikacích, které jednotlivým klientům nabízí různé záruky úrovní služeb.

Kontext a problém

Aplikace mohou jiným službám delegovat konkrétní úlohy – například provedení zpracování na pozadí nebo integrování s jinými aplikacemi nebo službami. Fronta zpráv v cloudu se obecně používá k delegování úkolů ke zpracování na pozadí. Ve většině případů není pořadí obdržených žádostí důležité. V některých případech je ale důležité určitým žádostem zvýšit prioritu. Takové požadavky by se měly zpracovat před požadavky s nízkou prioritou, které byly aplikací odeslané dříve.

Řešení

Fronta obvykle používá strukturu FIFO (first-in, first-out) a příjemci obvykle dostávají zprávy ve stejném pořadí, v jakém byly odeslány do fronty. Některé fronty zpráv ale podporují prioritní vyřizování. Aplikace, která zprávu odesílá, může přiřadit prioritu a zprávy ve frontě se automaticky přeuspořádají, aby se ty s vyšší prioritou vyřídily dříve než ty s nižší prioritou. Obrázek znázorňuje frontu s prioritním vyřizováním zpráv.

Obrázek 1 – použití mechanismu řízení front, který podporuje prioritní vyřizování zpráv.

Většina implementací fronty zpráv podporuje více zákazníků (podle modelu konkurenčních příjemců) a počet procesů příjemců je možné na základě poptávky vertikálně navýšit nebo snížit.

U systémů, které fronty s prioritním vyřizováním zpráv nepodporují, je alternativním řešením spravovat samostatnou frontu pro každou prioritu. Aplikace je zodpovědná za odesílání zpráv do příslušné fronty. Každá fronta může mít samostatný fond příjemců. Fronty s vyšší prioritou mohou mít větší fond příjemců běžící na rychlejším hardwaru než fronty s nižší prioritou. Následující obrázek znázorňuje používání samostatné fronty zpráv pro každou prioritu.

Obrázek 2 – používání samostatné fronty zpráv pro každou prioritu

Variantou této strategie je mít jeden fond příjemců, který nejprve zkontroluje zprávy ve frontách s vyšší prioritou a teprve potom začne načítat zprávy z front s nižší prioritou. Mezi řešením, které používá jeden fond procesů příjemců (buď s jednou frontou, která podporuje zprávy s různými prioritami, nebo s více frontami, kdy každá fronta zpracovává zprávy s jednou prioritou), a řešením, které používá více front s odděleným fondem pro každou frontu, jsou menší významové rozdíly.

U přístupu s jedním fondem se zprávy s vyšší prioritou vždy přijímají a zpracovávají před zprávami s nižší prioritou. Teoreticky by zprávy s velmi nízkou prioritou mohly být neustále nahrazované a nikdo by je nikdy nezpracoval. U přístupu s více fondy budou zprávy s nízkou prioritou vždy zpracovány, jen to nebude tak rychlé jako u zpráv s vyšší prioritou (rychlost závisí na relativní velikosti fondů a dostupných prostředcích).

Použití mechanismu prioritního řízení front může poskytnout následující výhody:

  • Umožňuje aplikacím splňovat obchodní požadavky, které vyžadují prioritizování dostupnosti nebo výkonu – například nabídnutí různých úrovní služby určitým skupinám zákazníků.

  • Může pomoct minimalizovat provozní náklady. U přístupu s jednou frontou můžete v případě potřeby vertikálně snížit kapacitu počtu zákazníků. Zprávy s vysokou prioritou se budou stále zpracovávat jako první (i když možná pomaleji) a zprávy s nižší prioritou mohou mít větší zpoždění. Pokud jste implementovali přístup s více frontami zpráv a oddělenými fondy příjemců pro každou frontu, můžete fond příjemců pro fronty s nižší prioritou zmenšit nebo dokonce pozastavit zpracování některých front s velmi nízkou prioritou tak, že zastavíte všechny příjemce, kteří naslouchají zprávám v těchto frontách.

  • Přístup s více frontami zpráv může díky rozdělení zpráv podle požadavků na zpracování pomoct maximalizovat výkon a škálovatelnost aplikace. Důležité úlohy mohou mít například vyšší prioritu, aby je spuštěné přijímače zpracovaly okamžitě, a méně důležité úlohy na pozadí mohou zpracovat přijímače, které podle plánu poběží v méně vytížené době.

Problémy a důležité informace

Když se budete rozhodovat, jak tento model implementovat, měli byste vzít v úvahu následující skutečnosti:

Priority definujte v kontextu řešení. Vysoká priorita může například znamenat, že zprávy by se měly zpracovat během deseti sekund. Identifikujte požadavky na zpracování položek s vysokou prioritou a ostatní prostředky, které je potřeba přidělit, aby tato kritéria splňovaly.

Rozhodněte se, zda je nutné všechny položky s vysokou prioritou zpracovat před ostatními položkami s nižší prioritou. Pokud zprávy zpracovává jeden fond příjemců, musíte použít mechanismus, který může spuštění úlohy, která vyřizuje zprávy s nízkou prioritou, zabránit nebo takovou úlohu pozastavit, když se objeví zpráva s vyšší prioritou.

Když používáte u přístupu s více frontami jeden fond procesu příjemců, který poslouchá všechny fronty, a nemáte fond příjemců pro každou frontu, příjemce musí použít algoritmus, který zajistí, že zprávy z front s vyšší prioritou budou vyřízeny před zprávami z front s nižší prioritou.

Monitorujte rychlost zpracování u front s vysokou i nízkou prioritou, abyste se ujistili, že se zprávy v těchto frontách zpracovávají podle očekávání.

Pokud potřebujete zajistit zpracování zpráv s nízkou prioritou, musíte implementovat přístup s více frontami zpráv a více fondy příjemců. Další možností je u fronty, která podporuje prioritní vyřizování zpráv, dynamicky prioritu zvyšovat podle stáří zprávy ve frontě. Tento přístup ale závisí na frontě zpráv, která tuto funkci poskytuje.

Použití samostatné fronty pro každou prioritu zprávy funguje nejlépe u systémů, které mají malý počet dobře definovaných priorit.

Priority zpráv může logicky určit systém. Například místo zpráv s vysokou a nízkou prioritou by mohl systém používat zprávy pro „platícího zákazníka“ nebo „neplatícího zákazníka“. V závislosti na vašem obchodním modelu může systém přidělit více prostředků na zpracovávání zpráv od platících zákazníků raději než od těch neplatících.

Zjišťování zprávy ve frontě může souviset s vyššími finančními náklady a náklady na zpracování (některé komerční systémy pro zasílání zpráv si účtují malý poplatek za každé odeslání nebo přijetí zprávy a za každý dotaz na zprávy ve frontě). Při kontrolování více front tyto náklady narůstají.

Velikost fondu příjemců je možné upravit dynamicky na základě délky fronty, kterou fond obsluhuje. Další informace najdete v pokynech k automatickému škálování.

Kdy se má tento model použít

Tento model je vhodný pro následující scénáře:

  • Systém musí zpracovat více úloh, které mají různé priority.

  • Různí uživatelé nebo tenanti by měli mít rozdílnou prioritu.

Příklad

Microsoft Azure neposkytuje mechanismus řízení front, který nativně podporuje automatické určování priority zpráv prostřednictvím řazení. Poskytuje ale témata a odběry Azure Service Bus, které podporují mechanismus řízení front a poskytují filtrování zpráv a širokou škálu flexibilních možností, díky kterým jsou vhodné pro použití ve většině implementací prioritního řízení fronty.

Řešení Azure může implementovat téma služby Service Bus, do kterého může aplikace odesílat zprávy stejně jako do fronty. Zprávy mohou obsahovat metadata ve formě vlastních vlastností definovaných aplikací. Odběry Service Bus umí filtrovat zprávy na základě jejich vlastností a je možné je přidružit k tématům. Když aplikace odešle zprávu do tématu, zpráva se přesměruje do příslušného odběru, kde si ji příjemce může přečíst. Procesy příjemců mohou přijímat zprávy z odběru pomocí stejné sémantiky, jako používá fronta zpráv (odběr je logickou frontou). Následující obrázek znázorňuje implementaci prioritní fronty pomocí témat a odběrů Azure Service Bus.

Obrázek 3 – implementace prioritní fronty pomocí témat a odběrů Azure Service Bus

Ve výše uvedeném obrázku aplikace vytvoří několik zpráv a každé z nich přiřadí vlastní vlastnost pojmenovanou Priority s hodnotou buď High, nebo Low. Aplikace tyto zprávy odešle do tématu. Téma má dva přidružené odběry, které filtrují zprávy podle vlastnosti Priority. Jeden odběr přijímá zprávy s hodnotou vlastnosti Priority nastavenou na High a druhý odběr přijímá zprávy s hodnotou vlastnosti Priority nastavenou na Low. Fond příjemců čte zprávy z každého odběru. Odběr s vysokou prioritou má větší fond a tito příjemci mohou běžet na výkonnějších počítačích a mít k dispozici více prostředků než příjemci ve fondu s nízkou prioritou.

Všimněte si, že v tomto příkladu není na označení zpráv s vysokou a nízkou prioritou nic zvláštního. Jsou to obyčejné popisky zadané jako vlastnosti každé zprávy, které se používají ke směrování zpráv do konkrétního odběru. Pokud potřebujete další priority, je poměrně snadné vytvořit další odběry a fondy procesů příjemců, které tyto priority zpracují.

Řešení PriorityQueue, které je k dispozici na GitHubu, obsahuje implementaci tohoto přístupu. Toto řešení obsahuje dva projekty role pracovního procesu pojmenované PriorityQueue.High a PriorityQueue.Low. Tyto role pracovního procesu dědí z třídy PriorityWorkerRole funkci pro připojení k určenému odběru v metodě OnStart.

Role pracovního procesu PriorityQueue.High a PriorityQueue.Low se na základě svých nastavení konfigurace připojují k různým odběrům. Správce může nakonfigurovat různý počet rolí, které se mají spustit. Obvykle bude existovat více instancí role pracovního procesu PriorityQueue.High než role PriorityQueue.Low.

Metoda Run ve třídě PriorityWorkerRole zajišťuje spouštění virtuální metody ProcessMessage (také definované ve třídě PriorityWorkerRole) u každé zprávy přijaté do fronty. Následující kód ukazuje metody Run a ProcessMessage. Třída QueueManager, definovaná v projektu PriorityQueue.Shared, poskytuje pomocné metody pro používání front Azure Service Bus.

public class PriorityWorkerRole : RoleEntryPoint
{
  private QueueManager queueManager;
  ...

  public override void Run()
  {
    // Start listening for messages on the subscription.
    var subscriptionName = CloudConfigurationManager.GetSetting("SubscriptionName");
    this.queueManager.ReceiveMessages(subscriptionName, this.ProcessMessage);
    ...;
  }
  ...

  protected virtual async Task ProcessMessage(BrokeredMessage message)
  {
    // Simulating processing.
    await Task.Delay(TimeSpan.FromSeconds(2));
  }
}

Obě role pracovního procesu (PriorityQueue.High a PriorityQueue.Low) přepisují výchozí funkci metody ProcessMessage. Níže uvedený kód ukazuje metodu ProcessMessage pro roli pracovního procesu PriorityQueue.High.

protected override async Task ProcessMessage(BrokeredMessage message)
{
  // Simulate message processing for High priority messages.
  await base.ProcessMessage(message);
  Trace.TraceInformation("High priority message processed by " +
    RoleEnvironment.CurrentRoleInstance.Id + " MessageId: " + message.MessageId);
}

Jak je vidět v následujícím příkladu kódu, když aplikace odešle zprávy do tématu, ke kterému jsou přidružené odběry používané rolemi pracovního procesu PriorityQueue.High a PriorityQueue.Low, určuje se priorita použitím vlastní vlastnosti Priority. Tento kód (implementovaný do třídy WorkerRole v projektu PriorityQueue.Sender) používá pomocnou metodu SendBatchAsync ze třídy QueueManager, aby zprávy do tématu odesílal v dávkách.

// Send a low priority batch.
var lowMessages = new List<BrokeredMessage>();

for (int i = 0; i < 10; i++)
{
  var message = new BrokeredMessage() { MessageId = Guid.NewGuid().ToString() };
  message.Properties["Priority"] = Priority.Low;
  lowMessages.Add(message);
}

this.queueManager.SendBatchAsync(lowMessages).Wait();
...

// Send a high priority batch.
var highMessages = new List<BrokeredMessage>();

for (int i = 0; i < 10; i++)
{
  var message = new BrokeredMessage() { MessageId = Guid.NewGuid().ToString() };
  message.Properties["Priority"] = Priority.High;
  highMessages.Add(message);
}

this.queueManager.SendBatchAsync(highMessages).Wait();

Další kroky

Při implementaci tohoto modelu můžou být relevantní také následující pokyny:

  • Ukázka, která tento model předvádí, je k dispozici na GitHubu.

  • Úvod k asynchronnímu zasílání zpráv: Služba příjemce, která zpracovává žádost, může potřebovat odeslat odpověď do instance aplikace, která žádost odeslala. Poskytuje informace o strategiích, které můžete použít k implementaci zasílání žádosti/odpovědi.

  • Pokyny pro automatické škálování. Velikost fondu procesů příjemců, který zpracovává frontu podle její délky, je možné škálovat. Tato strategie může zlepšit výkon, což platí zejména pro fondy zpracovávající zprávy s vysokou prioritou.

Při implementaci tohoto modelu můžou být relevantní také následující vzory:

  • Model konkurenčních spotřebitelů: Pokud chcete zvýšit propustnost front, můžete mít více příjemců, kteří poslouchají stejnou frontu, a zpracovávat úlohy paralelně. Tito příjemci spolu budou soutěžit o zprávy, ale každou zprávu by měl zpracovat pouze jeden z nich. Poskytuje další informace o výhodách a nevýhodách implementace tohoto přístupu.

  • Model omezení využití sítě. Omezení využití sítě můžete implementovat použitím front. Můžete použít prioritní vyřizování zpráv, abyste zajistili, že žádosti z důležitých aplikací nebo aplikací spuštěných důležitými zákazníky budou mít vyšší prioritu než žádosti z méně důležitých aplikací.

  • Enterprise a integrace Service Bus na blogu Abhisheka Lal.