Prestanda och skalning för Event Hubs och Azure Functions

Event Hubs
Functions

När du Azure Functions med Event Hubs finns det många funktioner och beslut som påverkar både prestanda och skalning. Den här artikeln innehåller normativ vägledning för att få ut det mesta av den här dynamiska parkopplingen.

Funktionsgruppering

Normalt kapslar en funktion in en arbetsenhet som bearbetar enskilda händelser. Det här arbetet kan omfatta omvandling av en händelse till en ny datastruktur eller kanske ett berikningssteg i en datapipeline för underordnade program.

Hur du grupperar funktioner kan ha en direkt effekt på funktionerna för prestanda och skalning i dina funktionsappar. Flera metodtips föreslår gruppering efter åtkomsträttigheter, distribution och användningsmönster som anropar din kod.

Andra riktlinjer för grupperingsfunktioner, med överväganden för lagring och konsumentgrupper, är:

  • Vara värd fören enskild funktion i en funktionsapp: En isolerad Event Hubs-utlöst funktion minskar resursfördelningen mellan andra funktioner som körs, särskilt de som är processor- eller minnesintensiva. Den här fördelen beror på att varje funktion har sitt eget fotavtryck för minne och användningsmönster som direkt kan påverka skalan för funktionsappen som funktionerna körs i.

  • Separata lagringskonton för varje funktionsapp:Undvik att dela lagringskonton mellan funktionsappar. Använd inte heller samma lagringskonto som används för funktionsappen för andra lagringsåtgärder eller behov. Det är viktigt att använda separata lagringskonton eftersom Event Hubs utlösta funktioner potentiellt kan ha en stor mängd lagringstransaktioner på grund av kontrollpunkter.

  • Skapa en dedikerad konsumentgrupp för varje funktionsapp:I en strömbearbetningslösning motsvarar varje konsumentprogram en konsumentgrupp. En funktionsapp är ett bra exempel på ett konsumentprogram. Dela inte konsumentgrupper mellan funktionsappar och andra 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

Sammanfattningsvis bör varje funktionsapp uppfattas som ett distinkt program med en egen, tilldelad konsumentgrupp. Detta säkerställer förskjutningsintegriteten för varje konsument och förenklar beroenden i en arkitektur för händelseströmning. Den här konfigurationen tillsammans med att ge varje händelsehubbutlöst funktion en egen funktionsapp och ett lagringskonto hjälper till att skapa grunden för optimal prestanda och skalning.

Värdplaner för funktioner

Att granska hur funktioner skalar på olika planer är ett viktigt steg vid utvärdering av värdalternativ.

När du använder förbrukningsplanen har varje funktionsapp som standard en egen plan. Funktionsappar i förbrukningsplanen skalas oberoende och är mest effektiva när de undviker långvariga uppgifter.

Planerna Premium och Dedikerad används ofta som värd för flera funktionsappar och funktioner som är mer processor- och minnesintensiva. Observera att alla funktionsappar i dessa planer delar samma resurser som allokerats till planen. Om funktioner har olika inläsningsprofiler eller unika krav är det bäst att ha dem i olika planer. Detta gäller särskilt för program för dataströmbearbetning.

Event Hubs skalning

När det gäller en Event Hubs namnrymd finns det flera viktiga inställningar som måste utvärderas för att säkerställa högsta prestanda och skalning. Det här avsnittet fokuserar på standardnivån för Event Hubs och dess unika funktioner som påverkar skalning när de används med Azure 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.

Förstå dataflödesenheter

I Event Hubs standardnivån klassificeras dataflödet som den mängd data som matas in och läses från namnområdet inom en viss period. En dataflödesenhet (TU) är en mekanism som används för att både mäta och hantera hur mycket dataflöde en Event Hubs namnområdet stöder.

Som referens kan ett namnområde i Event Hubs jämföras med ett kluster i Kafka. En konceptuell mappning mellan Kafka och Event Hubs finns i den här tabellen.

Varje dataflödesenhet faktureras per timme och delas mellan alla händelsehubbbar i ett namnområde. Det innebär att alla program och tjänster, både utgivare och konsumenter, måste redovisas när du väljer antalet tilldelade TUs. Azure Functions påverkar antalet byte och händelser som både publiceras till och läses från en händelsehubb.

Betoningen för att fastställa antalet TUs är centrerad kring ingresspunkten. Men aggregeringen för konsumentprogrammen, inklusive frekvensen för bearbetningen av dessa händelser, måste också tas med i beräkningen.

Skala upp med automatisk uppskalning

Automatisk ökning kan aktiveras på en Event Hubs för att hantera scenarier där belastningen ökar utöver det konfigurerade antalet TUs. Detta ser till att begränsning från tjänsten inte sker och att bearbetningen, inklusive inmatning av händelser, kan fortsätta utan avbrott. Eftersom TUS:er är en av de viktiga inställningar som också påverkar kostnaderna kan du hantera problem med överetablering genom att dra nytta av funktionen automatisk blåsning.

