Configurazione del server
Un silo viene configurato a livello di codice con il metodo di estensione UseOrleans(IHostBuilder, Action<HostBuilderContext,ISiloBuilder>) e diverse classi di opzioni supplementari. Le classi di opzione in Orleans seguono il modello Opzioni in .NET e possono essere caricate tramite file, variabili di ambiente e qualsiasi provider di configurazione valido.
Esistono diversi aspetti chiave della configurazione del silo:
- Provider di clustering
- (Facoltativo) informazioni sul clustering Orleans
- (Facoltativo) Endpoint da usare per le comunicazioni da silo a silo e da client a silo
Questo è un esempio di configurazione silo che definisce le informazioni sul cluster, usa il clustering di Azure e configura le parti dell'applicazione:
using IHost host = Host.CreateDefaultBuilder(args)
.UseOrleans(builder =>
{
builder.UseAzureStorageClustering(
options => options.ConfigureTableServiceClient(connectionString));
})
.UseConsoleLifetime()
.Build();
Suggerimento
Quando si sviluppa per Orleans, è possibile chiamare UseLocalhostClustering(ISiloBuilder, Int32, Int32, IPEndPoint, String, String) per configurare un cluster locale. Negli ambienti di produzione è consigliabile usare un provider di clustering adatto per la distribuzione.
Provider di clustering
siloBuilder.UseAzureStorageClustering(
options => options.ConfigureTableServiceClient(connectionString))
In genere, un servizio basato su Orleans viene distribuito in un cluster di nodi, su hardware dedicato o nel cloud. Per lo sviluppo e i test di base, Orleans può essere distribuito in una configurazione a nodo singolo. Quando viene distribuito in un cluster di nodi, Orleans implementa internamente un set di protocolli per individuare e mantenere l'appartenenza dei silo Orleans nel cluster, incluso il rilevamento degli errori dei nodi e la riconfigurazione automatica.
Per una gestione affidabile dell'appartenenza al cluster, Orleans usa Tabelle di Azure, SQL Server o Apache ZooKeeper per la sincronizzazione dei nodi.
In questo esempio viene usata la tabella di Azure come provider di appartenenze.
Informazioni sul clustering Orleans
Per configurare facoltativamente il clustering, usare ClusterOptions
come parametro di tipo per il metodo Configure nell'istanza di ISiloBuilder
.
siloBuilder.Configure<ClusterOptions>(options =>
{
options.ClusterId = "my-first-cluster";
options.ServiceId = "SampleApp";
})
Qui si specificano due opzioni:
- Impostare
ClusterId
su"my-first-cluster"
: si tratta di un ID univoco per il cluster Orleans. Tutti i client e i silo che usano questo ID potranno comunicare direttamente tra loro. È tuttavia possibile scegliere di usare un'opzioneClusterId
diversa per distribuzioni diverse. - Impostare
ServiceId
su"SampleApp"
: si tratta di un ID univoco per l'applicazione che verrà usato da alcuni provider, ad esempio provider di persistenza. Questo ID deve rimanere stabile e non cambiare tra le distribuzioni.
Per impostazione predefinita, Orleans userà un valore di "default"
sia per ServiceId
che per ClusterId
. Questi valori non devono essere modificati nella maggior parte dei casi. ServiceId
è il più significativo dei due e viene usato per distinguere i diversi servizi logici l'uno dall'altro in modo che possano condividere sistemi di archiviazione back-end senza interferire tra loro. ClusterId
viene usato per determinare quali host si connetteranno tra loro e formeranno un cluster.
All'interno di ogni cluster, tutti gli host devono usare lo stesso ServiceId
. Più cluster possono tuttavia condividere un oggetto ServiceId
. Ciò consente scenari di distribuzione blu/verde in cui viene avviata una nuova distribuzione (cluster) prima dell'arresto di un’altra. Questo è tipico per i sistemi ospitati nel servizio app di Azure.
Il caso più comune è che ServiceId
e ClusterId
rimangono fissi per la durata dell'applicazione e viene usata una strategia di distribuzione in sequenza. Questo è tipico per i sistemi ospitati in Kubernetes e Service Fabric.
Endpoint
Per impostazione predefinita, Orleans sarà in ascolto su tutte le interfacce sulla porta 11111
per la comunicazione da silo a silo e sulla porta 30000
per la comunicazione da client a silo. Per eseguire l'override di questo comportamento, chiamare ConfigureEndpoints(ISiloBuilder, Int32, Int32, AddressFamily, Boolean) e passare i numeri di porta da usare.
siloBuilder.ConfigureEndpoints(siloPort: 17_256, gatewayPort: 34_512)
Nel codice precedente:
- La porta silo è impostata su
17_256
. - La porta del gateway è impostata su
34_512
.
Un silo Orleans ha due tipi tipici di configurazione dell'endpoint:
- Gli endpoint da silo a silo vengono usati per la comunicazione tra silo nello stesso cluster.
- Gli endpoint da client a silo (o gateway) vengono usati per la comunicazione tra client e silo nello stesso cluster.
Questo metodo deve essere sufficiente nella maggior parte dei casi, ma è possibile personalizzarlo ulteriormente se necessario. Di seguito è riportato un esempio di come usare un indirizzo IP esterno con alcuni port forwarding:
siloBuilder.Configure<EndpointOptions>(options =>
{
// Port to use for silo-to-silo
options.SiloPort = 11_111;
// Port to use for the gateway
options.GatewayPort = 30_000;
// IP Address to advertise in the cluster
options.AdvertisedIPAddress = IPAddress.Parse("172.16.0.42");
// The socket used for client-to-silo will bind to this endpoint
options.GatewayListeningEndpoint = new IPEndPoint(IPAddress.Any, 40_000);
// The socket used by the gateway will bind to this endpoint
options.SiloListeningEndpoint = new IPEndPoint(IPAddress.Any, 50_000);
})
Internamente, il silo sarà in ascolto su 0.0.0.0:40000
e 0.0.0.0:50000
, ma il valore pubblicato nel provider di appartenenze sarà 172.16.0.42:11111
e 172.16.0.42:30000
.
Un silo viene configurato a livello di codice tramite SiloHostBuilder e diverse classi di opzioni supplementari. Le classi di opzione in Orleans seguono il modello Opzioni in .NET e possono essere caricate tramite file, variabili di ambiente e qualsiasi provider di configurazione valido.
Esistono diversi aspetti chiave della configurazione del silo:
- Informazioni sul clustering Orleans
- Provider di clustering
- Endpoint da usare per le comunicazioni da silo a silo e da client a silo
- Parti dell'applicazione
Questo è un esempio di configurazione silo che definisce le informazioni sul cluster, usa il clustering di Azure e configura le parti dell'applicazione:
var silo = Host.CreateDefaultBuilder(args)
.UseOrleans(builder =>
{
builder
.UseAzureStorageClustering(
options => options.ConnectionString = connectionString)
.Configure<ClusterOptions>(options =>
{
options.ClusterId = "my-first-cluster";
options.ServiceId = "AspNetSampleApp";
})
.ConfigureEndpoints(siloPort: 11111, gatewayPort: 30000)
.ConfigureApplicationParts(
parts => parts.AddApplicationPart(typeof(ValueGrain).Assembly).WithReferences())
})
.UseConsoleLifetime()
.Build();
Scomposizione dei passaggi usati in questo esempio:
Provider di clustering
siloBuilder.UseAzureStorageClustering(
options => options.ConnectionString = connectionString)
In genere, un servizio basato su Orleans viene distribuito in un cluster di nodi, su hardware dedicato o nel cloud. Per lo sviluppo e i test di base, Orleans può essere distribuito in una configurazione a nodo singolo. Quando viene distribuito in un cluster di nodi, Orleans implementa internamente un set di protocolli per individuare e mantenere l'appartenenza dei silo Orleans nel cluster, incluso il rilevamento degli errori dei nodi e la riconfigurazione automatica.
Per una gestione affidabile dell'appartenenza al cluster, Orleans usa Tabelle di Azure, SQL Server o Apache ZooKeeper per la sincronizzazione dei nodi.
In questo esempio si usa Tabella di Azure come provider di appartenenze.
Informazioni sul clustering Orleans
.Configure<ClusterOptions>(options =>
{
options.ClusterId = "my-first-cluster";
options.ServiceId = "AspNetSampleApp";
})
Di seguito vengono eseguite due operazioni:
- Impostare
ClusterId
su"my-first-cluster"
: si tratta di un ID univoco per il cluster Orleans. Tutti i client e i silo che usano questo ID potranno comunicare direttamente tra loro. È tuttavia possibile scegliere di usare un'opzioneClusterId
diversa per distribuzioni diverse. - Impostare
ServiceId
su"AspNetSampleApp"
: si tratta di un ID univoco per l'applicazione che verrà usato da alcuni provider, ad esempio provider di persistenza. Questo ID deve rimanere stabile e non cambiare tra le distribuzioni.
Per impostazione predefinita, Orleans userà un valore di "default"
sia per ServiceId
che per ClusterId
. Questi valori non devono essere modificati nella maggior parte dei casi. ServiceId
è il più significativo dei due e viene usato per distinguere i diversi servizi logici l'uno dall'altro in modo che possano condividere sistemi di archiviazione back-end senza interferire tra loro. ClusterId
viene usato per determinare quali host si connetteranno tra loro e formeranno un cluster.
All'interno di ogni cluster, tutti gli host devono usare lo stesso ServiceId
. Più cluster possono tuttavia condividere un oggetto ServiceId
. Ciò consente scenari di distribuzione blu/verde in cui viene avviata una nuova distribuzione (cluster) prima dell'arresto di un’altra. Questo è tipico per i sistemi ospitati nel servizio app di Azure.
Il caso più comune è che ServiceId
e ClusterId
rimangono fissi per la durata dell'applicazione e viene usata una strategia di distribuzione in sequenza. Questo è tipico per i sistemi ospitati in Kubernetes e Service Fabric.
Endpoint
siloBuilder.ConfigureEndpoints(siloPort: 11111, gatewayPort: 30000)
Un silo Orleans ha due tipi tipici di configurazione dell'endpoint:
- Endpoint da silo a silo, usato per la comunicazione tra silo nello stesso cluster
- Endpoint da client a silo (o gateway), usati per la comunicazione tra client e silo nello stesso cluster
Nell'esempio viene usato il metodo helper .ConfigureEndpoints(siloPort: 11111, gatewayPort: 30000)
che imposta la porta usata per la comunicazione da silo a silo a 11111
e la porta per il gateway su 30000
.
Questo metodo rileverà l'interfaccia da ascoltare.
Questo metodo deve essere sufficiente nella maggior parte dei casi, ma è possibile personalizzarlo ulteriormente se necessario. Di seguito è riportato un esempio di come usare un indirizzo IP esterno con alcuni port forwarding:
siloBuilder.Configure<EndpointOptions>(options =>
{
// Port to use for silo-to-silo
options.SiloPort = 11111;
// Port to use for the gateway
options.GatewayPort = 30000;
// IP Address to advertise in the cluster
options.AdvertisedIPAddress = IPAddress.Parse("172.16.0.42");
// The socket used for client-to-silo will bind to this endpoint
options.GatewayListeningEndpoint = new IPEndPoint(IPAddress.Any, 40000);
// The socket used by the gateway will bind to this endpoint
options.SiloListeningEndpoint = new IPEndPoint(IPAddress.Any, 50000);
})
Internamente, il silo sarà in ascolto su 0.0.0.0:40000
e 0.0.0.0:50000
, ma il valore pubblicato nel provider di appartenenze sarà 172.16.0.42:11111
e 172.16.0.42:30000
.
Parti dell'applicazione
siloBuilder.ConfigureApplicationParts(
parts => parts.AddApplicationPart(
typeof(ValueGrain).Assembly)
.WithReferences())
Anche se questo passaggio non è tecnicamente necessario (se non configurato, Orleans analizzerà tutti gli assembly nella cartella corrente), gli sviluppatori sono invitati a configurare questa operazione. Questo passaggio consentirà a Orleans di caricare assembly e tipi utente. Questi assembly vengono definiti parti dell'applicazione. Tutti i grani, le interfacce granulari e i serializzatori vengono individuati usando le parti dell'applicazione.
Le parti dell'applicazione vengono configurate usando IApplicationPartManager, a cui è possibile accedere usando il metodo di estensione ConfigureApplicationParts
su IClientBuilder e ISiloHostBuilder. Il metodo ConfigureApplicationParts
accetta un delegato Action<IApplicationPartManager>
.
I metodi di estensione seguenti in IApplicationPartManager supportano usi comuni:
- ApplicationPartManagerExtensions.AddApplicationPart è possibile aggiungere un singolo assembly usando questo metodo di estensione.
- ApplicationPartManagerExtensions.AddFromAppDomain aggiunge tutti gli assembly attualmente caricati in
AppDomain
. - ApplicationPartManagerExtensions.AddFromApplicationBaseDirectory carica e aggiunge tutti gli assembly nel percorso di base corrente (vedere AppDomain.BaseDirectory).
Gli assembly aggiunti dai metodi precedenti possono essere integrati usando i metodi di estensione seguenti sul tipo restituito, IApplicationPartManagerWithAssemblies:
- ApplicationPartManagerExtensions.WithReferences aggiunge tutti gli assembly a cui si fa riferimento dalle parti aggiunte. In questo modo vengono caricati immediatamente tutti gli assembly a cui si fa riferimento transitivamente. Gli errori di caricamento degli assembly vengono ignorati.
- ApplicationPartManagerCodeGenExtensions.WithCodeGeneration genera il codice di supporto per le parti aggiunte e lo aggiunge al gestore della parte. Si noti che questo richiede l'installazione del pacchetto
Microsoft.Orleans.OrleansCodeGenerator
e viene comunemente definito generazione del codice di runtime.
L'individuazione dei tipi richiede che le parti dell'applicazione specificate includano attributi specifici. L'aggiunta del pacchetto di generazione del codice in fase di compilazione (Microsoft.Orleans.CodeGenerator.MSBuild
o Microsoft.Orleans.OrleansCodeGenerator.Build
) a ogni progetto contenente grani, interfacce granulari o serializzatori è l'approccio consigliato per garantire che questi attributi siano presenti. La generazione di codice in fase di compilazione supporta solo C#. Per F#, Visual Basic e altri linguaggi .NET, il codice può essere generato durante il tempo di configurazione tramite il metodo WithCodeGeneration descritto in precedenza. Altre informazioni sulla generazione del codice sono disponibili nella sezione corrispondente.