Dela via


Varför strömmar in Orleans?

Det finns redan en mängd olika tekniker som gör att du kan skapa dataströmbearbetningssystem. Dessa omfattar system som durably lagrar dataströmmar (t.ex. Event Hubs och Kafka) och system för att uttrycka beräkningsåtgärder över dataström (t.ex. Azure Stream Analytics, Apache Storm och Apache Spark Streaming). Det är bra system som gör att du kan skapa effektiva dataströmbearbetningspipelines.

Begränsningar i befintliga system

Dessa system är dock inte lämpliga för detaljerad friformsberäkning över dataströmmar. Med de beräkningssystem för direktuppspelning som nämns ovan kan du ange ett enhetligt dataflödesdiagram över åtgärder som tillämpas på samma sätt för alla dataströmobjekt. Det här är en kraftfull modell när data är enhetliga och du vill uttrycka samma uppsättning transformerings-, filtrerings- eller aggregeringsåtgärder över dessa data. Men det finns andra användningsfall där du behöver uttrycka fundamentalt olika åtgärder jämfört med olika dataobjekt. Och i vissa av dem som en del av den här bearbetningen måste du ibland göra ett externt anrop, till exempel anropa några godtyckliga REST API. De enhetliga dataflödesströmbearbetningsmotorerna stöder antingen inte dessa scenarier, stöder dem på ett begränsat och begränsat sätt eller är ineffektiva när det gäller att stödja dem. Detta beror på att de i sig är optimerade för en stor mängd liknande objekt, och vanligtvis begränsade när det gäller uttrycksfullhet, bearbetning. OrleansFlöden rikta in sig på dessa andra scenarier.

Motivation

Allt började med begäranden från Orleans användare om stöd för att returnera en sekvens med objekt från ett kornmetodanrop. Som du kan föreställa dig var det bara toppen av isberget. De behövde mycket mer än så.

Ett typiskt scenario för Orleans Flöden är när du har dataströmmar per användare och vill utföra olika bearbetningar för varje användare, inom ramen för en enskild användare. Vi kanske har miljontals användare, men vissa av dem är intresserade av väder och kan prenumerera på vädervarningar för en viss plats, medan vissa är intresserade av sportevenemang; någon annan spårar statusen för en viss flygning. Bearbetning av dessa händelser kräver olika logik, men du vill inte köra två oberoende instanser av dataströmbearbetning. Vissa användare är bara intresserade av ett visst lager och endast om ett visst externt villkor gäller, ett villkor som kanske inte nödvändigtvis är en del av dataströmmen (och därför måste kontrolleras dynamiskt vid körning som en del av bearbetningen).

Användarna ändrar sina intressen hela tiden, därför ändras deras prenumerationer till specifika strömmar av händelser dynamiskt, vilket innebär att strömningstopologin ändras dynamiskt och snabbt. Dessutom utvecklas och ändras bearbetningslogik per användare dynamiskt, baserat på användartillstånd och externa händelser. Externa händelser kan ändra bearbetningslogik för en viss användare. I ett system för identifiering av spelfusk måste till exempel bearbetningslogik uppdateras med den nya regeln för att identifiera den nya överträdelsen när ett nytt sätt att fuska identifieras. Detta måste naturligtvis göras utan att störa den pågående bearbetningspipelinen. Dataflödesbearbetningsmotorer för massflöde har inte skapats för att stödja sådana scenarier.

Det säger sig nästan utan att säga att ett sådant system måste köras på flera nätverksanslutna datorer, inte på en enda nod. Därför måste bearbetningslogik distribueras på ett skalbart och elastiskt sätt över ett kluster med servrar.

Nya krav

Vi har identifierat fyra grundläggande krav för vårt Stream Processing-system som gör att det kan rikta in sig på ovanstående scenarier.

  1. Flexibel dataströmbearbetningslogik
  2. Stöd för mycket dynamiska topologier
  3. Detaljerad dataströmskornighet
  4. Distribution

Flexibel dataströmbearbetningslogik

Vi vill att systemet ska stödja olika sätt att uttrycka dataströmbearbetningslogik. De befintliga system som vi nämnde ovan kräver att utvecklaren skriver ett deklarativt dataflödesberäkningsdiagram, vanligtvis genom att följa ett funktionellt programmeringsformat. Detta begränsar bearbetningslogikernas uttryckskraft och flexibilitet. Orleans strömmar är likgiltiga för hur bearbetningslogik uttrycks. Det kan uttryckas som ett dataflöde (till exempel genom att använda reaktiva tillägg (Rx) i .NET); som ett funktionellt program, som en deklarativ fråga eller i en allmän imperativ logik. Logiken kan vara tillståndskänslig eller tillståndslös, kan eller kanske inte har biverkningar och kan utlösa externa åtgärder. All kraft går till utvecklaren.

Stöd för dynamiska topologier

Vi vill att systemet ska tillåta dynamiskt utvecklande topologier. De befintliga system som vi nämnde ovan är vanligtvis begränsade till endast statiska topologier som är fasta vid distributionen och inte kan utvecklas vid körning. I följande exempel på ett dataflödesuttryck är allt trevligt och enkelt tills du behöver ändra det.

Stream.GroupBy(x=> x.key).Extract(x=>x.field).Select(x=>x+2).AverageWindow(x, 5sec).Where(x=>x > 0.8) *

Ändra tröskelvärdet i Where filtret, lägg till Select instruktionen eller lägg till en annan gren i dataflödesdiagrammet och skapa en ny utdataström. I befintliga system är detta inte möjligt utan att ta bort hela topologin och starta om dataflödet från grunden. I praktiken kommer dessa system att kontrollera den befintliga beräkningen och kommer att kunna startas om från den senaste kontrollpunkten. Ändå är en sådan omstart störande och kostsam för en onlinetjänst som ger resultat i realtid. En sådan omstart blir särskilt opraktisk när vi talar om ett stort antal sådana uttryck som körs med liknande men olika parametrar (per användare, per enhet osv.) och som ändras kontinuerligt.

Vi vill att systemet ska kunna utveckla dataströmbearbetningsdiagrammet vid körning, genom att lägga till nya länkar eller noder i beräkningsdiagrammet eller genom att ändra bearbetningslogik i beräkningsnoderna.

Detaljerad dataströmskornighet

I de befintliga systemen är den minsta abstraktionsenheten vanligtvis hela flödet (topologi). Många av våra målscenarier kräver dock att en enskild nod/länk i topologin är en logisk entitet på egen hand. På så sätt kan varje entitet hanteras oberoende av varandra. I den stora strömtopologin som består av flera länkar kan till exempel olika länkar ha olika egenskaper och kan implementeras över olika fysiska transporter. Vissa länkar kan gå över TCP-socketar, medan andra över tillförlitliga köer. Olika länkar kan ha olika leveransgarantier. Olika noder kan ha olika kontrollpunktsstrategier och deras bearbetningslogik kan uttryckas i olika modeller eller till och med olika språk. Sådan flexibilitet är vanligtvis inte möjlig i befintliga system.

Abstraktions- och flexibilitetsargumentet liknar en jämförelse av SoA (tjänstorienterade arkitekturer) jämfört med aktörer. Aktörssystem ger större flexibilitet eftersom varje aktör i huvudsak är en oberoende hanterad "liten tjänst". På samma sätt vill vi att strömsystemet ska tillåta sådan detaljerad kontroll.

Distribution

Och naturligtvis bör vårt system ha alla egenskaper för ett "bra distribuerat system". Det omfattar:

  1. Skalbarhet – stöder ett stort antal strömmar och beräkningselement.
  2. Elasticitet – gör det möjligt att lägga till/ta bort resurser för att växa/krympa baserat på belastning.
  3. Tillförlitlighet – vara motståndskraftiga mot fel
  4. Effektivitet – använd de underliggande resurserna effektivt
  5. Svarstider – aktivera scenarier i nära realtid.

Det här var de krav som vi hade i åtanke för att skapa Orleans strömning.

Förtydligande: Orleans stöder för närvarande inte direkt skrivning av deklarativa dataflödesuttryck som i exemplet ovan. De aktuella Orleans API:erna för direktuppspelning är fler byggstenar på låg nivå, enligt beskrivningen här. Att tillhandahålla deklarativa dataflödesuttryck är vårt framtida mål.

Se även

OrleansFlöden programmerings-API:er