Elastisk Event Hubs och Functions-design
Felhantering, design för idempotens och hantering av återförsöksbeteende är några av de viktiga åtgärder som du kan vidta för att säkerställa att Event Hubs utlösta funktioner är motståndskraftiga och kan hantera stora mängder data. Den här artikeln beskriver dessa viktiga begrepp och ger rekommendationer för serverlösa händelseströmningslösningar.
Azure tillhandahåller tre huvudsakliga meddelandetjänster som kan användas med Azure Functions för att stödja en mängd olika unika, händelsedrivna scenarier. På grund av den partitionerade konsumentmodellen och möjligheten att mata in data med hög hastighet Azure Event Hubs ofta för händelseströmning och stordatascenarier. En detaljerad jämförelse av Azures meddelandetjänster finns i Välja mellan Azure-meddelandetjänster – Event Grid, Event Hubs och Service Bus.
Fördelar och utmaningar med direktuppspelning
Genom att förstå fördelarna och nackdelarna med dataströmmar kan du uppskatta hur en tjänst Event Hubs fungerar. Du behöver även den här kontexten när du fattar effektfulla arkitekturbeslut, felsöker problem och optimerar prestanda. Tänk på följande viktiga begrepp om lösningar med både Event Hubs och Functions:
Flöden inte är köer: Event Hubs, Kafka och andra liknande erbjudanden som bygger på den partitionerade konsumentmodellen har inte inbyggt stöd för vissa av huvudfunktionerna i en autjämnare för meddelanden som Service Bus. Den kanske största indikatorn på detta är att läsningar är icke-destruktiva. Det innebär att de data som läses av Functions-värden inte tas bort efteråt. Meddelanden är i stället oföränderliga och finns kvar för andra konsumenter att läsa, inklusive potentiellt samma kund som läser det igen. Därför passar lösningar som implementerar mönster som konkurrerande konsumenter bättre för en traditionell meddelandekoordinator.
Saknar ärvt stöd för uteblivna brev: En kanal utan bokstav är inte en inbyggd funktion i Event Hubs eller Kafka. Konceptet med dead lettering integreras ofta i en strömningslösning för att ta hänsyn till data som inte kan bearbetas. Den här funktionen är avsiktligt inte ett innate-element i Event Hubs och läggs endast till på konsumentsidan för att tillverkar ett liknande beteende eller en liknande effekt. Om du behöver stöd för meddelanden utan meddelanden bör du eventuellt granska ditt val av strömmande meddelandetjänst.
En arbetsenhet är en partition: I en traditionell a broker är en arbetsenhet ett enda meddelande. I en strömningslösning betraktas en partition ofta som arbetsenhet. Om varje händelse i en händelsehubb betraktas som ett diskret meddelande som kräver att den behandlas som en orderbearbetningsåtgärd eller en finansiell transaktion, är det mest sannolikt en indikation på fel meddelandetjänst som används.
Ingen filtrering på serversidan: En av orsakerna Event Hubs kan skalas enormt och dataflödet beror på den låga belastningen på själva tjänsten. Funktioner som filtrering på serversidan, index och samordning mellan koordinatorer är inte en del av arkitekturen för Event Hubs. Funktioner används ibland för att filtrera händelser genom att dirigera dem till Event Hubs baserat på innehållet i brödtexten eller rubriken. Den här metoden är vanlig i händelseströmning, men den innebär att varje händelse läses och utvärderas av den inledande funktionen.
Varje läsare måste läsa alla data: Eftersom filtrering på serversidan inte är tillgängligt läser konsumenten sekventiellt alla data i en partition. Detta omfattar data som kanske inte är relevanta eller till och med kan vara felaktiga. Det finns flera alternativ och även strategier som kan användas för att kompensera för dessa utmaningar som tas upp senare i det här avsnittet.
Dessa viktiga designbeslut gör att Event Hubs kan göra det den gör bäst: stödja en betydande mängd händelser och tillhandahålla en robust och motståndskraftig tjänst som konsumenter kan läsa från. Varje konsumentprogram ansvarar för att underhålla sina egna förskjutningar på klientsidan eller markörer för dessa händelser. Den låga omkostnaderna gör Event Hubs ett prisvärt och kraftfullt alternativ för händelseströmning.
Idempotens
En av grundprinciperna för Azure Event Hubs är begreppet leverans minst en gång. Den här metoden säkerställer att händelser alltid levereras. Det innebär också att händelser kan tas emot mer än en gång, även upprepade gånger, av konsumenter som en funktion. Därför är det viktigt att en funktion som utlöses av en händelsehubb stöder idempotenta konsumentmönster.
Att arbeta under antagandet om leverans minst en gång, särskilt inom ramen för en händelsedriven arkitektur, är en ansvarsfull metod för att bearbeta händelser på ett tillförlitligt sätt. Din funktion måste vara idempotent så att resultatet av bearbetningen av samma händelse flera gånger är detsamma som att bearbeta den en gång.
Dubbletthändelser
Det finns flera olika scenarier som kan resultera i att dubbletthändelser levereras till en funktion:
Kontrollpunkter: Om Azure Functions värd kraschar, eller om det tröskelvärde som angetts för batchkontrollpunktsfrekvensen inte uppfylls, skapas ingen kontrollpunkt. Därför är förskjutningen för konsumenten inte avancerad och nästa gång funktionen anropas återupptas den från den senaste kontrollpunkten. Det är viktigt att observera att kontrollpunkter sker på partitionsnivå för varje konsument.
Duplicerade händelser publicerade: Det finns många tekniker som kan minska risken för att samma händelse publiceras till en dataström, men det är fortfarande konsumentens ansvar att idempotent hantera dubbletter.
Bekräftelser saknas: I vissa situationer kan en utgående begäran till en tjänst lyckas, men en bekräftelse (ACK) från tjänsten tas aldrig emot. Detta kan resultera i uppfattningen att det utgående anropet misslyckades och initierar en serie, återförsök eller andra resultat från funktionen. I slutändan kan duplicerade händelser publiceras, eller så skapas ingen kontrollpunkt.
Dedupliceringstekniker
Att designa dina funktioner för identiska indata ska vara standardinställningen när du kopplar ihop dem med händelsehubbens utlösarbindning. Du bör tänka på följande tekniker:
Letar efter dubbletter: Innan bearbetningen bör du vidta nödvändiga åtgärder för att verifiera att händelsen ska bearbetas. I vissa fall kräver detta en undersökning för att bekräfta att den fortfarande är giltig. Det kan också vara möjligt att hanteringen av händelsen inte längre behövs på grund av data freshness eller logik som gör händelsen ogiltig.
Utforma händelser för idempotens: Genom att tillhandahålla ytterligare information i händelsens nyttolast kan det vara möjligt att säkerställa att bearbetningen av den flera gånger inte har några skadliga effekter. Ta ett exempel på en händelse som innehåller ett belopp som ska dras från ett bankkonto. Om det inte hanteras på ett ansvarsfullt sätt är det möjligt att det kan minska saldot för ett konto flera gånger. Men om samma händelse innehåller det uppdaterade saldot till kontot kan den användas för att utföra en upsert-åtgärd till bankkontosaldot. Den här metoden för överföring av händelsebaserade tillstånd kräver ibland samordning mellan producenter och konsumenter och bör användas när det är meningsfullt för deltagande tjänster.
Felhantering och återförsök
Felhantering och återförsök är några av de viktigaste egenskaperna hos distribuerade, händelsedrivna program och funktioner är inget undantag. För händelseströmningslösningar är behovet av rätt stöd för felhantering avgörande, eftersom tusentals händelser snabbt kan omvandlas till ett lika stort antal fel om de inte hanteras korrekt.
Vägledning för felhantering
Utan felhantering kan det vara svårt att implementera återförsök, identifiera körningsundantag och undersöka problem. Varje funktion bör ha minst en nivå eller felhantering. Några rekommenderade riktlinjer är:
Använd Application Insights: Aktivera och använda Application Insights för att logga fel och övervaka hälsotillståndet för dina funktioner. Ha i åtanke de konfigurerbara samplingsalternativen för scenarier som bearbetar en stor mängd händelser.
Lägg till strukturerad felhantering: Använd lämpliga felhanteringskonstruktioner för varje programmeringsspråk för att fånga, logga och identifiera förväntade och ohanterade undantag i funktionskoden. Du kan till exempel använda ett try/catch-block i C#, Java och JavaScript och dra nytta av try och except block i Python för att hantera undantag.
Loggning: Genom att fånga ett undantag under körningen kan du logga viktig information som kan användas för att identifiera, återskapa och åtgärda problem på ett tillförlitligt sätt. Logga undantaget, inte bara meddelandet, utan även brödtexten, det inre undantaget och andra användbara artefakter som kan vara till hjälp senare.
Fånga inte upp och ignorera undantag: En av de värsta saker du kan göra är att fånga ett undantag och inte göra något med det. Om du får ett allmänt undantag loggar du det någonstans. Om du inte loggar fel är det svårt att undersöka buggar och rapporterade problem.
Antal försök
Det kan vara komplicerat att implementera logik för omprövning i en arkitektur för händelseströmning. Stöd för annulleringstoken, antal omförsök och exponentiell back off-strategier är bara några av de överväganden som gör det svårt. Lyckligtvis tillhandahåller Functions återförsöksprinciper som kan utgör för många av dessa uppgifter som du normalt kodar själv.
Flera viktiga faktorer som måste beaktas när du använder återförsöksprinciperna med händelsehubbens bindning är:
Undvik obegränsade återförsök: När inställningen för maximalt antal återförsök har angetts till värdet -1 kommer funktionen att försöka på nytt på obestämd tid. I allmänhet bör obegränsade omförsök användas sparsamt med Functions och nästan aldrig med händelsehubbens utlösarbindning.
Välj lämplig strategi för återförsök: En fast fördröjningsstrategi kan vara optimal för scenarier som får tillbaka tryck från andra Azure-tjänster. I dessa fall kan fördröjningen hjälpa till att undvika begränsning och andra begränsningar som uppstår från dessa tjänster. Den exponentiella back off-strategin ger större flexibilitet för intervall för återförsöksfördröjning och används ofta vid integrering med tjänster från tredje part, REST-slutpunkter och andra Azure-tjänster.
Håll intervallen och antalet återförsök lågt: När det är möjligt bör du försöka hålla återförsöksintervallet kortare än en minut. Behåll också det maximala antalet återförsök till ett någorlunda lågt antal. De här inställningarna är särskilt relevanta när du kör i functions consumption-planen.
Kretsbrytarmönster: Ett tillfälligt fel förväntas då och då och ett naturligt användningsfall för återförsök. Men om ett stort antal fel eller problem inträffar under bearbetningen av funktionen kan det vara klokt att stoppa funktionen, åtgärda problemen och starta om senare.
En viktig del av återförsöksprinciperna i Functions är att det är en funktion för ombearbetning av händelser. Den ersätter inte behovet av felhantering, loggning och andra viktiga mönster som ger återhämtning för din kod.
Strategier för fel och skadade data
Det finns flera viktiga metoder som du kan använda för att kompensera för problem som uppstår på grund av fel eller dåliga data i en händelseström. Några grundläggande strategier är:
Sluta skicka och läsa: Pausa läsningen och skrivning av händelser för att åtgärda det underliggande problemet. Fördelen med den här metoden är att data inte går förlorade och att åtgärder kan återupptas när en korrigering har distribuerats. Den här metoden kan kräva en kretsbrytare i arkitekturen och eventuellt ett meddelande till de berörda tjänsterna för att uppnå en paus. I vissa fall kan det vara nödvändigt att stoppa en funktion tills problemen har lösts.
Ta bort meddelanden: Om meddelanden inte är viktiga eller betraktas som icke-verksamhetskritiska kan du överväga att gå vidare och inte bearbeta dem. Detta fungerar inte för scenarier som kräver stark konsekvens, till exempel registrering av förflyttningar i en matchad match eller ekonomibaserade transaktioner. Felhantering i en funktion rekommenderas för att fånga och släppa meddelanden som inte kan bearbetas.
Igen: Det finns många situationer som kan berättiga till ombearbetning av en händelse. Det vanligaste scenariot är ett tillfälligt fel som uppstår när en annan tjänst eller ett beroende anropas. Nätverksfel, tjänstbegränsningar och tillgänglighet och stark konsekvens är kanske de vanligaste användningsfallen som motiverar ombearbetningsförsök.
Död bokstav: Tanken här är att publicera händelsen till en annan händelsehubb så att det befintliga flödet inte avbryts. Uppfattningen är att den har flyttats från den heta sökvägen och kan hanteras senare eller av en annan process. Den här lösningen används ofta för att hantera skadligt meddelande eller händelser. Det bör noteras att varje funktion, som är konfigurerad med en annan konsumentgrupp, fortfarande stöter på felaktiga eller skadade data i dataströmmen och måste hantera den på ett ansvarsfullt sätt.
Försök igen och dead letter: Kombinationen av flera återförsök innan du slutligen publicerar till en dataström med en dead letter när ett tröskelvärde har uppnåtts är en annan välbekant metod.
Använd ett schemaregister: Ett schemaregister kan användas som ett proaktivt verktyg för att förbättra konsekvens och datakvalitet. Azure Schema Registry har stöd för övergången av scheman samt versionshantering och olika kompatibilitetslägen allt eftersom scheman utvecklas. I grunden fungerar schemat som ett kontrakt mellan producenter och konsumenter, vilket kan minska risken för att ogiltiga eller skadade data publiceras till dataströmmen.
I slutändan finns det ingen perfekt lösning och konsekvenserna och kompromisserna för var och en av strategierna måste undersökas noggrant. Baserat på kraven kan det vara den bästa metoden att använda flera av dessa tekniker tillsammans.
Nästa steg
Innan du fortsätter bör du granska de här relaterade artiklarna:
- Azure Functions tillförlitlig händelsebearbetning
- Designa Azure Functions för identiska indata
- Azure Functions felhantering och vägledning för återförsök
Relaterade resurser
- Övervakning av serverlös händelsebearbetning ger vägledning om övervakning av serverlösa händelsedrivna arkitekturer.
- Serverlös händelsebearbetning är en referensarkitektur som beskriver en typisk arkitektur av den här typen, med kodexempel och diskussion om viktiga överväganden.
- Avbatchning och filtrering i serverlös händelsebearbetning med Event Hubs beskriver i detalj hur dessa delar av referensarkitekturen fungerar.