Model konkurujících si příjemců

Azure Functions
Azure Service Bus

Umožňuje několika souběžným příjemcům zpracovávat zprávy přijaté ve stejném kanálu pro zasílání zpráv. S více souběžnými příjemci může systém zpracovávat více zpráv současně za účelem optimalizace propustnosti, zlepšení škálovatelnosti a dostupnosti a vyrovnávání zatížení.

Kontext a problém

Očekává se, že aplikace spuštěná v cloudu bude zpracovávat velké množství požadavků. Běžným postupem místo synchronního zpracování každého požadavku je, že aplikace předá požadavky prostřednictvím systému zasílání zpráv jiné službě (službě příjemce), která je zpracuje asynchronně. Tato strategie pomáhá zajistit, aby obchodní logika v aplikaci nebyla blokována, zatímco se požadavky zpracovávají.

Počet požadavků se může v průběhu času z mnoha důvodů výrazně lišit. Náhlé zvýšení aktivity uživatelů nebo počtu agregovaných požadavků přicházejících z více tenantů může způsobit nepředvídatelné zatížení. Ve špičkách může systém potřebovat zpracovat mnoho stovek požadavků za sekundu, zatímco jindy může být číslo velmi malé. Navíc povaha akcí zpracovávajících tyto požadavky může být velmi proměnlivá. Použitím jedné instance služby příjemce můžete způsobit, že instance bude zahlcená požadavky. Nebo může být systém zasílání zpráv přetížen přílivem zpráv, které pocházejí z aplikace. Aby mohl systém zpracovávat proměnlivé zatížení, může používat více instancí služby příjemce. Tito příjemci ale musí být koordinovaní, aby se zajistilo, že každá zpráva se doručí jenom jednomu příjemci. Zatížení se také musí mezi příjemci vyrovnávat, aby se zabránilo tomu, že se některá instance stane kritickým bodem.

Řešení

Použijte frontu zpráv k implementaci komunikačního kanálu mezi aplikací a instancemi spotřebitelské služby. Aplikace odesílá požadavky ve formě zpráv do fronty a instance služby příjemce přijímají zprávy z fronty a zpracovávají je. Tento přístup umožňuje, aby zprávy z libovolné instance aplikace zpracovával stejný fond instancí služby příjemce. Obrázek znázorňuje distribuci úloh do instancí služby pomocí fronty zpráv.

Distribuce úloh do instancí služby pomocí fronty zpráv

Poznámka:

I když je těchto zpráv více příjemců, není to stejné jako model publikování odběru (pub/sub). Při přístupu Konkurenční spotřebitelé se každá zpráva předává jednomu příjemci ke zpracování, zatímco při přístupu Pub/Sub se předají všechny příjemce každé zprávy.

Toto řešení má tyto výhody:

  • Nabízí systém vyrovnávání zatížení, který umožňuje zpracovávat velké odchylky v množství požadavků odesílaných instancemi aplikace. Fronta funguje jako vyrovnávací prostředek mezi instancemi aplikace a instancemi služby příjemce. Tato vyrovnávací paměť může pomoct minimalizovat dopad na dostupnost a rychlost odezvy pro aplikace i instance služby. Další informace najdete v tématu Model vyrovnávání zatížení na základě fronty. Zpracování zprávy, která vyžaduje některé dlouhotrvající akce, nezabraňuje souběžnému zpracovávání dalších zpráv jinými instancemi služby příjemce.

  • Zvyšuje spolehlivost. Pokud odesílatel místo použití tohoto modelu komunikuje přímo s příjemcem, ale nemonitoruje tohoto příjemce, je vysoká pravděpodobnost, že při selhání u příjemce může dojít ke ztrátě zpráv nebo k chybě při jejich zpracování. V tomto modelu se zprávy neodesílají konkrétní instanci služby. Instance služby, která selhala, nezablokuje odesílatele a zprávy může zpracovat kterákoli funkční instance služby.

  • Nevyžaduje složitou koordinaci mezi příjemci ani mezi odesílatelem a instancemi příjemce. Fronta zpráv zajišťuje, že každá zpráva se doručí aspoň jednou.

  • Je škálovatelné. Když použijete automatické škálování, systém může dynamicky zvýšit nebo snížit počet instancí služby příjemce, protože objem zpráv kolísá.

  • Pokud fronta zpráv poskytuje transakční operace čtení, může se zvýšit odolnost. Pokud instance služby příjemce načte a zpracuje zprávu v rámci transakční operace a tato instance služby příjemce selže, může tento model zajistit vrácení dané zprávy do fronty, aby ji mohla načíst a zpracovat jiná instance služby příjemce. Pokud chcete zmírnit riziko nepřetržitého selhání zprávy, doporučujeme používat fronty nedoručených zpráv.

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:

  • Pořadí zpráv: Pořadí, ve kterém instance služby příjemce přijímají zprávy, není zaručené a neodráží nutně pořadí, ve kterém se zprávy vytvořily. Navrhněte systém tak, aby se zajistilo, že zpracování zpráv bude idempotentní, protože tak můžete omezit závislost na pořadí, ve kterém se zprávy zpracovávají. Další informace naleznete v tématu Idempotency Patterns na blogu Jonathon Olivera.

    Fronty služby Microsoft Azure Service Bus můžou k implementaci zaručeného pořadí zpráv využívat relace zpráv (metoda první dovnitř, první ven). Další informace najdete v článku o modelech zasílání zpráv s využitím relací.

  • Navrhování služeb z hlediska odolnosti: Pokud je systém navržený tak, aby zjišťoval a restartoval instance služby, které selhaly, může být nutné, aby se zpracování prováděné instancemi služby implementovalo jako idempotentní operace, které minimalizují účinky toho, že se jedna zpráva načte a zpracuje více než jednou.

  • Zjišťování nezpracovatelných zpráv: Poškozená zpráva nebo úloha vyžadující přístup k prostředkům, které nejsou k dispozici, může způsobit selhání instance služby. Systém by měl bránit návratu takových zpráv do fronty a místo toho zaznamenávat a ukládat podrobnosti o těchto zprávách někam jinam, aby se v případě potřeby daly analyzovat.

  • Zpracování výsledků: Instance služby zpracovávající zprávu je zcela oddělená od aplikační logiky, která generuje danou zprávu, a nemusí s ní přímo komunikovat. Pokud instance služby generuje výsledky, které je potřeba předávat zpět do aplikační logiky, je nutné, aby byly tyto informace uložené v umístění, které je přístupné pro obě služby. Aby se zabránilo načítání neúplných dat aplikační logikou, je nutné, aby systém indikoval, že zpracování je dokončené.

    Pokud používáte Azure, může pracovní proces předávat výsledky zpět do aplikační logiky pomocí vyhrazené fronty odpovědí na zprávy. Je nutné, aby aplikační logika mohla zjišťovat korelaci těchto výsledků s původní zprávou. Tento scénář je podrobně popsaný v úvodu k asynchronnímu zasílání zpráv.

  • Škálování systému zasílání zpráv: V řešení většího rozsahu se může jedna fronta zpráv zahltit velkým počtem zpráv a stát se kritickým bodem v systému. V této situaci zvažte rozdělení systému zasílání zpráv tak, aby se zprávy od určitých odesílatelů odesílaly do konkrétní fronty, nebo použití vyrovnávání zatížení k distribuci zpráv do více front.

  • Zajištění spolehlivosti systému zasílání zpráv: Vyžaduje se spolehlivý systém zasílání zpráv, který zaručuje, že když aplikace zprávu zařadí do fronty, nedojde ke ztrátě zprávy. Tento systém je nezbytný pro zajištění toho, aby se všechny zprávy doručily alespoň jednou.

Kdy se má tento model použít

Tento model použijte v těchto případech:

  • Zatížení pro aplikaci je rozdělené na úlohy, které lze spustit asynchronně.
  • Úlohy jsou nezávislé a můžou běžet paralelně.
  • Množství úloh je velmi proměnlivé a vyžaduje škálovatelné řešení.
  • Řešení musí poskytovat vysokou dostupnost a musí být odolné pro případ, že se zpracování úlohy nezdaří.

Tento model nebude pravděpodobně vhodný v následujících případech:

  • Zatížení aplikace není možné snadno rozdělit na jednotlivé úlohy nebo mezi úlohami se vyskytuje vysoký stupeň závislosti.
  • Úlohy je nutné provádět synchronně a logika aplikace musí před pokračováním čekat na dokončení úlohy.
  • Úlohy je nutné provádět v určitém pořadí.

Některé systémy zasílání zpráv podporují relace, které umožňují odesílateli seskupovat zprávy a zajistit, aby je všechny zpracoval stejný příjemce. Tento mechanismus lze použít u zpráv s určenou prioritou (pokud se tato funkce podporuje) k implementaci takového typu řazení zpráv, který doručuje zprávy podle pořadí od odesílatele jedinému příjemci.

Návrh úloh

Architekt by měl vyhodnotit způsob použití modelu Konkurenční spotřebitelé v návrhu jejich úloh k řešení cílů a principů zahrnutých v pilířích architektury Azure Well-Architected Framework. Příklad:

Pilíř Jak tento model podporuje cíle pilíře
Rozhodnutí o návrhu spolehlivosti pomáhají vaší úloze stát se odolnou proti selhání a zajistit, aby se po selhání obnovila do plně funkčního stavu. Tento model vytváří redundanci zpracování front tím, že zpracovává uživatele jako repliky, takže selhání instance nezabrání jiným příjemcům ve zpracování zpráv fronty.

- RE:05 Redundance
- RE:07 Úlohy na pozadí
Optimalizace nákladů se zaměřuje na udržení a zlepšení návratnosti vašich úloh. Tento model vám může pomoct optimalizovat náklady tím, že povolí škálování na základě hloubky fronty až na nulu, když je fronta prázdná. Může také optimalizovat náklady tím, že vám umožní omezit maximální počet souběžných instancí příjemců.

- CO:05 Optimalizace rychlosti
- CO:07 Náklady na komponenty
Efektivita výkonu pomáhá vaší úloze efektivně splňovat požadavky prostřednictvím optimalizací škálování, dat a kódu. Distribuce zatížení napříč všemi uzly příjemců zvyšuje využití a dynamické škálování na základě hloubky fronty minimalizuje nadměrné zřizování.

- PE:05 Škálování a dělení
- PE:07 Kód a infrastruktura

Stejně jako u jakéhokoli rozhodnutí o návrhu zvažte jakékoli kompromisy proti cílům ostatních pilířů, které by mohly být s tímto vzorem zavedeny.

Příklad

Azure poskytuje fronty služby Service Bus a triggery front funkcí Azure, které v kombinaci představují přímou implementaci tohoto vzoru návrhu cloudu. Azure Functions se integruje se službou Azure Service Bus prostřednictvím triggerů a vazeb. Integrace se službou Service Bus umožňuje vytvářet funkce, které využívají zprávy fronty odesílané vydavateli. Aplikace publikování budou publikovat zprávy do fronty a příjemci implementované jako Azure Functions mohou načítat zprávy z této fronty a zpracovávat je.

Kvůli odolnosti fronta služby Service Bus umožňuje příjemci používat PeekLock režim při načítání zprávy z fronty. Tento režim zprávu ve skutečnosti neodebere, ale jednoduše ji skryje před ostatními uživateli. Modul runtime Azure Functions obdrží zprávu v režimu PeekLock, pokud se funkce úspěšně dokončí voláním funkce Complete ve zprávě, nebo může volat Funkci Opustit, pokud funkce selže, a zpráva se znovu zobrazí a umožní jinému příjemci ji načíst. Pokud se funkce spustí po dobu delší než časový limit PeekLock, zámek se automaticky obnoví, pokud je funkce spuštěná.

Služba Azure Functions se může škálovat na více instancí na základě hloubky fronty, která funguje jako konkurenční příjemci fronty. Pokud se vytvoří více instancí funkcí, budou všechny soutěžit nezávisle na vyžádání a zpracování zpráv.

Podrobné informace o používání front služby Azure Service Bus najdete v tématu Fronty, témata a odběry služby Service Bus.

Informace o službě Azure Functions aktivované ve frontě najdete v tématu Trigger služby Azure Service Bus pro Azure Functions.

Následující kód ukazuje, jak můžete vytvořit novou zprávu a odeslat ji do fronty služby Service Bus pomocí ServiceBusClient instance.

private string serviceBusConnectionString = ...;
...

  public async Task SendMessagesAsync(CancellationToken  ct)
  {
   try
   {
    var msgNumber = 0;

    var serviceBusClient = new ServiceBusClient(serviceBusConnectionString);

    // create the sender
    ServiceBusSender sender = serviceBusClient.CreateSender("myqueue");

    while (!ct.IsCancellationRequested)
    {
     // Create a new message to send to the queue
     string messageBody = $"Message {msgNumber}";
     var message = new ServiceBusMessage(messageBody);

     // Write the body of the message to the console
     this._logger.LogInformation($"Sending message: {messageBody}");

     // Send the message to the queue
     await sender.SendMessageAsync(message);

     this._logger.LogInformation("Message successfully sent.");
     msgNumber++;
    }
   }
   catch (Exception exception)
   {
    this._logger.LogException(exception.Message);
   }
  }

Následující příklad kódu ukazuje příjemce napsaný jako funkce Azure Functions v jazyce C#, který čte metadata zpráv a protokoluje zprávu fronty služby Service Bus. Všimněte si, jak se ServiceBusTrigger atribut používá k vytvoření vazby k frontě služby Service Bus.

[FunctionName("ProcessQueueMessage")]
public static void Run(
    [ServiceBusTrigger("myqueue", Connection = "ServiceBusConnectionString")]
    string myQueueItem,
    Int32 deliveryCount,
    DateTime enqueuedTimeUtc,
    string messageId,
    ILogger log)
{
    log.LogInformation($"C# ServiceBus queue trigger function consumed message: {myQueueItem}");
    log.LogInformation($"EnqueuedTimeUtc={enqueuedTimeUtc}");
    log.LogInformation($"DeliveryCount={deliveryCount}");
    log.LogInformation($"MessageId={messageId}");
}

Další kroky

  • Úvod k asynchronnímu zasílání zpráv: Fronty zpráv jsou asynchronní komunikační mechanismus. Pokud služba příjemce vyžaduje odeslání odpovědi do aplikace, může být nutná implementace nějakého způsobu zasílání odpovědí. Úvod k asynchronnímu zasílání zpráv poskytuje informace o tom, jak se dá zasílání požadavků a odpovědí implementovat pomocí front zpráv.

  • Pokyny k automatickému škálování: Instance služby příjemce by mělo být možné spouštět a zastavovat, protože délka fronty, do které aplikace odesílají zprávy, se mění. Automatické škálování může usnadnit udržování propustnosti zpracování v obdobích špičky.

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

  • Model výpočtu konsolidace prostředků: Mělo by být možné provést konsolidaci více instancí služby příjemce do jediného procesu, aby se snížily náklady a režie na správu. Model konsolidace výpočtových prostředků popisuje výhody a nevýhody tohoto přístupu.

  • Model vyrovnávání zatížení na základě fronty: Zavedení fronty zpráv může systému dodat odolnost tím, že instance služby budou moct zpracovávat výrazně proměnlivá množství požadavků z instancí aplikace. Fronta zpráv funguje jako prostředek, který vyrovnává zatížení. Model vyrovnávání zatížení na základě fronty popisuje tento scénář podrobněji.