Automatisk uppskalning är en unik funktion i Event Hubs som ofta förväxlas med autoskalning, särskilt inom ramen för serverlösa lösningar. Det är viktigt att observera att den här egenskapen i Event Hubs stöder ökning av TUs dynamiskt för att stödja burst-scenarier, men inte har en funktion för att tömma eller skala ned automatiskt.

För scenarier som kräver högt dataflöde och inte kan tillgodoses med det högsta tilldelade antalet TUs, bör du överväga Azure Event Hubs Premium eller Dedikerad kluster.

Partitioner och samtidiga funktioner

När en händelsehubb skapas måste antalet partitioner anges. Antalet partitioner är fast och kan inte ändras förutom från nivåerna PremiumDedikerad. När du Event Hubs utlösaren kan antalet samtidiga funktionsappinstanser potentiellt matcha antalet partitioner.

I Förbruknings- Premium-planer skalar funktionsappinstanserna ut dynamiskt för att uppfylla antalet partitioner när det behövs. Dedikerade App Service kräver att du manuellt konfigurerar dina instanser eller konfigurerar och autoskalningsschemat. Slutligen är en en-till-en-relation mellan antalet partitioner och funktionsappinstanser det perfekta målet för maximalt dataflöde i en lösning för dataströmbearbetning.

Optimal parallellitet uppnås genom att ha flera konsumenter i en konsumentgrupp. Det Azure Functions till exempel många instanser av en funktionsapp i planen. Resultatet kallas parallellitet på partitionsnivå eller maximal grad av parallellitet.

Maximal grad av parallellitet

Det kan till en början vara klokt att konfigurera så många partitioner som möjligt för att uppnå maximalt dataflöde och ta hänsyn till risken för en högre mängd händelser. Det finns dock flera viktiga faktorer som måste beaktas när många partitioner konfigureras:

  • 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 anvisat antal TUs för en händelsehubb med andra konsumentprogram.

  • Fler funktioner kan kräva mer minne: När antalet funktionsappinstanser ö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 konsumenterna.

  • Bakåttryck från underordnade tjänster: När mer dataflöde genereras kan risken för att överbelasta eller få tillbaka tryck från underordnade tjänster uppstå. Konsumentför fan-out måste tas med i beaktande när man överväger vilka konsekvenser det kan ha på de omgivande resurserna. Exempel kan vara begränsning från andra tjänster, nätverksmättnad och andra former av resursbegränsning som kan uppstå med ett ökat dataflöde.

  • Glesa ifyllda partitioner: Kombinationen av många partitioner och en låg mängd händelser kan leda till data som distribueras över partitioner. I stället kan ett mindre antal partitioner ge bättre prestanda och resursanvändning för Functions att använda.

Tillgänglighet och konsekvens

När ingen partitionsnyckel eller ID anges dirigerar Event Hubs 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 ordningen är viktig kan en specifik partition anges för att bevara ordningen på händelserna när de publiceras. Ett konsumentprogram som läser från samma partition kan sedan bearbeta händelserna i ordning. Den här kompromissen ger konsekvens men komprometterar tillgängligheten. Använd endast metoden när ordningen på händelser är ett krav.

För Functions uppnås ordningsföljd när händelser publiceras till en viss partition och en Event Hubs utlöst funktion erhåller ett lån till samma partition. För närvarande stöds inte möjligheten att konfigurera en partition Event Hubs en utdatabindning. I stället är en av Event Hubs-SDK:er den bästa metoden för publicering till en specifik partition.

En mer detaljerad förklaring av hur tillgänglighet och konsekvens stöds av Azure Event Hubs rekommenderar vi att du läser den här artikeln.

Event Hubs utlösare

Det här avsnittet fokuserar på de inställningar och överväganden som ingår vid optimering Event Hubs utlösta funktioner för högsta prestanda. Faktorer inkluderar batchbearbetning, sampling och relaterade funktioner som påverkar beteendet för en utlösarbindning för en händelsehubb.

Batchbearbetning

Funktioner som utlöses av händelsehubbb kan konfigureras för att bearbeta en samling händelser, eller en händelse i taget. Bearbetning av en batch med händelser är effektivare på grund av de kostnader som ingår för varje funktionsanrop. Såvida du inte bara behöver bearbeta en enskild händelse ska funktionen konfigureras för att bearbeta flera händelser när den anropas.

Hur du aktiverar batchbearbetning för Event Hubs-utlösarbindningen varierar mellan olika språk:

  • I C# konfigureras kardinaliteten automatiskt när en matris anges för typen i EventHubTrigger attributet.

  • JavaScript, Python och andra språk möjliggör batchbearbetning när kardinalitetsegenskapen är inställd på många i function.json-filen för funktionen.

Mer information om hur batchbearbetning är aktiverat finns i attribut- och anteckningsalternativen för varje språk som stöds.

Inställningar för utlösare

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

  • maxBatchSize: Den här inställningen representerar det maximala antalet händelser som funktionen tar emot när den anropas. Det är viktigt att känna till att detta inte är det minsta antalet händelser, bara det högsta. Om antalet händelser som tas emot är mindre än det här beloppet anropas funktionen fortfarande med så många händelser som är tillgängliga. Du kan inte ange den minsta batchstorleken.

  • prefetchCount: En av de viktigaste inställningarna när du optimerar för prestanda är antalet prefetch. Det här värdet refereras av den underliggande AMQP-kanalen 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 maxBatchSize värdet och är vanligtvis inställt på en multipel av den mängden. Om du ställer in det här värdet på ett tal maxBatchSize som är mindre än inställningen kan det påverka prestanda negativt.

  • batchCheckpointFrequency: När batchar bearbetas av funktionen används det här värdet för att fastställa med vilken hastighet en kontrollpunkt skapas. Som standard är det här värdet inställt på , vilket innebär att en kontrollpunkt skapas när en funktion 1 har bearbetar en batch. Tänk på att en kontrollpunkt skapas på partitionsnivå för varje läsare i konsumentgruppen. Det här intressanta blogginlägget ger ytterligare insikter om det beteende som den här inställningen kan introducera och hur den påverkar återuppspelningar och återförsök av händelser.

De värden som du anger för utlösarbindningen ska fastställas under loppet av flera prestandatester och iterationer. Vi rekommenderar att ändringar görs iterativt och mäts konsekvent för att finjustera dessa alternativ i enlighet med detta. Standardvärdena är ett försök att ge en startpunkt för de flesta lösningar för händelsebearbetning.

Kontrollpunkter

Det är viktigt att förstå begreppet kontrollpunkter för Event Hubs utlösta funktioner. Det är Functions-värdens ansvar att kontrollpunkt när händelser bearbetas och inställningen för batchkontrollpunktsfrekvensen uppfylls.

Följande begrepp är viktiga för att förstå relationen mellan kontrollpunkter och hur funktionen bearbetar händelser:

  • Undantag räknas fortfarande mot att lyckas: Om funktionsprocessen inte kraschar när händelser bearbetas anses slutförandet av funktionen som lyckad. Att fånga och hantera undantag bör fortfarande vara en försvarsmetod i funktionskoden. När det lyckas utvärderar Functions-värden inställningen för kontrollpunkten för batchfrekvens och skapar en kontrollpunkt om den har nåtts, oavsett vilka undantag som kan ha inträffat under bearbetningen.

  • Batchfrekvensen är viktig: I händelseströmningslösningar med stora volymer kan det vara fördelaktigt 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 hastigheten för när en kontrollpunkt skapas, vilket minskar antalet I/O-åtgärder till lagringskontot och ger högre prestanda.

  • Återuppspelningar kan ske: Varje gång en funktion anropas med Event Hubs-utlösarbindningen används den senaste kontrollpunkten för att avgöra var bearbetningen ska återupptas. Det har betonats att förskjutningen för varje konsument sparas på partitionsnivå för varje konsumentgrupp. Återuppspelningar inträffar när en kontrollpunkt inte inträffar under den senaste anropen av funktionen och den anropas igen. Mer information om dubbletter och dedupliceringstekniker finns i Idempotens i nästa artikel.

Det är viktigt att förstå kontrollpunkter när du överväger metodtips för felhantering och återförsök, vilket beskrivs i ett senare avsnitt i den här artikeln.

Telemetri-sampling

Azure Functions har inbyggt stöd för Application Insights. Med den här funktionen kan du samla in logg, prestanda och information om körningsundantag som inträffar i dina funktioner. Den här kraftfulla installationen erbjuder några viktiga konfigurationsalternativ som påverkar prestandan. Några av de viktiga 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. Granska funktionen för telemetrisampling i Application Insights för att undvika att försämra funktionens prestanda med onödiga telemetridata och mått.

  • Konfigurera sammansättningsinställningar: Granska och konfigurera hur ofta data aggregeras och skickas 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ål för version 1.x av Azure Functions-körningen lagrar den här inställningen anslutningssträngen till ett lagringskonto som används av Azure SDK för att behålla loggar för WebJobs-instrumentpanelen. Om Application Insights används till förmån för WebJobs-instrumentpanelen bör den här inställningen tas bort. Mer information finns i inställningsreferensen för AzureWebJobsDashboard.

Det är viktigt att nämna att när Application Insights är aktiverat utan sampling skickas alla telemetridata. Att skicka data om alla händelser kan ha en skadlig effekt på funktionens övergripande prestanda, särskilt under scenarier med händelseströmning med högt dataflöde.

Att dra nytta av sampling och kontinuerligt utvärdera lämplig mängd telemetri som behövs för övervakning är en av de många viktiga inställningar som är tillgängliga för optimala prestanda. Telemetri bör användas för allmän utvärdering av plattformshälsa i sammanställningen och för felsökning då och då, och inte för att samla in grundläggande affärsmått. Mer information finns i Konfigurera sampling.

Utdatabindning

Publicering till en händelseström från en funktion förenklas med hjälp av utdatabindningen för Event Hubs. Här är några av fördelarna med att använda den här bindningen:

  • Resurshantering:Bindningen hanterar både klient- och anslutningslivscyklerna åt dig. Detta minskar risken för problem som kan uppstå med portutmattning och hantering av anslutningspooler.

  • Mindre kod:Bindningen abstraherar den underliggande SDK:n och minskar mängden kod som behövs för att publicera händelser. Detta resulterar i kod som är enklare att skriva och underhålla.

  • Batchbearbetning:För flera språk stöds batchbearbetning för att effektivt publicera till en händelseström. Detta kan förbättra prestanda och effektivisera koden som skickar händelserna.

Vi rekommenderar starkt att du granskar listan över språk som stöds för Azure Functions respektive utvecklarguider. Avsnittet Bindningar för varje språk innehåller detaljerade exempel och dokumentation.

Batchbearbetning

Om funktionen bara publicerar en enda händelse är det vanligt att konfigurera bindningen med ett returvärde. Detta är användbart om funktionskörningen alltid slutar med en -instruktion som skickar händelsen. Att använda returvärdet är ett mönster som endast ska användas för synkrona funktioner som endast returnerar en händelse.

Batchbearbetning rekommenderas för att förbättra prestanda när du skickar flera händelser till en dataström. Med batchbearbetning kan bindningen publicera händelser på det mest effektiva sättet.

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

Mata ut flera händelser i C #

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

  • Metoden ICollector<T>.Add() kan användas i både synkrona och asynkrona funktioner. Den kör åtgärden lägg till så fort den anropas.

  • -metoden IAsyncCollector<T>.AddAsync() förbereder händelserna för publicering till händelseströmmen. Om du skriver en asynkron funktion bör du använda för att IAsyncCollector bättre hantera publicerade händelser.

Se dokumentationen för exempel på publicering av både enskilda och flera händelser med hjälp av C#.

Begränsning och bakåttryck

Begränsningsöverväganden gäller även för utdatabindning, inte bara för Event Hubs utan även för Azure-tjänster som Azure Cosmos DB. I allmänhet är det 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 fånga upp undantag från IAsyncCollector genom att omsluta AddAsync och FlushAsync i en undantagshanterare för .NET Azure Functions eller inte använda utdatabindningar och använda Event Hubs-SDK:er direkt.

Funktionskod

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

Asynkron programmering

Vi rekommenderar att din funktion använder icke-blockerande, asynkron kod. Detta är viktigt när I/O-anrop ingår.

När du överväger asynkron programmering i en funktion finns det några viktiga riktlinjer som bör följas:

  • Alla asynkrona eller alla synkrona: Om en funktion är konfigurerad för att köras asynkront bör även alla I/O-anrop vara asynkrona. I de flesta fall kan delvis asynkront vara sämre än kod som är helt synkron. Välj antingen asynkron eller synkron för implementeringen av funktionen och följ den hela vägen.

  • Undvik att blockera anrop: Blockerande anrop återgår till anroparen först när anropet har slutförts. Detta skiljer sig från asynkrona anrop som returneras omedelbart. Ett exempel i C# är att anropa Task.Result eller Task.Wait på en asynkron åtgärd.

Mer om att blockera anrop

När blockerande anrop görs på asynkrona åtgärder kan det leda till att trådpoolen blir utsvulten och att funktionsprocessen kraschar. Detta beror på att ett blockerande anrop 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äver det nu 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 krasch i funktionen inte uppdaterar kontrollpunkten. Nästa gång funktionen anropas kan den hamna i den här cykeln och verkar ha fastnat eller gå långsamt eftersom funktionskörningar kommer att få en time out.

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 öka antalet partitioner. Undersökningar kan också leda till att flera av batchbearbetningsalternativen ändras, till exempel maximal batchstorlek eller förinjningsantal. Intrycket är att det är ett dataflödesproblem eller en konfigurationsinställning som bara behöver justeras därefter. Huvudproblemet ligger dock i själva koden och måste åtgärdas där för en korrekt lösning.

Nästa steg

Innan du fortsätter bör du granska de här relaterade artiklarna: