Školení
Modul
Vytvoření první aplikace Orleans pomocí ASP.NET Core 8.0 - Training
Naučte se vytvářet aplikace nativní pro cloud s distribuovanými aplikacemi pomocí Orleans.
Tento prohlížeč se už nepodporuje.
Upgradujte na Microsoft Edge, abyste mohli využívat nejnovější funkce, aktualizace zabezpečení a technickou podporu.
Orleans 7.0 představuje několik výhodných změn, včetně vylepšení hostování, vlastní serializace, neměnnosti a abstrakce zrnitosti.
Stávající aplikace využívající připomenutí, datové proudy nebo trvalost zrnitosti nelze snadno migrovat na Orleans verzi 7.0 kvůli změnám způsobu Orleans identifikace zrn a datových proudů. Plánujeme pro tyto aplikace přírůstkově nabídnout cestu migrace.
Aplikace s předchozími verzemi Orleans nelze hladce upgradovat prostřednictvím postupného upgradu na Orleans verzi 7.0. Proto se musí použít jiná strategie upgradu, například nasazení nového clusteru a vyřazení předchozího clusteru z provozu. Orleans 7.0 změní protokol drátu nekompatibilním způsobem, což znamená, že clustery nemohou obsahovat kombinaci Orleans hostitelů 7.0 a hostitelů s předchozími verzemi Orleans.
Už mnoho let jsme se takovým zásadním změnám vyhnuli, a to i v hlavních verzích, takže proč? Existují dva hlavní důvody: identity a serializace. Pokud jde o identity, odstupňované identity a identity datových proudů se teď skládají z řetězců, což umožňuje správně kódovat informace o obecném typu a umožnit datovým proudům snadněji mapovat do domény aplikace. Typy zrn se dříve identifikovaly pomocí komplexní datové struktury, která nemohla představovat obecná zrnka, což vedlo k rohovým případům. Streamy byly identifikovány oborem string
názvů a Guid klíčem, který vývojářům obtížně namapoval na svoji doménu aplikace, ale efektivně. Serializace je nyní odolné proti verzím, což znamená, že můžete upravit typy určitými kompatibilními způsoby, sledovat sadu pravidel a mít jistotu, že můžete upgradovat aplikaci bez chyb serializace. To bylo obzvláště problematické, když typy aplikací trvaly v datových proudech nebo v úložišti zrnitosti. Následující části podrobně uvádějí hlavní změny a podrobněji je probírají.
Pokud upgradujete projekt na Orleans verzi 7.0, budete muset provést následující akce:
Microsoft.Orleans.CodeGenerator.MSBuild
a Microsoft.Orleans.OrleansCodeGenerator.Build
.
KnownAssembly
parametrem GenerateCodeForDeclaringAssemblyAttribute.Microsoft.Orleans.Sdk
odkazuje na balíček C# Source Generator (Microsoft.Orleans.CodeGenerator
).Microsoft.Orleans.OrleansRuntime
.
Microsoft.Orleans.Runtime
.ConfigureApplicationParts
Části aplikace byly odebrány. Zdrojový generátor jazyka C# se Orleans přidá do všech balíčků (včetně klienta a serveru) a automaticky vygeneruje ekvivalent částí aplikace.Microsoft.Orleans.OrleansServiceBus
Microsoft.Orleans. Streaming.EventHubsTip
Orleans Všechny ukázky byly upgradovány na Orleans verzi 7.0 a lze je použít jako referenci na provedené změny. Další informace najdete v tématu Orleans problém č. 8035 , který uvádí změny provedené v každé ukázce.
Všechny Orleans projekty buď přímo nebo nepřímo odkazují na Microsoft.Orleans.Sdk
balíček NuGet. Orleans Pokud je projekt nakonfigurovaný tak, aby umožňoval implicitní použití (například<ImplicitUsings>enable</ImplicitUsings>
), Orleans
oba obory názvů se Orleans.Hosting
implicitně používají. To znamená, že kód aplikace tyto direktivy nepotřebuje.
Další informace najdete v tématu ImplicitUsings a dotnet/orleans/src/Orleans. Sdk/build/Microsoft.Orleans. Sdk.targets.
Typ ClientBuilder byl nahrazen metodou UseOrleansClient rozšíření na IHostBuilder. Typ IHostBuilder
pochází z balíčku NuGet Microsoft.Extensions.Hosting . To znamená, že můžete přidat Orleans klienta do existujícího hostitele, aniž byste museli vytvořit samostatný kontejner injektáže závislostí. Klient se připojí ke clusteru během spuštění. Po IHost.StartAsync dokončení se klient připojí automaticky. Služby přidané do registrace IHostBuilder
jsou spuštěny v pořadí registrace, takže volání UseOrleansClient
před voláním ConfigureWebHostDefaults zajistí, že Orleans se spustí před spuštěním ASP.NET Core, například umožníte přístup k klientovi z aplikace ASP.NET Core okamžitě.
Pokud chcete emulovat předchozí ClientBuilder
chování, můžete vytvořit samostatný HostBuilder
a nakonfigurovat ho Orleans pomocí klienta. IHostBuilder
může mít nakonfigurovaného Orleans klienta nebo Orleans sila. Všechna sila registrují instanci IGrainFactory a IClusterClient kterou může aplikace používat, takže konfigurace klienta samostatně není nutná a nepodporovaná.
Orleans umožňuje provádění kódu během aktivace a deaktivace. Dá se použít k provádění úloh, jako je čtení stavu z úložiště nebo zpráv životního cyklu protokolu. V Orleans 7.0 se podpis těchto metod životního cyklu změnil:
CancellationToken
parametr. Označuje DeactivationReason
, proč se aktivace deaktivuje. Očekává se, že vývojáři budou tyto informace používat pro účely protokolování a diagnostiky. CancellationToken
Po zrušení by se měl proces deaktivace provést okamžitě. Mějte na paměti, že vzhledem k tomu, že jakýkoli hostitel může kdykoli selhat, nedoporučuje se spoléhat na OnDeactivateAsync
provádění důležitých akcí, jako je zachování kritického stavu.Představte si následující příklad přepsání těchto nových metod:
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;
}
Orleans Zrna už nemusí dědit ze Grain základní třídy ani z jakékoli jiné třídy. Tato funkce se označuje jako zrnka POCO . Přístup k rozšiřujícím metodám, jako je některý z následujících způsobů:
Vaše agregační interval musí buď implementovat IGrainBase , nebo dědit z Grain. Tady je příklad implementace IGrainBase
třídy grain:
public sealed class PingGrain : IGrainBase, IPingGrain
{
public PingGrain(IGrainContext context) => GrainContext = context;
public IGrainContext GrainContext { get; }
public ValueTask Ping() => ValueTask.CompletedTask;
}
IGrainBase
také definuje OnActivateAsync
a OnDeactivateAsync
s výchozími implementacemi, což umožňuje, aby se vaše podrobné údaje v případě potřeby účastnily jeho životního cyklu:
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;
}
Nejtěžnější změnou ve verzi Orleans 7.0 je zavedení serializátoru odolného proti verzi. Tato změna byla provedena, protože aplikace se obvykle vyvíjejí a to vedlo k významnému nástrahám pro vývojáře, protože předchozí serializátor nemohl tolerovat přidávání vlastností do existujících typů. Na druhou stranu serializátor byl flexibilní, což vývojářům umožnilo reprezentovat většinu typů .NET bez úprav, včetně funkcí, jako jsou obecné typy, polymorfismus a sledování odkazů. Náhrada byla příliš dlouhá, ale uživatelé stále potřebují vysoce věrnou reprezentaci svých typů. Proto byl zaveden náhradní serializátor v Orleans 7.0, který podporuje vysoce věrnou reprezentaci typů .NET a zároveň umožňuje vyvíjet typy. Nový serializátor je mnohem efektivnější než předchozí serializátor, což vede až k 170% vyšší koncové propustnosti.
Další informace najdete v následujících článcích, které se týkají Orleans verze 7.0:
Každý zrna má jedinečnou identitu, která se skládá z typu zrnka a jeho klíče. Předchozí verze použitého Orleans složeného typu pro GrainId
s pro podporu klíčů zrnitosti:
To zahrnuje určitou složitost, pokud jde o práci s klíči odstupňované. Identity agregace se skládají ze dvou součástí: typu a klíče. Součást typu se dříve skládala z číselného kódu typu, kategorie a 3 bajtů obecných informací o typu.
Odstupňované identity teď mají tvar type/key
, ve kterém type
jsou řetězce i key
řetězce. Nejčastěji používané rozhraní klíče zrnitosti IGrainWithStringKeyje . To výrazně zjednodušuje fungování odstupňované identity a zlepšuje podporu obecných typů agregačních typů.
Rozhraní zrnitosti jsou nyní také reprezentována pomocí čitelného názvu člověka místo kombinace kódu hash a řetězcové reprezentace jakýchkoli parametrů obecného typu.
Nový systém je lépe přizpůsobitelný a tato přizpůsobení můžou být řízena atributy.
class
určuje část typu id jeho agregace.interface
, který IGrainFactory se má ve výchozím nastavení vyřešit při získání odkazu na agregační interval. Například při volání IGrainFactory.GetGrain<IMyGrain>("my-key")
, grain factory vrátí odkaz na zrno "my-type/my-key"
, pokud IMyGrain
má výše uvedený atribut zadaný.Jak je uvedeno výše, přepsání výchozí třídy zrnitosti a názvů rozhraní pro vaše typy umožňuje přejmenovat základní typy bez narušení kompatibility s existujícími nasazeními.
Při Orleans prvním vydání datových proudů lze datové proudy identifikovat pouze pomocí Guid. To bylo efektivní z hlediska přidělování paměti, ale pro uživatele bylo obtížné vytvářet smysluplné identity datových proudů, často vyžadují určité kódování nebo nepřímé určení vhodné identity streamu pro daný účel.
Ve Orleans verzi 7.0 jsou teď streamy identifikovány pomocí řetězců. Obsahuje Orleans.Runtime.StreamId struct
tři vlastnosti: a StreamId.NamespaceStreamId.Key, a a StreamId.FullKey. Tyto hodnoty vlastností jsou kódované řetězce UTF-8. Například StreamId.Create(String, String).
SimpleMessageStreams
(označuje se také jako SMS) byla odebrána ve verzi 7.0. SMS měla stejné rozhraní jako Orleans.Providers.Streams.PersistentStreams, ale jeho chování bylo velmi odlišné, protože se spoléhalo na přímé volání od zrnitosti. Aby nedošlo k nejasnostem, SMS byla odstraněna a byla zavedena nová výměna Orleans.BroadcastChannel .
BroadcastChannel
podporuje pouze implicitní předplatná a v tomto případě může být přímým nahrazením. Pokud potřebujete explicitní předplatná nebo potřebujete použít PersistentStream
rozhraní (například jste používali SMS v testech při používání EventHub
v produkčním prostředí), pak MemoryStream
je pro vás nejlepším kandidátem.
BroadcastChannel
bude mít stejné chování jako SMS, zatímco MemoryStream
se bude chovat jako ostatní poskytovatelé datových proudů. Představte si následující příklad použití kanálu broadcastu:
// 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;
}
}
}
MemoryStream
Migrace bude jednodušší, protože pouze konfigurace se musí změnit. Zvažte následující MemoryStream
konfiguraci:
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);
});
Systém telemetrie byl aktualizován ve verzi Orleans 7.0 a předchozí systém byl odebrán ve prospěch standardizovaných rozhraní .NET API, jako jsou metriky .NET pro metriky a ActivitySource trasování.
V rámci této funkce byly stávající Microsoft.Orleans.TelemetryConsumers.*
balíčky odebrány. Zvažujeme zavedení nové sady balíčků, abychom zjednodušili proces integrace metrik vygenerovaných Orleans do zvoleného řešení monitorování. Jako vždy vítáme zpětnou vazbu a příspěvky.
Nástroj dotnet-counters
nabízí monitorování výkonu pro monitorování stavu ad hoc a prošetření výkonu na první úrovni. U Orleans čítačů lze nástroj dotnet-counters použít k jejich monitorování:
dotnet counters monitor -n MyApp --counters Microsoft.Orleans
Podobně metriky OpenTelemetry můžou přidat Microsoft.Orleans
měřiče, jak je znázorněno v následujícím kódu:
builder.Services.AddOpenTelemetry()
.WithMetrics(metrics => metrics
.AddPrometheusExporter()
.AddMeter("Microsoft.Orleans"));
Pokud chcete povolit distribuované trasování, nakonfigurujete OpenTelemetry, jak je znázorněno v následujícím kódu:
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");
});
});
V předchozím kódu je OpenTelemetry nakonfigurovaná tak, aby monitorovala:
Microsoft.Orleans.Runtime
Microsoft.Orleans.Application
Pokud chcete aktivitu rozšířit, zavolejte AddActivityPropagation:
builder.Host.UseOrleans((_, clientBuilder) =>
{
clientBuilder.AddActivityPropagation();
});
V Orleans 7.0 jsme se snažili zohlednit rozšíření do samostatných balíčků, které se nespoléhá na Orleans.Core. Konkrétně , Orleans.Streaminga Orleans.RemindersOrleans.Transactions byly odděleny od jádra. To znamená, že tyto balíčky jsou zcela platit za to, co používáte, a žádný kód v jádru Orleans je vyhrazený pro tyto funkce. Tím se zklidní plocha a velikost základního rozhraní API, zjednoduší se jádro a zlepší výkon. Pokud jde o výkon, transakce v Orleans minulosti vyžadovaly nějaký kód, který byl proveden pro každou metodu ke koordinaci potenciálních transakcí. To bylo od té doby přesunuto na jednotlivé metody.
Jedná se o změnu způsobující kompilaci. Možná máte existující kód, který komunikuje s připomenutími nebo datovými proudy voláním metod, které byly dříve definovány v Grain základní třídě, ale nyní jsou rozšiřující metody. Taková volání, která nezadávají this
(například GetReminders) budou muset být aktualizována tak, aby zahrnovala this
(například this.GetReminders()
), protože metody rozšíření musí být kvalifikované. Pokud tato volání neaktualizujete, dojde k chybě kompilace a požadovaná změna kódu nemusí být zřejmé, pokud nevíte, co se změnilo.
Orleans7.0 zavádí novou abstrakci pro koordinaci transakcí , Orleans.ITransactionClient Dříve mohly být transakce koordinovány pouze zrny. S ITransactionClient
, který je k dispozici prostřednictvím injektáže závislostí, klienti mohou také koordinovat transakce bez nutnosti zprostředkujícího agregace. Následující příklad stáhne kredity z jednoho účtu a uloží je do jiné v rámci jedné transakce. Tento kód lze volat z agregačního intervalu nebo z externího klienta, který načetl ITransactionClient
kontejner injektáž závislostí.
await transactionClient.RunTransaction(
TransactionOption.Create,
() => Task.WhenAll(from.Withdraw(100), to.Deposit(100)));
V případě transakcí koordinovaných klientem musí klient během konfigurace přidat požadované služby:
clientBuilder.UseTransactions();
Ukázka BankAccount ukazuje použití ITransactionClient
. Další informace naleznete v tématu Orleans transakce.
Zrnka jsou ve výchozím nastavení jednovláknová a zpracovávají jeden po druhém. Jinými slovy, zrnka nejsou ve výchozím nastavení znovu prováděná. ReentrantAttribute Přidání do třídy zrnitosti umožňuje souběžné zpracování více požadavků, a to v prokládání, zatímco stále je jednovláknové. To může být užitečné pro zrnka, která neobsahují žádný vnitřní stav nebo provádějí velké množství asynchronních operací, jako je vydávání volání HTTP nebo zápis do databáze. Při prokládání požadavků je potřeba věnovat zvláštní pozornost: je možné, že stav agregace je pozorován před await
změnou příkazu v době, kdy se asynchronní operace dokončí, a metoda pokračuje v provádění.
Například následující agregační interval představuje čítač. Bylo označeno Reentrant
, což umožňuje více volání prokládání. Metoda Increment()
by měla zvýšit vnitřní čítač a vrátit pozorovanou hodnotu. Vzhledem k tomu, že Increment()
tělo metody sleduje stav zrnitosti před await
bodem a následně ho aktualizuje, je možné, že více prokládání provádění Increment()
může mít za následek _value
menší než celkový počet přijatých Increment()
volání. Jedná se o chybu, kterou představuje nesprávné použití opětovného použití.
ReentrantAttribute Odstranění problému stačí k vyřešení problému.
[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;
}
}
Chcete-li těmto chybám zabránit, nejsou zrnka ve výchozím nastavení znovu prováděná. Nevýhodou je snížení propustnosti zrna, která provádějí asynchronní operace v jejich implementaci, protože jiné požadavky nelze zpracovat, zatímco agregační interval čeká na dokončení asynchronní operace. Chcete-li to zmírnit, Orleans nabízí několik možností, jak v některých případech umožnit opakované zařazení:
ReadOnly
požadavkem a pro požadavky na danou metodu prokládání jinými ReadOnly
požadavky. V tomto smyslu je to omezenější forma 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;
Opětovná architektura řetězu volání musí být opted-in per-grain, per-call-chain. Představte si například dvě zrnka, zrno A a B. Pokud agregační interval A umožňuje znovu zavolat řetěz volání před voláním agregační agregační interval B, může v daném volání zavolat zpět do agregační hodnoty A. Agregační agregační interval A však nemůže volat zpět do agregační hodnoty B, pokud agregační interval B také nepovolil převázání řetězu volání. Jedná se o agregační řetězec podle volání.
Zrna mohou také potlačit informace o zpětném řetězu volání od toku z řetězu volání pomocí using var _ = RequestContext.SuppressCallChainReentrancy()
. Tím se zabrání opětovnému zavádění následných volání.
Abyste zajistili kompatibilitu s clusteringem Orleans , trvalostmi a připomenutími, která se spoléhají na ADO.NET, budete potřebovat příslušný skript migrace SQL:
Vyberte soubory pro použitou databázi a použijte je v pořadí.
Zpětná vazba k produktu .NET
.NET je open source projekt. Vyberte odkaz pro poskytnutí zpětné vazby:
Školení
Modul
Vytvoření první aplikace Orleans pomocí ASP.NET Core 8.0 - Training
Naučte se vytvářet aplikace nativní pro cloud s distribuovanými aplikacemi pomocí Orleans.