Prestanda- och skalningsvägledning för Event Hubs och Azure Functions

Azure Event Hubs
Azure Functions

Den här artikeln innehåller vägledning för att optimera skalbarhet och prestanda när du använder Azure Event Hubs och Azure Functions tillsammans i dina program.

Funktionsgruppering

Vanligtvis kapslar en funktion in en arbetsenhet i en händelsebearbetningsström. En funktion kan till exempel omvandla en händelse till en ny datastruktur eller berika data för underordnade program.

I Functions tillhandahåller en funktionsapp körningskontexten för funktioner. Funktionsappens beteenden gäller för alla funktioner som funktionsappen är värd för. Funktioner i en funktionsapp distribueras tillsammans och skalas tillsammans. Alla funktioner i en funktionsapp måste ha samma språk.

Hur du grupperar funktioner i funktionsappar kan påverka prestanda- och skalningsfunktionerna i dina funktionsappar. Du kan gruppera efter åtkomsträttigheter, distribution och användningsmönster som anropar koden.

Vägledning om metodtips för funktioner för gruppering och andra aspekter finns i Metodtips för tillförlitliga Azure Functions och Förbättra prestanda och tillförlitlighet för Azure Functions.

Följande lista är vägledning för grupperingsfunktioner. Vägledningen tar hänsyn till lagrings- och konsumentgruppsaspekter:

  • Värd för en enskild funktion i en funktionsapp: Om Event Hubs utlöser en funktion kan du isolera funktionen i sin egen funktionsapp för att minska konkurrensen mellan den funktionen och andra funktioner. Isolering är särskilt viktigt om de andra funktionerna är processor- eller minnesintensiva. Den här tekniken hjälper eftersom varje funktion har ett eget minnesavtryck och användningsmönster som direkt kan påverka skalningen av funktionsappen som är värd för den.

  • Ge varje funktionsapp ett eget lagringskonto: Undvik att dela lagringskonton mellan funktionsappar. Om en funktionsapp använder ett lagringskonto ska du inte heller använda det kontot för andra lagringsåtgärder eller behov. Det kan vara särskilt viktigt att undvika att dela lagringskonton för funktioner som Event Hubs utlöser, eftersom sådana funktioner kan ha en stor mängd lagringstransaktioner på grund av kontrollpunkter.

  • Skapa en dedikerad konsumentgrupp för varje funktionsapp: En konsumentgrupp är en vy över en händelsehubb. Olika konsumentgrupper har olika åsikter, vilket innebär att tillstånd, positioner och förskjutningar kan skilja sig åt. Konsumentgrupper gör det möjligt för flera använda program att ha sina egna vyer över händelseströmmen och att läsa dataströmmen oberoende av varandra i sin egen takt och med sina egna förskjutningar. Mer information om konsumentgrupper finns i Funktioner och terminologi i Azure Event Hubs.

    En konsumentgrupp har ett eller flera konsumentprogram kopplade till sig, och ett konsumentprogram kan använda en eller flera konsumentgrupper. I en dataströmbearbetningslösning motsvarar varje konsumentprogram en konsumentgrupp. En funktionsapp är ett bra exempel på ett konsumentprogram. Följande diagram innehåller ett exempel på två funktionsappar som läser från en händelsehubb, där varje app har en egen dedikerad konsumentgrupp:

    Dedikerade konsumentgrupper för varje funktionsapp

    Dela inte konsumentgrupper mellan funktionsappar och andra konsumentprogram. Varje funktionsapp bör vara ett distinkt program med en egen tilldelad konsumentgrupp för att säkerställa förskjutningsintegritet för varje konsument och för att förenkla beroenden i en arkitektur för händelseströmning. En sådan konfiguration, tillsammans med att tillhandahålla varje händelsehubbutlöst funktion sin egen funktionsapp och lagringskonto, hjälper till att skapa grunden för optimal prestanda och skalning.

Funktionsvärdplaner

Varje funktionsapp hanteras enligt en av tre värdplaner. Information om dessa planer finns i Azure Functions värdalternativ. Anteckna hur de tre alternativen skalas.

Förbrukningsplanen är standard. Funktionsappar i förbrukningsplanen skalas oberoende av varandra och är mest effektiva när de undviker långvariga uppgifter.

Premium- och Dedikerade planer används ofta för att vara värd för flera funktionsappar och funktioner som är mer processor- och minnesintensiva. Med den dedikerade planen kör du dina funktioner i en Azure App Service plan till regelbundna App Service abonnemangspriser. Det är viktigt att observera att alla funktionsappar i dessa planer delar de resurser som har allokerats till planen. Om funktioner har olika belastningsprofiler eller unika krav är det bäst att vara värd för dem i olika planer, särskilt i dataströmbearbetningsprogram.

Event Hubs-skalning

När du distribuerar ett Event Hubs-namnområde finns det flera viktiga inställningar som du måste ange korrekt för att säkerställa högsta prestanda och skalning. Det här avsnittet fokuserar på standardnivån för Event Hubs och de unika funktionerna på den nivån som påverkar skalningen när du även använder Functions. Mer information om Event Hubs-nivåer finns i Basic jämfört med Standard jämfört med Premium jämfört med dedikerade nivåer.

Ett Event Hubs-namnområde motsvarar ett Kafka-kluster. Information om hur Event Hubs och Kafka relaterar till varandra finns i Vad är Azure Event Hubs för Apache Kafka.

Förstå dataflödesenheter (RU:er)

På Event Hubs Standard-nivån klassificeras dataflödet som mängden data som anges och läss från namnområdet per tidsenhet. TU:er är förköpta enheter med dataflödeskapacitet.

TU:er debiteras per timme.

Alla händelsehubbar i ett namnområde delar TU:erna. För att kunna beräkna kapacitetsbehoven korrekt måste du ta hänsyn till alla program och tjänster, både utgivare och konsumenter. Funktionerna påverkar antalet byte och händelser som publiceras till och läss från en händelsehubb.

Betoningen för att fastställa antalet TU:er ligger på ingresspunkten. Aggregering för konsumentprogram, inklusive den hastighet med vilken dessa händelser bearbetas, måste dock också tas med i beräkningen.

Mer information om dataflödesenheter för Event Hubs finns i Dataflödesenheter.

Skala upp med Auto-inflate

Automatisk blåsning kan aktiveras på ett Event Hubs-namnområde för att hantera situationer där belastningen överskrider det konfigurerade antalet TU:er. Om du använder Auto-inflate förhindrar du begränsning av ditt program och säkerställer att bearbetningen, inklusive inmatning av händelser, fortsätter utan avbrott. Eftersom TU-inställningen påverkar kostnaderna kan du lösa problem med överetablering med hjälp av Automatisk uppflatering.

Auto-inflate är en funktion i Event Hubs som ofta förväxlas med autoskalning, särskilt i samband med serverlösa lösningar. Men autouppfyllnad, till skillnad från autoskalning, skalas inte ned när den tillagda kapaciteten inte längre behövs.

Om programmet behöver kapacitet som överskrider det maximala tillåtna antalet TU:er bör du överväga att använda Event Hubs Premium-nivå eller dedikerad nivå.

Partitioner och samtidiga funktioner

När en händelsehubb skapas måste antalet partitioner anges. Partitionsantalet är fortfarande fast och kan inte ändras förutom premium- och dedikerade nivåer. När Event Hubs utlöser funktionsappar är det möjligt att antalet samtidiga instanser kan vara lika med antalet partitioner.

I Förbruknings- och Premium-värdplaner skalar funktionsappinstanserna ut dynamiskt för att uppfylla antalet partitioner, om det behövs. Den dedikerade värdplanen kör funktioner i en App Service plan och kräver att du konfigurerar dina instanser manuellt eller konfigurerar ett autoskalningsschema. Mer information finns i Dedikerade värdplaner för Azure Functions.

I slutändan är en en-till-en-relation mellan antalet partitioner och funktionsappinstanser det idealiska målet för maximalt dataflöde i en dataströmbearbetningslösning. För att uppnå optimal parallellitet kan du ha flera konsumenter i en konsumentgrupp. För Functions översätts det här målet till många instanser av en funktionsapp i planen. Resultatet kallas parallellitet på partitionsnivå eller maximal grad av parallellitet, enligt följande diagram:

Maximal grad av parallellitet

Det kan verka vettigt att konfigurera så många partitioner som möjligt för att uppnå maximalt dataflöde och ta hänsyn till möjligheten till en högre mängd händelser. Det finns dock flera viktiga faktorer att tänka på när du konfigurerar många partitioner:

  • Fler partitioner kan leda till mer dataflöde: Eftersom graden av parallellitet är antalet konsumenter (funktionsappinstanser), desto fler partitioner finns det, desto högre kan det samtidiga dataflödet vara. Det här är viktigt när du delar ett angivet antal TU:er för en händelsehubb med andra konsumentprogram.
  • Fler funktioner kan kräva mer minne: I takt med att antalet instanser av funktionsappar ökar, ökar även minnesfotavtrycket för resurser i planen. Vid något tillfälle kan för många partitioner försämra prestanda för konsumenter.
  • Det finns en risk för mottryck från underordnade tjänster: När mer dataflöde genereras riskerar du att överbelasta underordnade tjänster eller få tillbaka tryck från dem. Konsumentfan-out måste redovisas när man överväger konsekvenserna för omgivande resurser. Möjliga konsekvenser var begränsningar från andra tjänster, nätverksmättnad och andra former av resurskonkurrering.
  • Partitioner kan fyllas i glest: Kombinationen av många partitioner och en låg mängd händelser kan leda till data som är glest fördelade över partitioner. I stället kan ett mindre antal partitioner ge bättre prestanda och resursanvändning

Tillgänglighet och konsekvens

När en partitionsnyckel eller ett ID inte har angetts dirigerar Event Hubs en inkommande händelse till nästa tillgängliga partition. Den här metoden ger hög tillgänglighet och hjälper till att öka dataflödet för konsumenter.

När en uppsättning händelser måste ordnas kan händelseproducenten ange att en viss partition ska användas för alla händelser i uppsättningen. Konsumentprogrammet som läser från partitionen tar emot händelserna i rätt ordning. Den här kompromissen ger konsekvens men äventyrar tillgängligheten. Använd inte den här metoden om inte händelseordningen måste bevaras.

För Functions uppnås ordningen när händelser publiceras till en viss partition och en händelsehubbutlöst funktion hämtar ett lån till samma partition. För närvarande stöds inte möjligheten att konfigurera en partition med Event Hubs-utdatabindningen. Den bästa metoden är i stället att använda en av Event Hubs SDK:er för att publicera till en viss partition.

Mer information om hur Event Hubs stöder tillgänglighet och konsekvens finns i Tillgänglighet och konsekvens i Event Hubs.

Event Hubs-utlösare

Det här avsnittet fokuserar på inställningar och överväganden för att optimera funktioner som Event Hubs utlöser. Faktorerna är batchbearbetning, sampling och relaterade funktioner som påverkar beteendet för en händelsehubbs utlösarbindning.

Batchbearbetning för utlösta funktioner

Du kan konfigurera funktioner som en händelsehubb utlöser för att bearbeta en batch med händelser eller en händelse i taget. Bearbetning av en batch med händelser är mer effektivt eftersom det eliminerar en del av omkostnaderna för funktionsanrop. Om du inte bara behöver bearbeta en enda händelse ska funktionen konfigureras för att bearbeta flera händelser när den anropas.

Aktivering av batchbearbetning för Event Hubs-utlösarbindningen varierar mellan olika språk:

  • JavaScript, Python och andra språk aktiverar batchbearbetning när kardinalitetsegenskapen är inställd på många i function.json-filen för funktionen.
  • I C# konfigureras kardinaliteten automatiskt när en matris har angetts för typen i attributet EventHubTrigger .

Mer information om hur batchbearbetning är aktiverat finns i Azure Event Hubs utlösare för Azure Functions.

Inställningar för utlösare

Flera konfigurationsinställningar i filen host.json spelar en viktig roll i prestandaegenskaperna för Event Hubs-utlösarbindningen för Functions:

  • maxEventBatchSize: Den här inställningen representerar det maximala antalet händelser som funktionen kan ta emot när den anropas. Om antalet mottagna händelser är mindre än det här beloppet anropas funktionen fortfarande med så många händelser som är tillgängliga. Du kan inte ange en minsta batchstorlek.
  • prefetchCount: Antalet prefetch är en av de viktigaste inställningarna när du optimerar för prestanda. Den underliggande AMQP-kanalen refererar till det här värdet för att avgöra hur många meddelanden som ska hämtas och cachelagras för klienten. Antalet prefetch ska vara större än eller lika med maxEventBatchSize-värdet och anges ofta till en multipel av det beloppet. Om du ställer in det här värdet på ett tal som är mindre än maxEventBatchSize-inställningen kan prestandan försämras.
  • batchCheckpointFrequency: När funktionen bearbetar batchar avgör det här värdet hur snabbt kontrollpunkter skapas. Standardvärdet är 1, vilket innebär att det finns en kontrollpunkt när en funktion bearbetar en batch. En kontrollpunkt skapas på partitionsnivå för varje läsare i konsumentgruppen. Information om hur den här inställningen påverkar repriser och återförsök av händelser finns i Event Hub triggered Azure function: Replays and Retries (blogginlägg).

Utför flera prestandatester för att fastställa de värden som ska anges för utlösarbindningen. Vi rekommenderar att du ändrar inställningarna stegvis och mäter konsekvent för att finjustera dessa alternativ. Standardvärdena är en rimlig startpunkt för de flesta händelsebearbetningslösningar.

Kontrollpunkter

Kontrollpunkter markerar eller checkar in läsarpositioner i en partitionshändelsesekvens. Det är functions-värdens ansvar att kontrollera när händelser bearbetas och inställningen för batchkontrollpunktsfrekvensen uppfylls. Mer information om kontrollpunkter finns i Funktioner och terminologi i Azure Event Hubs.

Följande begrepp kan hjälpa dig att förstå relationen mellan kontrollpunkter och hur din funktion bearbetar händelser:

  • Undantag räknas fortfarande mot framgång: Om funktionsprocessen inte kraschar vid bearbetning av händelser anses slutförandet av funktionen vara lyckad, även om undantag har inträffat. När funktionen är klar utvärderar Functions-värden batchCheckpointFrequency. Om det är dags för en kontrollpunkt skapar den en, oavsett om det fanns undantag. Det faktum att undantag inte påverkar kontrollpunkter bör inte påverka korrekt användning av undantagskontroll och hantering.
  • Batchfrekvens spelar roll: I lösningar för händelseströmning med stora volymer kan det vara bra att ändra inställningen batchCheckpointFrequency till ett värde som är större än 1. Om du ökar det här värdet kan du minska genereringshastigheten för kontrollpunkt och därmed antalet I/O-åtgärder för lagring.
  • Repriser kan inträffa: Varje gång en funktion anropas med Event Hubs-utlösarbindningen använder den den senaste kontrollpunkten för att avgöra var bearbetningen ska återupptas. Förskjutningen för varje konsument sparas på partitionsnivå för varje konsumentgrupp. Repriser inträffar när en kontrollpunkt inte inträffar under funktionens senaste anrop och funktionen anropas igen. Mer information om dubbletter och dedupliceringstekniker finns i Idempotens.

Att förstå kontrollpunkter blir viktigt när du överväger metodtips för felhantering och återförsök, ett ämne som beskrivs senare i den här artikeln.

Telemetrisampling

Functions har inbyggt stöd för Application Insights, ett tillägg av Azure Monitor som tillhandahåller funktioner för övervakning av programprestanda. Med den här funktionen kan du logga information om funktionsaktiviteter, prestanda, körningsund undantag med mera. Mer information finns i Översikt över Application Insights.

Den här kraftfulla funktionen erbjuder några viktiga konfigurationsalternativ som påverkar prestanda. Några av de viktigaste inställningarna och övervägandena för övervakning och prestanda är:

  • Aktivera telemetrisampling: För scenarier med högt dataflöde bör du utvärdera mängden telemetri och information som du behöver. Överväg att använda telemetrisamplingsfunktionen i Application Insights för att undvika att försämra funktionens prestanda med onödig telemetri och mått.
  • Konfigurera sammansättningsinställningar: Granska och konfigurera frekvensen för att aggregera och skicka data till Application Insights. Den här konfigurationsinställningen finns i filen host.json tillsammans med många andra alternativ för sampling och loggning. Mer information finns i Konfigurera aggregatorn.
  • Inaktivera AzureWebJobDashboard: För appar som är målversion 1.x av Functions-körningen lagrar den här inställningen anslutningssträngen till ett lagringskonto som Azure SDK använder för att behålla loggar för WebJobs-instrumentpanelen. Om Application Insights används i stället för WebJobs-instrumentpanelen bör den här inställningen tas bort. Mer information finns i AzureWebJobsDashboard.

När Application Insights är aktiverat utan sampling skickas all telemetri. Att skicka data om alla händelser kan ha en skadlig effekt på funktionens prestanda, särskilt i scenarier med händelseströmning med högt dataflöde.

Att dra nytta av provtagning och kontinuerligt bedöma den mängd telemetri som behövs för övervakning är avgörande för optimala prestanda. Telemetri ska användas för allmän hälsoutvärdering av plattformen och för tillfällig felsökning, inte för att samla in viktiga affärsmått. Mer information finns i Konfigurera sampling.

Utdatabindning

Använd Event Hubs-utdatabindningen för Azure Functions för att förenkla publiceringen till en händelseström från en funktion. Fördelarna med att använda den här bindningen är:

  • Resurshantering: Bindningen hanterar både klient- och anslutningslivscykler åt dig och minskar risken för problem som kan uppstå med portöverbelastning och hantering av anslutningspooler.
  • Mindre kod: Bindningen abstraherar den underliggande SDK:en och minskar mängden kod som du behöver för att publicera händelser. Det hjälper dig att skriva kod som är enklare att skriva och underhålla.
  • Dosering: För flera språk stöds batchbearbetning för att effektivt publicera till en händelseström. Batchbearbetning kan förbättra prestanda och effektivisera koden som skickar händelserna.

Vi rekommenderar starkt att du granskar listan över språk som Functions stöder och utvecklarguiderna för dessa språk. Avsnittet Bindningar för varje språk innehåller detaljerade exempel och dokumentation.

Batchbearbetning vid publicering av händelser

Om funktionen bara publicerar en enskild händelse är det vanligt att konfigurera bindningen för att returnera ett värde om funktionskörningen alltid slutar med en instruktion som skickar händelsen. Den här tekniken bör endast användas för synkrona funktioner som bara returnerar en händelse.

Batchbearbetning uppmuntras att förbättra prestanda när flera händelser skickas till en dataström. Batchbearbetning gör att bindningen kan publicera händelser på det mest effektiva sättet.

Stöd för att använda utdatabindningen för att skicka flera händelser till Event Hubs finns i C#, Java, Python och JavaScript.

Mata ut flera händelser (C#)

Använd typerna ICollector och IAsyncCollector när du skickar flera händelser från en funktion i C#.

  • ICollector<T>. Add()-metoden kan användas i både synkrona och asynkrona funktioner. Den kör tilläggsåtgärden så snart den anropas.
  • IAsyncCollector<T>. AddAsync()-metoden förbereder de händelser som ska publiceras till händelseströmmen. Om du skriver en asynkron funktion bör du använda IAsyncCollector för att bättre hantera publicerade händelser.

Exempel på hur du använder C# för att publicera enstaka och flera händelser finns i Azure Event Hubs utdatabindning för Azure Functions.

Begränsning och bakåttryck

Begränsningsöverväganden gäller för utdatabindning, inte bara för Event Hubs utan även för Azure-tjänster som Azure Cosmos DB. Det är viktigt att bekanta sig med de gränser och kvoter som gäller för dessa tjänster och att planera därefter.

Om du vill hantera underordnade fel kan du omsluta AddAsync och FlushAsync i en undantagshanterare för .NET Functions för att fånga undantag från IAsyncCollector. Ett annat alternativ är att använda Event Hubs SDK:er direkt i stället för att använda utdatabindningar.

Funktionskod

Det här avsnittet beskriver de viktiga områden som måste beaktas när du skriver kod för att bearbeta händelser i en funktion som Event Hubs utlöser.

Asynkron programmering

Vi rekommenderar att du skriver din funktion för att använda asynkron kod och undvika blockering av anrop, särskilt när I/O-anrop ingår.

Här följer riktlinjer som du bör följa när du skriver en funktion för att bearbeta asynkront:

  • Alla asynkrona eller synkrona: Om en funktion är konfigurerad att köras asynkront bör alla I/O-anrop vara asynkrona. I de flesta fall är delvis asynkron kod sämre än kod som är helt synkron. Välj antingen asynkron eller synkron och håll dig till valet hela vägen.
  • Undvik blockering av anrop: Blockerande anrop återgår endast till anroparen när anropet har slutförts, till skillnad från asynkrona anrop som returneras omedelbart. Ett exempel i C# skulle vara att anropa Task.Result eller Task.Wait på en asynkron åtgärd.

Mer om att blockera anrop

Om du använder blockeringsanrop för asynkrona åtgärder kan det leda till utsvulten trådpool och orsaka att funktionsprocessen kraschar. Kraschen inträffar eftersom ett blockeringsanrop kräver att en annan tråd skapas för att kompensera för det ursprungliga anropet som nu väntar. Därför krävs dubbelt så många trådar för att slutföra åtgärden.

Att undvika den här synkroniseringen över asynkron metod är särskilt viktigt när Event Hubs är inblandat, eftersom en funktionskrasch inte uppdaterar kontrollpunkten. Nästa gång funktionen anropas kan den hamna i den här cykeln och verkar ha fastnat eller röra sig långsamt när funktionskörningarna så småningom överskrider tidsgränsen.

Felsökning av det här fenomenet börjar vanligtvis med att granska utlösarinställningarna och köra experiment som kan innebära att antalet partitioner ökar. Undersökningar kan också leda till att flera av batchalternativen ändras, till exempel den maximala batchstorleken eller antalet prefetch. Intrycket är att det är ett dataflödesproblem eller en konfigurationsinställning som bara behöver justeras därefter. Huvudproblemet finns dock i själva koden och måste åtgärdas där.

Deltagare

Den här artikeln underhålls av Microsoft. Den skrevs ursprungligen av följande deltagare.

Huvudförfattare:

Om du vill se icke-offentliga LinkedIn-profiler loggar du in på LinkedIn.

Nästa steg

Innan du fortsätter bör du överväga att granska dessa relaterade artiklar: