Händelser
17 mars 21 - 21 mars 10
Gå med i mötesserien för att skapa skalbara AI-lösningar baserat på verkliga användningsfall med andra utvecklare och experter.
Registrera dig nuDen här webbläsaren stöds inte längre.
Uppgradera till Microsoft Edge och dra nytta av de senaste funktionerna och säkerhetsuppdateringarna, samt teknisk support.
Orleans 7.0 introducerar flera fördelaktiga ändringar, inklusive förbättringar av värdtjänster, anpassad serialisering, oföränderlighet och kornabstraktioner.
Befintliga program som använder påminnelser, strömmar eller kornbeständighet kan inte enkelt migreras till Orleans 7.0 på grund av ändringar i hur Orleans identifierar korn och strömmar. Vi planerar att stegvis erbjuda en migreringssökväg för dessa program.
Program som kör tidigare versioner av Orleans kan inte uppgraderas smidigt via en löpande uppgradering till Orleans 7.0. Därför måste en annan uppgraderingsstrategi användas, till exempel att distribuera ett nytt kluster och inaktivera det tidigare klustret. Orleans 7.0 ändrar trådprotokollet på ett inkompatibelt sätt, vilket innebär att kluster inte kan innehålla en blandning av Orleans 7.0-värdar och värdar som kör tidigare versioner av Orleans.
Vi har undvikit sådana icke-bakåtkompatibla förändringar i många år, även i större versioner, så varför nu? Det finns två huvudsakliga orsaker: identiteter och serialisering. När det gäller identiteter består korn- och strömidentiteter nu av strängar, vilket gör det möjligt för korn att koda allmän typinformation korrekt och göra det lättare för strömmar att mappas till programdomänen. Korntyper identifierades tidigare med hjälp av en komplex datastruktur som inte kunde representera generiska korn, vilket ledde till hörnfall. Strömmar identifierades av ett string
namnområde och en Guid nyckel, vilket var svårt för utvecklare att mappa till sin programdomän, hur effektivt det än var. Serialiseringen är nu versionstolerant, vilket innebär att du kan ändra dina typer på vissa kompatibla sätt, följa en uppsättning regler och vara säker på att du kan uppgradera programmet utan serialiseringsfel. Detta var särskilt problematiskt när programtyperna bevarades i strömmar eller kornlagring. Följande avsnitt beskriver de viktigaste ändringarna och diskuterar dem mer detaljerat.
Om du uppgraderar ett projekt till Orleans 7.0 måste du utföra följande åtgärder:
Microsoft.Orleans.CodeGenerator.MSBuild
och Microsoft.Orleans.OrleansCodeGenerator.Build
.
KnownAssembly
med GenerateCodeForDeclaringAssemblyAttribute.Microsoft.Orleans.Sdk
refererar till C#-källgeneratorpaketet (Microsoft.Orleans.CodeGenerator
).Microsoft.Orleans.OrleansRuntime
.
Microsoft.Orleans.Runtime
.ConfigureApplicationParts
.
Programdelar har tagits bort. C#-källgeneratorn för Orleans läggs till i alla paket (inklusive klienten och servern) och genererar motsvarigheten till programdelar automatiskt.Microsoft.Orleans.OrleansServiceBus
med Microsoft.Orleans. Streaming.EventHubs.Tips
Orleans Alla exempel har uppgraderats till Orleans 7.0 och kan användas som referens för vilka ändringar som har gjorts. Mer information finns i Orleans problem #8035 som specificerar de ändringar som görs i varje exempel.
Alla Orleans projekt refererar antingen direkt eller indirekt till NuGet-paketet Microsoft.Orleans.Sdk
. När ett Orleans projekt har konfigurerats för att aktivera implicit användning (till exempel <ImplicitUsings>enable</ImplicitUsings>
) Orleans
används båda namnrymderna och Orleans.Hosting
implicit. Det innebär att appkoden inte behöver dessa direktiv.
Mer information finns i ImplicitUsings och dotnet/orleans/src/Orleans.Sdk/build/Microsoft.Orleans.Sdk.targets.
Typen ClientBuilder har ersatts med en UseOrleansClient tilläggsmetod på IHostBuilder. Typen IHostBuilder
kommer från NuGet-paketet Microsoft.Extensions.Hosting . Det innebär att du kan lägga till en Orleans klient i en befintlig värd utan att behöva skapa en separat container för beroendeinmatning. Klienten ansluter till klustret under starten. När IHost.StartAsync klienten har slutförts ansluts den automatiskt. Tjänster som läggs till IHostBuilder
i startas i registreringsordningen, så anropa UseOrleansClient
innan anropet ConfigureWebHostDefaults kommer att säkerställa Orleans att startas innan ASP.NET Core startar, till exempel så att du kan komma åt klienten från ditt ASP.NET Core-program omedelbart.
Om du vill emulera det tidigare ClientBuilder
beteendet kan du skapa en separat HostBuilder
och konfigurera den med en Orleans klient.
IHostBuilder
kan ha antingen en Orleans klient eller en Orleans silo konfigurerad. Alla silor registrerar en instans av IGrainFactory och IClusterClient som programmet kan använda, så att konfigurera en klient separat är onödigt och stöds inte.
Orleans låter korn köra kod under aktivering och inaktivering. Detta kan användas för att utföra uppgifter som att läsa tillstånd från lagrings- eller logglivscykelmeddelanden. I Orleans 7.0 ändrades signaturen för dessa livscykelmetoder:
CancellationToken
parameter.
DeactivationReason
Anger varför aktiveringen inaktiveras. Utvecklare förväntas använda den här informationen i loggnings- och diagnostiksyfte. När avbryts CancellationToken
bör inaktiveringsprocessen slutföras omgående. Observera att eftersom alla värdar kan misslyckas när som helst rekommenderar vi inte att du förlitar dig på OnDeactivateAsync
att utföra viktiga åtgärder som att bevara kritiskt tillstånd.Tänk på följande exempel på ett korn som åsidosätter dessa nya metoder:
public sealed class PingGrain : Grain, IPingGrain
{
private readonly ILogger<PingGrain> _logger;
public PingGrain(ILogger<PingGrain> logger) =>
_logger = logger;
public override Task OnActivateAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("OnActivateAsync()");
return Task.CompletedTask;
}
public override Task OnDeactivateAsync(DeactivationReason reason, CancellationToken token)
{
_logger.LogInformation("OnDeactivateAsync({Reason})", reason);
return Task.CompletedTask;
}
public ValueTask Ping() => ValueTask.CompletedTask;
}
Korn i Orleans behöver inte längre ärva från basklassen Grain eller någon annan klass. Den här funktionen kallas POCO-korn . Så här kommer du åt tilläggsmetoder som något av följande:
Ditt korn måste antingen implementera IGrainBase eller ärva från Grain. Här är ett exempel på implementering IGrainBase
på en kornklass:
public sealed class PingGrain : IGrainBase, IPingGrain
{
public PingGrain(IGrainContext context) => GrainContext = context;
public IGrainContext GrainContext { get; }
public ValueTask Ping() => ValueTask.CompletedTask;
}
IGrainBase
definierar OnActivateAsync
och OnDeactivateAsync
med standardimplementeringar, vilket gör att ditt korn kan delta i livscykeln om så önskas:
public sealed class PingGrain : IGrainBase, IPingGrain
{
private readonly ILogger<PingGrain> _logger;
public PingGrain(IGrainContext context, ILogger<PingGrain> logger)
{
_logger = logger;
GrainContext = context;
}
public IGrainContext GrainContext { get; }
public Task OnActivateAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("OnActivateAsync()");
return Task.CompletedTask;
}
public Task OnDeactivateAsync(DeactivationReason reason, CancellationToken token)
{
_logger.LogInformation("OnDeactivateAsync({Reason})", reason);
return Task.CompletedTask;
}
public ValueTask Ping() => ValueTask.CompletedTask;
}
Den mest betungande förändringen i Orleans 7.0 är introduktionen av den versionstoleranta serialiseraren. Den här ändringen gjordes eftersom program tenderar att utvecklas och detta ledde till en betydande fallgrop för utvecklare, eftersom den tidigare serialiseraren inte kunde tolerera att egenskaper lades till i befintliga typer. Å andra sidan var serialiseraren flexibel, vilket gjorde det möjligt för utvecklare att representera de flesta .NET-typer utan ändringar, inklusive funktioner som generiska läkemedel, polymorfism och referensspårning. En ersättning borde ha ersatts för länge sedan, men användarna behöver fortfarande en återgivningsrepresentation av sina typer. Därför introducerades en ersättnings serialiserare i Orleans 7.0 som stöder återgivning av .NET-typer samtidigt som typer kan utvecklas. Den nya serialiseraren är mycket effektivare än den tidigare serialiseraren, vilket resulterar i upp till 170 % högre dataflöde från slutpunkt till slutpunkt.
Mer information finns i följande artiklar om Orleans 7.0:
Korn har var och en en unik identitet som består av korntypen och dess nyckel. Tidigare versioner av Orleans använde en sammansatt typ för s för GrainId
att stödja kornnycklar för något av följande:
Detta innebär viss komplexitet när det gäller att hantera kornnycklar. Korniga identiteter består av två komponenter: en typ och en nyckel. Typkomponenten bestod tidigare av en numerisk typkod, en kategori och 3 byte allmän typinformation.
Korniga identiteter har nu formatet type/key
där både type
och key
är strängar. Det vanligaste kornnyckelgränssnittet är IGrainWithStringKey. Detta förenklar avsevärt hur kornidentitet fungerar och förbättrar stödet för generiska korntyper.
Korngränssnitt representeras nu också med ett läsbart namn för människor, i stället för en kombination av en hashkod och en strängrepresentation av alla generiska typparametrar.
Det nya systemet är mer anpassningsbart och dessa anpassningar kan styras av attribut.
class
anger typdelen av dess korn-ID.interface
anger typen av korn som ska matchas som IGrainFactory standard när en kornreferens hämtas. När du till exempel anropar IGrainFactory.GetGrain<IMyGrain>("my-key")
returnerar kornfabriken en referens till kornigheten "my-type/my-key"
om IMyGrain
det ovan nämnda attributet har angetts.Som nämnts ovan kan du genom att åsidosätta standardnamnen för kornklass och gränssnitt för dina typer byta namn på de underliggande typerna utan att bryta kompatibiliteten med befintliga distributioner.
När Orleans strömmar först släpptes kunde strömmar bara identifieras med hjälp av en Guid. Detta var effektivt när det gäller minnesallokering, men det var svårt för användare att skapa meningsfulla strömidentiteter, vilket ofta krävde viss kodning eller indirektion för att fastställa lämplig strömidentitet för ett visst syfte.
I Orleans 7.0 identifieras strömmar nu med hjälp av strängar. Innehåller Orleans.Runtime.StreamIdstruct
tre egenskaper: en StreamId.Namespace, en StreamId.Keyoch en StreamId.FullKey. Dessa egenskapsvärden är kodade UTF-8-strängar. Exempel: StreamId.Create(String, String)
SimpleMessageStreams
(kallas även SMS) togs bort i 7.0. SMS hade samma gränssnitt som Orleans.Providers.Streams.PersistentStreams, men dess beteende var mycket annorlunda, eftersom det förlitade sig på direkta korn-till-korn-anrop. För att undvika förvirring togs SMS bort och en ny ersättning med namnet Orleans.BroadcastChannel introducerades.
BroadcastChannel
stöder endast implicita prenumerationer och kan vara en direkt ersättning i det här fallet. Om du behöver explicita prenumerationer eller behöver använda PersistentStream
gränssnittet (till exempel om du använde SMS i tester när du använde EventHub
i produktion) är det MemoryStream
den bästa kandidaten för dig.
BroadcastChannel
kommer att ha samma beteenden som SMS, medan MemoryStream
kommer att bete sig som andra strömprovidrar. Tänk på följande exempel på sändningskanalanvändning:
// Configuration
builder.AddBroadcastChannel(
"my-provider",
options => options.FireAndForgetDelivery = false);
// Publishing
var grainKey = Guid.NewGuid().ToString("N");
var channelId = ChannelId.Create("some-namespace", grainKey);
var stream = provider.GetChannelWriter<int>(channelId);
await stream.Publish(1);
await stream.Publish(2);
await stream.Publish(3);
// Simple implicit subscriber example
[ImplicitChannelSubscription]
public sealed class SimpleSubscriberGrain : Grain, ISubscriberGrain, IOnBroadcastChannelSubscribed
{
// Called when a subscription is added to the grain
public Task OnSubscribed(IBroadcastChannelSubscription streamSubscription)
{
streamSubscription.Attach<int>(
item => OnPublished(streamSubscription.ChannelId, item),
ex => OnError(streamSubscription.ChannelId, ex));
return Task.CompletedTask;
// Called when an item is published to the channel
static Task OnPublished(ChannelId id, int item)
{
// Do something
return Task.CompletedTask;
}
// Called when an error occurs
static Task OnError(ChannelId id, Exception ex)
{
// Do something
return Task.CompletedTask;
}
}
}
Migreringen till MemoryStream
blir enklare eftersom endast konfigurationen behöver ändras. Överväg följande MemoryStream
konfiguration:
builder.AddMemoryStreams<DefaultMemoryMessageBodySerializer>(
"in-mem-provider",
_ =>
{
// Number of pulling agent to start.
// DO NOT CHANGE this value once deployed, if you do rolling deployment
_.ConfigurePartitioning(partitionCount: 8);
});
Telemetrisystemet har uppdaterats i Orleans 7.0 och det tidigare systemet har tagits bort till förmån för standardiserade .NET-API:er som .NET Metrics för mått och ActivitySource för spårning.
Som en del av detta har de befintliga Microsoft.Orleans.TelemetryConsumers.*
paketen tagits bort. Vi överväger att införa en ny uppsättning paket för att effektivisera processen med att integrera måtten som genereras av Orleans i valfri övervakningslösning. Som alltid är feedback och bidrag välkomna.
Verktyget dotnet-counters
har prestandaövervakning för ad hoc-hälsoövervakning och prestandaundersökning på första nivån. För Orleans räknare kan verktyget dotnet-counters användas för att övervaka dem:
dotnet counters monitor -n MyApp --counters Microsoft.Orleans
På samma sätt kan OpenTelemetry-mått lägga till mätarna Microsoft.Orleans
, enligt följande kod:
builder.Services.AddOpenTelemetry()
.WithMetrics(metrics => metrics
.AddPrometheusExporter()
.AddMeter("Microsoft.Orleans"));
Om du vill aktivera distribuerad spårning konfigurerar du OpenTelemetry enligt följande kod:
builder.Services.AddOpenTelemetry()
.WithTracing(tracing =>
{
tracing.SetResourceBuilder(ResourceBuilder.CreateDefault()
.AddService(serviceName: "ExampleService", serviceVersion: "1.0"));
tracing.AddAspNetCoreInstrumentation();
tracing.AddSource("Microsoft.Orleans.Runtime");
tracing.AddSource("Microsoft.Orleans.Application");
tracing.AddZipkinExporter(options =>
{
options.Endpoint = new Uri("http://localhost:9411/api/v2/spans");
});
});
I föregående kod konfigureras OpenTelemetry för övervakning:
Microsoft.Orleans.Runtime
Microsoft.Orleans.Application
Om du vill sprida aktivitet anropar du AddActivityPropagation:
builder.Host.UseOrleans((_, clientBuilder) =>
{
clientBuilder.AddActivityPropagation();
});
I Orleans 7.0 har vi gjort ett försök att dela in tillägg i separata paket som inte är beroende Orleans.Coreav . Orleans.StreamingNämligen , Orleans.Reminders, och Orleans.Transactions har separerats från kärnan. Det innebär att dessa paket helt betalar för det du använder och ingen kod i kärnan av Orleans är dedikerad till dessa funktioner. Detta bantar ner api-kärnytan och sammansättningsstorleken, förenklar kärnan och förbättrar prestandan. När det gäller prestanda krävde transaktioner i Orleans tidigare viss kod som kördes för varje metod för att samordna potentiella transaktioner. Det har sedan dess flyttats till per metod.
Det här är en kompileringsbrytande ändring. Du kan ha befintlig kod som interagerar med påminnelser eller strömmar genom att anropa till metoder som tidigare har definierats i basklassen Grain men som nu är tilläggsmetoder. Sådana anrop som inte anger this
(till exempel GetReminders) måste uppdateras för att inkludera this
(till exempel this.GetReminders()
) eftersom tilläggsmetoder måste vara kvalificerade. Det uppstår ett kompileringsfel om du inte uppdaterar dessa anrop och den nödvändiga kodändringen kanske inte är uppenbar om du inte vet vad som har ändrats.
Orleans 7.0 introducerar en ny abstraktion för samordning av transaktioner, Orleans.ITransactionClient. Tidigare kunde transaktioner endast samordnas av korn. Med ITransactionClient
, som är tillgängligt via beroendeinmatning, kan klienter också samordna transaktioner utan att behöva ett mellanliggande korn. I följande exempel tas krediter ut från ett konto och de sätts in i ett annat inom en enda transaktion. Den här koden kan anropas från ett korn eller från en extern klient som har hämtat ITransactionClient
från containern för beroendeinmatning.
await transactionClient.RunTransaction(
TransactionOption.Create,
() => Task.WhenAll(from.Withdraw(100), to.Deposit(100)));
För transaktioner som samordnas av klienten måste klienten lägga till de nödvändiga tjänsterna under konfigurationstiden:
clientBuilder.UseTransactions();
BankAccount-exemplet visar användningen av ITransactionClient
. Mer information finns i Orleans transaktioner.
Korn är entrådade och bearbetar begäranden en i taget från början till slut som standard. Med andra ord är korn inte reentrant som standard.
ReentrantAttribute Genom att lägga till i en kornklass kan flera begäranden bearbetas samtidigt, på ett interfolierande sätt, samtidigt som de fortfarande är enkeltrådade. Detta kan vara användbart för korn som inte har något internt tillstånd eller utför många asynkrona åtgärder, till exempel att utfärda HTTP-anrop eller skriva till en databas. Extra försiktighet måste iakttas när begäranden kan interleave: det är möjligt att tillståndet för ett korn observeras innan en await
instruktion har ändrats när den asynkrona åtgärden slutförs och metoden återupptar körningen.
Följande korn representerar till exempel en räknare. Det har markerats Reentrant
, vilket gör att flera anrop kan interleave. Metoden Increment()
bör öka den interna räknaren och returnera det observerade värdet. Men eftersom metodtexten Increment()
observerar kornets tillstånd före en await
punkt och uppdaterar den efteråt, är det möjligt att flera interleaving-körningar av Increment()
kan resultera i ett _value
mindre än det totala antalet Increment()
mottagna anrop. Det här är ett fel som uppstår vid felaktig användning av återaktivering.
ReentrantAttribute Det räcker med att ta bort problemet.
[Reentrant]
public sealed class CounterGrain : Grain, ICounterGrain
{
int _value;
/// <summary>
/// Increments the grain's value and returns the previous value.
/// </summary>
public Task<int> Increment()
{
// Do not copy this code, it contains an error.
var currentVal = _value;
await Task.Delay(TimeSpan.FromMilliseconds(1_000));
_value = currentVal + 1;
return currentValue;
}
}
För att förhindra sådana fel är korn som standard icke-reentrant. Nackdelen med detta är minskat dataflöde för korn som utför asynkrona åtgärder i implementeringen, eftersom andra begäranden inte kan bearbetas medan kornet väntar på att en asynkron åtgärd ska slutföras. För att lindra detta Orleans erbjuder flera alternativ för att tillåta återaktivering i vissa fall:
ReadOnly
begäranden och begäranden till den metoden interfolieras av andra ReadOnly
begäranden. I den meningen är det en mer begränsad form av AlwaysInterleave
.public Task<int> OuterCall(IMyGrain other)
{
// Allow call-chain reentrancy for this grain, for the duration of the method.
using var _ = RequestContext.AllowCallChainReentrancy();
await other.CallMeBack(this.AsReference<IMyGrain>());
}
public Task CallMeBack(IMyGrain grain)
{
// Because OuterCall allowed reentrancy back into that grain, this method
// will be able to call grain.InnerCall() without deadlocking.
await grain.InnerCall();
}
public Task InnerCall() => Task.CompletedTask;
Återaktivering av samtalskedja måste väljas per korn, per samtalskedja. Överväg till exempel två korn, korn A & korn B. Om korn A aktiverar återaktivering av anropskedja innan du anropar korn B, kan korn B anropa tillbaka till korn A i det anropet. Korn A kan dock inte anropa tillbaka till korn B om korn B inte också har aktiverat återaktivering av anropskedjan. Det är per korn, per anropskedja.
Korn kan också förhindra återaktiveringsinformation för anropskedjan från att flöda ned i en anropskedja med hjälp av using var _ = RequestContext.SuppressCallChainReentrancy()
. Detta förhindrar att efterföljande anrop försöker igen.
För att säkerställa vidarekompatibilitet med Orleans klustring, beständighet och påminnelser som är beroende av ADO.NET behöver du rätt SQL-migreringsskript:
Välj filerna för databasen som används och tillämpa dem i ordning.
Feedback om .NET
.NET är ett öppen källkod projekt. Välj en länk för att ge feedback:
Händelser
17 mars 21 - 21 mars 10
Gå med i mötesserien för att skapa skalbara AI-lösningar baserat på verkliga användningsfall med andra utvecklare och experter.
Registrera dig nuUtbildning
Modul
Skapa din första Orleans-app med ASP.NET Core 8.0 - Training
Lär dig hur du skapar molnbaserade, distribuerade appar med Orleans.