Förbättra prestanda och tillförlitlighet för Azure Functions

Den här artikeln innehåller vägledning för att förbättra prestanda och tillförlitlighet för dina serverlösa funktionsappar. En mer allmän uppsättning Azure Functions bästa praxis finns i Azure Functions bästa praxis.

Följande är metodtips för hur du skapar och skapar serverlösa lösningar med hjälp av Azure Functions.

Undvik långvariga funktioner

Stora, långvariga funktioner kan orsaka oväntade timeout-problem. Mer information om tidsgränser för en viss värdplan finns i tidsgränsen för funktionsappen.

En funktion kan bli stor på grund av många Node.js beroenden. Import av beroenden kan också orsaka ökade inläsningstider som resulterar i oväntade timeouter. Beroenden läses in både explicit och implicit. En enskild modul som läses in av koden kan läsa in sina egna ytterligare moduler.

När det är möjligt omstrukturerar du stora funktioner till mindre funktionsuppsättningar som fungerar tillsammans och returnerar svar snabbt. En webhook- eller HTTP-utlösarfunktion kan till exempel kräva ett bekräftelsesvar inom en viss tidsperiod. det är vanligt att webhooks kräver ett omedelbart svar. Du kan skicka HTTP-utlösarens nyttolast till en kö som ska bearbetas av en köutlösarfunktion. Med den här metoden kan du skjuta upp det faktiska arbetet och returnera ett omedelbart svar.

Kontrollera att bakgrundsaktiviteterna har slutförts

När funktionen startar några uppgifter, återanrop, trådar, processer måste de slutföras innan funktionskoden returneras. Eftersom Functions inte spårar dessa bakgrundstrådar kan webbplatsavstängning ske oavsett bakgrundstrådsstatus, vilket kan orsaka oavsiktligt beteende i dina funktioner.

Om en funktion till exempel startar en bakgrundsaktivitet och returnerar ett lyckat svar innan aktiviteten slutförs, anser Functions-körningen att körningen har slutförts, oavsett resultatet av bakgrundsaktiviteten. Om den här bakgrundsaktiviteten utför viktigt arbete kan det föregripas av avstängning av webbplatsen, vilket gör att arbetet är i ett okänt tillstånd.

Kommunikation mellan funktioner

Durable Functions och Azure Logic Apps skapas för att hantera tillståndsövergångar och kommunikation mellan flera funktioner.

Om du inte använder Durable Functions eller Logic Apps för att integrera med flera funktioner är det bäst att använda lagringsköer för kommunikation mellan funktioner. Den främsta orsaken är att lagringsköer är billigare och mycket enklare att etablera än andra lagringsalternativ.

Enskilda meddelanden i en lagringskö är begränsade till 64 kB. Om du behöver skicka större meddelanden mellan funktioner kan en Azure Service Bus kö användas för att stödja meddelandestorlekar på upp till 256 kB på standardnivån och upp till 100 MB på Premium-nivån.

Service Bus-ämnen är användbara om du behöver meddelandefiltrering innan du bearbetar.

Händelsehubbar är användbara för att stödja kommunikation med stora volymer.

Skrivfunktioner som ska vara tillståndslösa

Funktionerna ska vara tillståndslösa och idempotent om det är möjligt. Koppla all nödvändig tillståndsinformation till dina data. Till exempel skulle en order som bearbetas sannolikt ha en associerad state medlem. En funktion kan bearbeta en ordning baserat på det tillståndet medan själva funktionen förblir tillståndslös.

Idempotent-funktioner rekommenderas särskilt med timerutlösare. Om du till exempel har något som absolut måste köras en gång om dagen skriver du det så att det kan köras när som helst under dagen med samma resultat. Funktionen kan avslutas när det inte finns något arbete för en viss dag. Om en tidigare körning inte kunde slutföras bör nästa körning fortsätta där den slutade. Detta är särskilt viktigt för meddelandebaserade bindningar som försöker igen vid fel. Mer information finns i Designa Azure Functions för identiska indata.

Skriva defensiva funktioner

Anta att funktionen kan stöta på ett undantag när som helst. Utforma dina funktioner med möjlighet att fortsätta från en tidigare felpunkt under nästa körning. Tänk dig ett scenario som kräver följande åtgärder:

  1. Fråga efter 10 000 rader i en databas.
  2. Skapa ett kömeddelande för var och en av dessa rader för att bearbeta längre ned på linjen.

Beroende på hur komplext ditt system är kan du ha: involverade underordnade tjänster som beter sig dåligt, nätverksstopp eller kvotgränser som nåtts osv. Alla dessa kan påverka din funktion när som helst. Du måste utforma dina funktioner för att vara förberedda för det.

Hur reagerar koden om ett fel inträffar när 5 000 av dessa objekt har infogats i en kö för bearbetning? Spåra objekt i en uppsättning som du har slutfört. Annars kan du infoga dem igen nästa gång. Den här dubbelinfogning kan ha en allvarlig inverkan på ditt arbetsflöde, så gör dina funktioner idempotenta.

Om ett köobjekt redan har bearbetats kan funktionen vara en no-op.

Dra nytta av de defensiva åtgärder som redan finns för komponenter som du använder i Azure Functions plattform. Se till exempel Hantera meddelanden om giftköer i dokumentationen för Azure Storage Queue-utlösare och bindningar.

För HTTP-baserade funktioner bör du överväga API-versionshanteringsstrategier med Azure API Management. Om du till exempel måste uppdatera din HTTP-baserade funktionsapp distribuerar du den nya uppdateringen till en separat funktionsapp och använder API Management revisioner eller versioner för att dirigera klienter till den nya versionen eller revisionen. När alla klienter använder versionen eller revisionen och inga fler körningar finns kvar i den tidigare funktionsappen kan du avetablera den tidigare funktionsappen.

Metodtips för funktionsorganisation

Som en del av din lösning kan du utveckla och publicera flera funktioner. Dessa funktioner kombineras ofta i en enda funktionsapp, men de kan också köras i separata funktionsappar. I Premium och dedikerade (App Service) värdplaner kan flera funktionsappar också dela samma resurser genom att köra i samma plan. Hur du grupperar dina funktioner och funktionsappar kan påverka prestanda, skalning, konfiguration, distribution och säkerhet för din övergripande lösning. Det finns inga regler som gäller för varje scenario, så tänk på informationen i det här avsnittet när du planerar och utvecklar dina funktioner.

Organisera funktioner för prestanda och skalning

Varje funktion som du skapar har ett minnesavtryck. Även om det här fotavtrycket vanligtvis är litet kan för många funktioner i en funktionsapp leda till långsammare start av appen på nya instanser. Det innebär också att den totala minnesanvändningen för funktionsappen kan vara högre. Det är svårt att säga hur många funktioner som ska finnas i en enda app, vilket beror på din specifika arbetsbelastning. Men om funktionen lagrar mycket data i minnet bör du överväga att ha färre funktioner i en enda app.

Om du kör flera funktionsappar i en enda Premium-plan eller dedikerad (App Service) plan delar alla dessa appar samma resurser som allokerats till planen. Om du har en funktionsapp som har ett mycket högre minneskrav än de andra använder den en oproportionerlig mängd minnesresurser på varje instans som appen distribueras till. Eftersom det här kan lämna mindre minne tillgängligt för de andra apparna på varje instans kanske du vill köra en funktionsapp med högt minne som den här i sin egen separata värdplan.

Anteckning

När du använder förbrukningsplanen rekommenderar vi att du alltid placerar varje app i en egen plan, eftersom apparna ändå skalas oberoende av varandra. Mer information finns i Flera appar i samma plan.

Överväg om du vill gruppera funktioner med olika belastningsprofiler. Om du till exempel har en funktion som bearbetar tusentals kömeddelanden och en annan som bara anropas ibland men har höga minneskrav, kanske du vill distribuera dem i separata funktionsappar så att de får sina egna uppsättningar resurser och de skalas oberoende av varandra.

Organisera funktioner för konfiguration och distribution

Funktionsappar har en host.json fil som används för att konfigurera avancerat beteende för funktionsutlösare och Azure Functions körning. Ändringar i host.json filen gäller för alla funktioner i appen. Om du har några funktioner som behöver anpassade konfigurationer kan du överväga att flytta dem till en egen funktionsapp.

Alla funktioner i ditt lokala projekt distribueras tillsammans som en uppsättning filer till din funktionsapp i Azure. Du kan behöva distribuera enskilda funktioner separat eller använda funktioner som distributionsplatser för vissa funktioner och inte andra. I sådana fall bör du distribuera dessa funktioner (i separata kodprojekt) till olika funktionsappar.

Organisera funktioner efter behörighet

Anslutningssträngar och andra autentiseringsuppgifter som lagras i programinställningarna ger alla funktioner i funktionsappen samma uppsättning behörigheter i den associerade resursen. Överväg att minimera antalet funktioner med åtkomst till specifika autentiseringsuppgifter genom att flytta funktioner som inte använder dessa autentiseringsuppgifter till en separat funktionsapp. Du kan alltid använda tekniker som funktionslänkning för att skicka data mellan funktioner i olika funktionsappar.

Metodtips för skalbarhet

Det finns ett antal faktorer som påverkar hur instanser av din funktionsapp skalas. Informationen finns i dokumentationen för funktionsskalning. Följande är några metodtips för att säkerställa optimal skalbarhet för en funktionsapp.

Dela och hantera anslutningar

Återanvänd anslutningar till externa resurser när det är möjligt. Se hur du hanterar anslutningar i Azure Functions.

Undvik att dela lagringskonton

När du skapar en funktionsapp måste du associera den med ett lagringskonto. Anslutningen till lagringskontot underhålls i programinställningen AzureWebJobsStorage.

Använd ett separat lagringskonto för varje funktionsapp för att maximera prestanda. Detta är särskilt viktigt när du har Durable Functions- eller Event Hub-utlösta funktioner, som båda genererar en stor mängd lagringstransaktioner. När din programlogik interagerar med Azure Storage, antingen direkt (med hjälp av Storage SDK) eller via en av lagringsbindningarna, bör du använda ett dedikerat lagringskonto. Om du till exempel har en händelsehubbutlöst funktion som skriver vissa data till bloblagring använder du två lagringskonton – ett för funktionsappen och ett annat för de blobar som lagras av funktionen.

Blanda inte test- och produktionskod i samma funktionsapp

Funktioner i en funktionsapp delar resurser. Till exempel delas minne. Om du använder en funktionsapp i produktion ska du inte lägga till testrelaterade funktioner och resurser i den. Det kan orsaka oväntade kostnader under körningen av produktionskoden.

Var försiktig med vad du läser in i dina produktionsfunktionsappar. Minnet beräknas i genomsnitt för varje funktion i appen.

Om du har en delad sammansättning som refereras i flera .NET-funktioner placerar du den i en gemensam delad mapp. Annars kan du av misstag distribuera flera versioner av samma binärfil som beter sig annorlunda mellan funktioner.

Använd inte utförlig loggning i produktionskod, vilket har en negativ prestandapåverkan.

Använd asynkron kod men undvik att blockera anrop

Asynkron programmering är en rekommenderad metod, särskilt när du blockerar I/O-åtgärder.

I C# ska du alltid undvika att Result referera till egenskapen eller anropa Wait metoden på en Task instans. Den här metoden kan leda till trådöverbelastning.

Tips

Om du planerar att använda HTTP- eller WebHook-bindningarna planerar du att undvika portöverbelastning som kan orsakas av felaktig instansiering av HttpClient. Mer information finns i Hantera anslutningar i Azure Functions.

Använda flera arbetsprocesser

Som standard använder alla värdinstanser för Functions en enda arbetsprocess. För att förbättra prestanda, särskilt med entrådade körningar som Python, använder du FUNCTIONS_WORKER_PROCESS_COUNT för att öka antalet arbetsprocesser per värd (upp till 10). Azure Functions försöker sedan fördela samtidiga funktionsanrop jämnt mellan dessa arbetare.

FUNCTIONS_WORKER_PROCESS_COUNT gäller för varje värd som Functions skapar när du skalar ut ditt program för att möta efterfrågan.

Ta emot meddelanden i batch när det är möjligt

Vissa utlösare som Event Hub gör det möjligt att ta emot en batch med meddelanden på ett enda anrop. Batchbearbetning av meddelanden har mycket bättre prestanda. Du kan konfigurera den maximala batchstorleken host.json i filen enligt beskrivningen i referensdokumentationen för host.json

För C#-funktioner kan du ändra typen till en starkt typifierad matris. I stället för EventData sensorEvent metodsignaturen kan till exempel vara EventData[] sensorEvent. För andra språk måste du uttryckligen ange kardinalitetsegenskapen i din function.json till many för att aktivera batchbearbetning enligt nedan.

Konfigurera värdbeteenden för att bättre hantera samtidighet

Filen host.json i funktionsappen möjliggör konfiguration av värdens körnings- och utlösarbeteenden. Förutom batchbearbetningsbeteenden kan du hantera samtidighet för ett antal utlösare. Om du ofta justerar värdena i de här alternativen kan varje instans skalas på rätt sätt för de anropade funktionernas krav.

Inställningarna i filen host.json gäller för alla funktioner i appen, i en enda instans av funktionen. Om du till exempel har en funktionsapp med två HTTP-funktioner och maxConcurrentRequests begäranden inställda på 25, räknas en begäran till någon AV HTTP-utlösare mot de delade 25 samtidiga begärandena. När funktionsappen skalas till 10 instanser tillåter de tio funktionerna effektivt 250 samtidiga begäranden (10 instanser * 25 samtidiga begäranden per instans).

Andra värdkonfigurationsalternativ finns i konfigurationsartikeln host.json.

Nästa steg

Mer information finns i följande resurser: