Design för elastiska eventhubbar och funktioner

Felhantering, design för idempotens och hantering av återförsöksbeteende är några av de kritiska å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 lösningar för händelseströmning.

Azure tillhandahåller tre huvudsakliga meddelandetjänster som kan användas med Azure Functions för att stödja en mängd unika, händelsedrivna scenarier. På grund av dess partitionerade konsumentmodell och möjligheten att mata in data med hög hastighet används Azure Event Hubs ofta för händelseströmning och stordatascenarier. En detaljerad jämförelse av Azures meddelandetjänster finns i Välj mellan Azure-meddelandetjänster – Event Grid, Event Hubs och Service Bus.

Fördelar och utmaningar med strömning

Genom att förstå fördelarna och nackdelarna med strömmar kan du uppskatta hur en tjänst som Event Hubs fungerar. Du behöver också den här kontexten när du fattar viktiga arkitektoniska beslut, felsöker problem och optimerar prestanda. Tänk på följande viktiga begrepp om lösningar med både Event Hubs och Functions:

  • Strömmar är inte köer: Event Hubs, Kafka och andra liknande erbjudanden som bygger på den partitionerade konsumentmodellen stöder inte i sig några av huvudfunktionerna i en asynkron meddelandekö som Service Bus. Den kanske största indikatorn på detta är det faktum att läsningar är icke-destruktiva. Det innebär att de data som läss av Functions-värden inte tas bort efteråt. I stället är meddelanden oföränderliga och förblir för andra konsumenter att läsa, inklusive potentiellt samma kund som läser det igen. Därför är lösningar som implementerar mönster som konkurrerande konsumenter bättre lämpade för en traditionell meddelandekö.

  • Stöd för inbyggda obeställbara meddelanden saknas: En kanal med obeställbara meddelanden är inte en inbyggd funktion i Event Hubs eller Kafka. Ofta integreras begreppet obeställbara meddelanden 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 medfödd element i Event Hubs och läggs bara till på konsumentsidan för att tillverka ett liknande beteende eller en liknande effekt. Om du behöver stöd för obeställbara meddelanden bör du eventuellt granska ditt val av strömmande meddelandetjänst.

  • En arbetsenhet är en partition: I en traditionell meddelandekö är en arbetsenhet ett enda meddelande. I en strömningslösning betraktas en partition ofta som en 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 ekonomisk transaktion är det troligtvis en indikation på att fel meddelandetjänst används.

  • Ingen filtrering på serversidan: En av anledningarna till att Event Hubs kan ha enorm skala och dataflöde beror på den låga belastningen på själva tjänsten. Funktioner som filtrering på serversidan, index och samordning mellan asynkrona meddelandeköer ingår inte i arkitekturen för Event Hubs. Funktioner används ibland för att filtrera händelser genom att dirigera dem till andra händelsehubbar baserat på innehållet i brödtexten eller rubriken. Den här metoden är vanlig i händelseströmning, men den kommer med en varning om att varje händelse läse och utvärderas av den första funktionen.

  • Alla läsare måste läsa alla data: Eftersom filtrering på serversidan inte är tillgänglig läser en konsument sekventiellt alla data i en partition. Detta omfattar data som kanske inte är relevanta eller som till och med kan vara felaktiga. Det finns flera alternativ och till och med strategier som kan användas för att kompensera för dessa utmaningar som kommer att tas upp senare i det här avsnittet.

Dessa viktiga designbeslut gör det möjligt för Event Hubs att göra det de gör bäst: stödja ett betydande inflöde av händelser och tillhandahålla en robust och motståndskraftig tjänst som konsumenter kan läsa från. Varje konsumentprogram har till uppgift att underhålla sina egna förskjutningar på klientsidan eller markören till dessa händelser. Den låga kostnaden gör Event Hubs till ett prisvärt och kraftfullt alternativ för händelseströmning.

Idempotens

En av grundsatserna i 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, till och med upprepade gånger, av konsumenter, till exempel en funktion. Därför är det viktigt att en händelsehubbutlöst funktion stöder konsumentmönstret idempotent .

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 tillförlitlig bearbetning av händelser. 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.

Duplicerade hä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 tröskelvärdet 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.

  • Dubbletthändelser publicerade: Det finns många tekniker som kan minska risken för att samma händelse publiceras till en ström, men det är fortfarande konsumentens ansvar att hantera dubbletter på ett idempotent sätt.

  • Saknade bekräftelser: 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 leda till uppfattningen att det utgående anropet misslyckades och initiera en serie eller återförsök eller andra resultat från funktionen. I slutändan kan dubbletthändelser publiceras eller så skapas inte en kontrollpunkt.

Dedupliceringstekniker

Att utforma dina funktioner för identiska indata bör vara den standardmetod som används när du parkopplas med händelsehubbens utlösarbindning. Du bör överväga följande tekniker:

  • Letar du efter dubbletter: Innan du bearbetar 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 dataaktualitet eller logik som ogiltigförklarar händelsen.

  • Utforma händelser för idempotens: Genom att tillhandahålla ytterligare information inom nyttolasten för händelsen kan det vara möjligt att säkerställa att bearbetningen flera gånger inte får några skadliga effekter. Ta exemplet med en händelse som innehåller ett belopp för uttag 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 för kontot kan den användas för att utföra en upsert-åtgärd till bankkontosaldot. Denna metod för överföring av händelseförsenad stat kräver ibland samordning mellan producenter och konsumenter och bör användas när det är meningsfullt att delta i tjänster.

Felhantering och återförsök

Felhantering och återförsök är några av de viktigaste egenskaperna för distribuerade, händelsedrivna program och Funktioner är inget undantag. För händelseströmningslösningar är behovet av korrekt stöd för felhantering avgörande, eftersom tusentals händelser snabbt kan omvandlas till lika många 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 viss 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. Tänk på 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 upp, logga och identifiera förväntade och ohanterade undantag i funktionskoden. Använd till exempel ett try/catch-block i C#, Java och JavaScript och dra nytta av try- och except-blocken 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 och ignorera undantag: En av de värsta sakerna 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

Implementering av omprövningslogik i en arkitektur för händelseströmning kan vara komplext. Stöd för annulleringstoken, antal återförsök och exponentiella backoff-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öra många av de här uppgifterna som du vanligtvis kodar själv.

Flera viktiga faktorer som måste beaktas när du använder återförsöksprinciperna med Event Hub-bindningen är:

  • Undvik obegränsade återförsök: När inställningen för maximalt antal återförsök har angetts till värdet -1 försöker funktionen igen på obestämd tid. I allmänhet bör obegränsade återförsök användas sparsamt med Functions och nästan aldrig med Event Hub-utlösarbindningen.

  • Välj lämplig strategi för återförsök: En strategi med fast fördröjning kan vara optimal för scenarier som får tillbaka tryck från andra Azure-tjänster. I dessa fall kan fördröjningen bidra till att undvika begränsningar och andra begränsningar som påträffas från dessa tjänster. Strategin för exponentiell backoff ger större flexibilitet för intervall för återförsöksfördröjning och används ofta när du integrerar 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 kan du försöka upprätthålla ett återförsöksintervall som är 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-förbrukningsplanen.

  • Kretsbrytarmönster: Ett tillfälligt fel från tid till tidpunkt förväntas 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 bra att stoppa funktionen, åtgärda problemen och starta om senare.

Ett viktigt tips för återförsöksprinciperna i Functions är att det är en funktion för bästa förmåga att ombearbeta händelser. Den ersätter inte behovet av felhantering, loggning och andra viktiga mönster som ger återhämtning i koden.

Strategier för fel och skadade data

Det finns flera anmärkningsvärda metoder som du kan använda för att kompensera för problem som uppstår på grund av fel eller felaktiga data i en händelseström. Några grundläggande strategier är:

  • Sluta skicka och läsa: Pausa läsning 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ärderna kan återupptas när en korrigering har distribuerats. Den här metoden kan kräva en kretsbrytarkomponent 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 anses vara 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 inspelning av rörelser i en schackmatch eller finansbaserade 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 motivera 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.

  • Obeställbara bokstäver: 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 vägen och kan hanteras senare eller av en annan process. Den här lösningen används ofta för hantering av förgiftade meddelanden 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 dem på ett ansvarsfullt sätt.

  • Försök igen och obeställbara bokstäver: Kombinationen av många återförsök innan du slutligen publicerar till en dataström med obeställbara meddelanden 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 kan stödja övergången av scheman tillsammans med versionshantering och olika kompatibilitetslägen när 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 med var och en av strategierna måste undersökas noggrant. Baserat på kraven kan det bästa sättet att använda flera av dessa tekniker tillsammans vara.

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: