Mönster för konsolidering av beräkningsresurser

Konsolidera flera aktiviteter eller åtgärder i en enda beräkningsenhet. Det här kan öka användningen av beräkningsresurserna. Det kan dessutom minska kostnaderna och hanteringen kopplade till att beräkna i molnbaserade program.

Kontext och problem

Ett molnprogram implementerar ofta en mängd åtgärder. I vissa lösningar är det klokt inledningsvis följa designprincipen att dela upp olika ämnen. Du delar då upp de här åtgärderna i separata beräkningsenheter. De har olika värdar och distribueras enskilt (exempelvis som separata App Service-webbappar, separata virtuella datorer och separata molntjänstroller). Den här strategin kan visserligen underlätta den logiska utformningen av lösningen, men du ska vara medveten om att distribution av ett stort antal beräkningsenheter som del av samma program kan öka runtime-värdkostnaderna och göra hantering av systemet mer komplex.

Bilden visar ett exempel på en förenklad struktur i en molnbaserad lösning som implementeras med hjälp av mer än en beräkningsenhet. Varje beräkningsenhet körs i en egen virtuell miljö. Varje funktion har implementerats som separat åtgärd (märkta aktivitet A till E) och körs med en egen beräkningsenhet.

Köra aktiviteter i molnmiljö med en uppsättning dedikerade beräkningsenheter

Varje beräkningsenhet förbrukar resurser, även när den är inaktiv eller används i begränsad omfattning. Det är därför inte alltid den mest kostnadseffektiva lösningen.

I Azure gäller detta rollerna i molntjänster, App Services och virtuella datorer. Dessa objekt körs i egna virtuella miljöer. Det kan vara ineffektiv resursanvändning att köra en mängd olika roller, webbplatser och virtuella maskiner som är utformade för att utföra en uppsättning väldefinierade åtgärder och samtidigt behöver kommunicera och samarbeta i en enda lösning.

Lösning

Det går att konsolidera flera aktiviteter och åtgärder i en enda beräkningsenhet. Det här görs i syfte att minska kostnaderna, öka användningsgraden, skynda på kommunikationen och minska hanteringen.

Aktiviteter kan grupperas enligt villkor, baserat på funktionerna i miljön och kostnaderna knutna till de här funktionerna. En vanlig metod är att söka efter aktiviteter som har en liknande profil vad gäller krav på skalbarhet, livstid och behandling. När de här grupperas tillsammans kan de skalanpassas som en enhet. Många molnmiljöer har stor elasticitet. Det betyder att det går att starta och stoppa ytterligare instanser av en beräkningsenhet, allt enligt arbetsbelastning. Azure tillhandahåller exempelvis automatisk skalningsanpassning som du kan tillämpa på roller i molnbaserade tjänster, App Services och virtuella datorer. Mer information finns i Vägledning om autoskalning.

Här visar vi två uppgifter som exempel på hur skalbarhet kan användas för att avgöra vilka åtgärder som inte ska grupperas tillsammans:

  • Aktivitet 1 söker efter ovanliga, icke tidskänsliga meddelanden som har skickats till en kö.
  • Aktivitet 2 hanterar stora och plötsliga toppar i nätverkstrafiken.

Den andra aktiviteten kräver elasticitet som kan omfatta att starta och stoppa ett stort antal instanser av beräkningsenheten. Att tillämpa samma skalning på den första aktiviteten skulle bara resultera i att fler aktiviteter skulle lyssna efter ovanliga meddelanden i samma kö. Det är slöseri med resurser.

I många molnmiljöer går det att specificera vilka resurser som är tillgängliga för en beräkningsenhet, vad gäller antal processorkärnor, minne, diskutrymme och så vidare. I allmänhet gäller att ju fler resurser som anges, desto större blir kostnaden. Om du vill spara pengar är det viktigt att maximera det arbete en dyr beräkningsenhet utför och inte låta den vara inaktiv någon längre tid.

Om det finns aktiviteter som kräver korta sekvenser med mycket intensiv processoreffekt kan du överväga att konsolidera de här i en enda beräkningsenhet som tillhandahåller den nödvändiga effekten. Det är dock viktigt att balansera behovet av att hålla dyra resurser aktiva mot konkurrensen som kan uppstå om de överbelastas. Det är till exempel inte bra att låta flera tidskrävande, beräkningsintensiva aktiviteter dela samma beräkningsenhet.

Problem och överväganden

Tänk på följande när du implementerar det här mönstret:

Skalbarhet och elasticitet. I många molnlösningar implementeras skalbarhet och elasticitet hos beräkningsenheten genom att instanser av enheter startas och stoppas. Undvik att samla aktiviteter med konkurrerande skalbarhetskrav i samma beräkningsenhet.

Livslängd. Molninfrastrukturen återanvänder regelbundet den virtuella miljö som är värd för en beräkningsenhet. När det finns många tidskrävande aktiviteter i en beräkningsenhet kan det vara nödvändigt att konfigurera enheten så att den inte återvinns förrän dessa aktiviteter har slutförts. Du kan också utforma aktiviteter med hjälp av kontrollpunkter som gör det möjligt för dem att stanna upp vid en viss punkt och sedan fortsätta från samma punkt när beräkningsenheten startar igen.

Frisläppningstakt. Om implementeringen eller konfigurationen för en aktivitet ändras ofta kan det bli nödvändigt att stoppa den beräkningsenhet som är värd för den uppdaterade koden, konfigurera om enheten, distribuera om den och sedan starta om den. Den här processen kräver också att alla andra aktiviteter inom samma beräkningsenhet stoppas, distribueras om och startas om.

Säkerhet. Aktiviteter i samma beräkningsenhet kan dela samma säkerhetskontext och kan eventuellt komma åt samma resurser. Förtroendegraden mellan aktiviteterna måste vara hög, och det måste vara sannolikt att ingen aktivitet skadar eller på annat sätt negativt påverkar någon annan. När antalet aktiviteter som körs i en beräkningsenhet växer ökar samtidigt risken för angrepp på enheten. Det är den aktivitet som har flest sårbarheter som bestämmer säkerhetsnivån.

Feltolerans. Om en aktivitet i en beräkningsenhet misslyckas eller beter sig onormalt kan det påverka de andra aktiviteterna som körs på samma enhet. Om en aktivitet till exempel inte kan startas på rätt sätt kan hela startlogiken för beräkningsenheten misslyckas och förhindra att andra aktiviteter i samma enhet körs.

Konkurrens. Undvik att införa konkurrens mellan aktiviteter som konkurrerar om resurser i samma beräkningsenhet. Vi rekommenderar att du ser till att aktiviteter som delar samma beräkningsenhet har olika resursanvändningsbehov. Du bör till exempel inte placera två beräkningsintensiva aktiviteter i samma beräkningsenhet, och inte heller två aktiviteter som använder stora mängder minne. Att blanda en beräkningsintensiv uppgift med en aktivitet som kräver en stor mängd minne är dock en användbar kombination.

Anteckning

Överväg att konsolidera beräkningsresurser endast för ett system som har varit i produktion under en viss tidsperiod så att operatörer och utvecklare kan övervaka systemet och skapa en värmekarta som identifierar hur varje uppgift använder olika resurser. Kartan kan användas för att avgöra vilka aktiviteter som kan dela beräkningsresurser.

Komplexitet. När du kombinera flera aktiviteter i en beräkningsenhet gör det koden för enheten mer komplex. Det kan göra den svårare att testa, felsöka och underhålla.

Stabil logisk arkitektur. Utforma och implementera koden i varje aktivitet så att den inte behöver ändras, även om den fysiska miljön som aktiviteten körs i ändras.

Andra strategier. Konsolidering av beräkningsresurser är bara ett sätt att minska kostnaderna förknippade med flera samtidiga aktiviteter. Det krävs noggrann planering och övervakning för att säkerställa att det förblir en effektiv strategi. Andra strategier kan vara bättre lämpade. Det beror på arbetets typ och var de användare som är kopplade till aktiviteterna finns. En funktionell uppdelning av arbetsbelastningen (som beskrivs i guiden om beräkningspartitionering) kan vara ett bättre alternativ.

När du ska använda det här mönstret

Använd det här mönstret för aktiviteter som inte är kostnadseffektiva när de körs i egna beräkningsenheter. Om en aktivitet är inaktiv en stor del av tiden kan det bli dyrt att köra den här aktiviteten i en egen enhet.

Det här mönstret kanske inte är lämpligt för aktiviteter som utför kritiska feltoleranta åtgärder. Det kanske inte heller är lämpligt för aktiviteter som bearbetar mycket känsliga eller privata data som kräver en egen säkerhetskontext. Den typen av aktiviteter ska köras i en egen isolerad miljö, i en separat beräkningsenhet.

Exempel

När du skapar en molntjänst i Azure är det möjligt att konsolidera bearbetningen som utförs av flera uppgifter till en enda roll. Det här är vanligtvis en arbetsroll som utför bearbetningsaktiviteter i bakgrunden eller asynkront.

I vissa fall går det att inkludera bakgrundsaktiviteter och asynkrona bearbetningsaktiviteter i webbrollen. Den här tekniken sänker kostnaderna och förenklar distributionen. Den kan dock påverka skalbarheten och svarstiderna för det offentliga gränssnittet som tillhandahålls av webbrollen.

Rollen är ansvarig för att starta och stoppa aktiviteterna. När Microsoft Azure-infrastrukturkontrollanten läser in en roll genererar den Start-händelsen för rollen. Det går att åsidosätta OnStart-metoden för WebRole- eller WorkerRole-klassen för att hantera händelsen, kanske för att initiera data och andra resurser som aktiviteterna i den här metoden är beroende av.

När OnStart metoden har slutförts kan rollen börja svara på begäranden. Du hittar mer information och vägledning om hur du använder metoderna och i en roll i avsnittet Startprocesser för program i mönsterguiden OnStartRun Flytta program till OnStart&Run

Håll koden i OnStart-metoden så koncis som möjligt. Azure har ingen tidsgräns för när metoden ska slutföras. Rollen kan dock börja svara på nätverksförfrågningar först när metoden har slutförts.

När OnStart-metoden har slutförts kör rollen Run-metoden. Vid det här laget kan infrastrukturkontrollanten börja skicka förfrågningar till rollen.

Placera den kod som faktiskt skapar aktiviteterna i Run-metoden. Observera att Run-metoden definierar livslängden för rollinstansen. När den här metoden slutförs ser infrastrukturkontrollanten till att rollen stängs av.

När en roll stängs av eller återanvänds förhindrar infrastrukturkontrollanten att fler inkommande begäranden tas emot från lastbalanseraren och aktiverar Stop-händelsen. Du kan fånga den här händelsen genom att åsidosätta OnStop-metoden för rollen och rensa upp efter behov innan rollen avslutas.

Alla åtgärder som utförs inom OnStop-metoden måste slutföras inom fem minuter (eller 30 sekunder om du använder Azure-emulatorn på en lokal dator). Annars förutsätter Microsoft Azure-infrastrukturkontrollanten att rollen har stannat upp och tvingar fram ett stopp.

Aktiviteterna startas av Run-metoden som väntar på att aktiviteter ska slutföras. Aktiviteterna implementerar affärslogiken från molntjänsten och svarar på meddelanden som skickas till rollen via Azure-lastbalanseraren. Bilden visar livscykeln för aktiviteter och resurser i en roll i en Azure-molntjänst.

Livscykeln för aktiviteter och resurser i en roll i en Azure-molntjänst

I filen WorkerRole.cs i projektet ComputeResourceConsolidation.Worker finns ett exempel på hur du kan implementera det här mönstret i en Azure-molntjänst.

Projektet ComputeResourceConsolidation.Worker ingår i lösningen ComputeResourceConsolidation som du kan hämta från GitHub.

Metoderna MyWorkerTask1 och MyWorkerTask2 illustrerar hur du utför olika aktiviteter inom samma arbetsroll. Följande kod visar MyWorkerTask1. Det här är en enkel aktivitet som vilar i 30 sekunder och sedan matar ut ett spårningsmeddelande. Processen upprepas tills aktiviteten avbryts. Koden i MyWorkerTask2 är liknande.

// A sample worker role task.
private static async Task MyWorkerTask1(CancellationToken ct)
{
  // Fixed interval to wake up and check for work and/or do work.
  var interval = TimeSpan.FromSeconds(30);

  try
  {
    while (!ct.IsCancellationRequested)
    {
      // Wake up and do some background processing if not canceled.
      // TASK PROCESSING CODE HERE
      Trace.TraceInformation("Doing Worker Task 1 Work");

      // Go back to sleep for a period of time unless asked to cancel.
      // Task.Delay will throw an OperationCanceledException when canceled.
      await Task.Delay(interval, ct);
    }
  }
  catch (OperationCanceledException)
  {
    // Expect this exception to be thrown in normal circumstances or check
    // the cancellation token. If the role instances are shutting down, a
    // cancellation request will be signaled.
    Trace.TraceInformation("Stopping service, cancellation requested");

    // Rethrow the exception.
    throw;
  }
}

Exempelkoden visar en vanlig tillämpning av bakgrundsprocessen. I en verklig tillämpning går det att följa samma struktur, förutom att du skulle placera din egen bearbetningslogik i innehållet i den loop som väntar på avbrottsbegäran.

När arbetsrollen har initierat de resurser den använder så startar metoden Run de två aktiviteterna samtidigt, som visas här.

/// <summary>
/// The cancellation token source use to cooperatively cancel running tasks
/// </summary>
private readonly CancellationTokenSource cts = new CancellationTokenSource();

/// <summary>
/// List of running tasks on the role instance
/// </summary>
private readonly List<Task> tasks = new List<Task>();

// RoleEntry Run() is called after OnStart().
// Returning from Run() will cause a role instance to recycle.
public override void Run()
{
  // Start worker tasks and add to the task list
  tasks.Add(MyWorkerTask1(cts.Token));
  tasks.Add(MyWorkerTask2(cts.Token));

  foreach (var worker in this.workerTasks)
  {
      this.tasks.Add(worker);
  }

  Trace.TraceInformation("Worker host tasks started");
  // The assumption is that all tasks should remain running and not return,
  // similar to role entry Run() behavior.
  try
  {
    Task.WaitAll(tasks.ToArray());
  }
  catch (AggregateException ex)
  {
    Trace.TraceError(ex.Message);

    // If any of the inner exceptions in the aggregate exception
    // are not cancellation exceptions then re-throw the exception.
    ex.Handle(innerEx => (innerEx is OperationCanceledException));
  }

  // If there wasn't a cancellation request, stop all tasks and return from Run()
  // An alternative to canceling and returning when a task exits would be to
  // restart the task.
  if (!cts.IsCancellationRequested)
  {
    Trace.TraceInformation("Task returned without cancellation request");
    Stop(TimeSpan.FromMinutes(5));
  }
}
...

I det här exemplet väntar metoden Run på aktiviteter som ska slutföras. Om en aktivitet avbryts så förutsätter metoden Run att rollen stängs av. Den väntar sedan på att de återstående aktiviteterna ska avbrytas innan den avslutar (högst fem minuter innan försöket avbryts). Om en aktivitet misslyckas på grund av ett förväntat undantag så avbryter metoden Run aktiviteten.

Du kan implementera mer omfattande strategier för övervakning och undantagshantering i metoden Run. Det kan till exempel vara att starta om aktiviteter som har misslyckats och att inkludera kod som gör det möjligt för rollen att stoppa och starta enskilda aktiviteter.

Stop-metoden som visas i följande kod anropas när infrastrukturkontrollanten stänger ned rollinstansen (den anropas från OnStop-metoden). Koden stoppar smidigt varje aktivitet genom att avbryta den. Om någon aktivitet tar mer än fem minuter att slutföra så slutar avbrottsprocessen i Stop-metoden att vänta. Rollen avslutas.

// Stop running tasks and wait for tasks to complete before returning
// unless the timeout expires.
private void Stop(TimeSpan timeout)
{
  Trace.TraceInformation("Stop called. Canceling tasks.");
  // Cancel running tasks.
  cts.Cancel();

  Trace.TraceInformation("Waiting for canceled tasks to finish and return");

  // Wait for all the tasks to complete before returning. Note that the
  // emulator currently allows 30 seconds and Azure allows five
  // minutes for processing to complete.
  try
  {
    Task.WaitAll(tasks.ToArray(), timeout);
  }
  catch (AggregateException ex)
  {
    Trace.TraceError(ex.Message);

    // If any of the inner exceptions in the aggregate exception
    // are not cancellation exceptions then rethrow the exception.
    ex.Handle(innerEx => (innerEx is OperationCanceledException));
  }
}

Följande mönster och riktlinjer kan vara relevanta när du implementerar det här mönstret:

  • Vägledning för automatisk skalning. Automatisk skalning kan användas för att starta och stoppa instanser av bearbetningsresurser av typen värd för tjänst, beroende på förväntat bearbetningsbehov.

  • Riktlinjer för beräkningspartitionering. Beskriver hur du tilldelar tjänster och komponenter i en molntjänst på ett sätt som hjälper till att minimera de löpande kostnaderna samtidigt som tjänstens skalbarhet, prestanda, tillgänglighet och säkerhet bibehålls.

  • Det här mönstret omfattar ett nedladdningsbart exempelprogram.