Serverkonfiguration

Ein Silo wird programmgesteuert mit der Erweiterungsmethode UseOrleans(IHostBuilder, Action<HostBuilderContext,ISiloBuilder>) und mehreren zusätzlichen Optionsklassen konfiguriert. Optionsklassen in Orleans folgen dem Optionsmuster in .NET und können über Dateien, Umgebungsvariablen und jeden gültigen Konfigurationsanbieter geladen werden.

Es gibt mehrere wichtige Aspekte bei der Silokonfiguration:

  • Clusteringanbieter
  • (Optional) Orleans-Clusterinformationen
  • (Optional) Endpunkte für die Kommunikation zwischen Silos und für die Kommunikation zwischen Clients und Silos

Im Anschluss sehen Sie ein Beispiel für eine Silokonfiguration, die Clusterinformationen definiert, Azure-Clustering verwendet und die Anwendungsparts konfiguriert:

using IHost host = Host.CreateDefaultBuilder(args)
    .UseOrleans(builder =>
    {
        builder.UseAzureStorageClustering(
            options => options.ConfigureTableServiceClient(connectionString));
    })
    .UseConsoleLifetime()
    .Build();

Tipp

Bei der Entwicklung für Orleans können Sie UseLocalhostClustering(ISiloBuilder, Int32, Int32, IPEndPoint, String, String) aufrufen, um einen lokalen Cluster zu konfigurieren. In Produktionsumgebungen sollten Sie einen Clusteringanbieter verwenden, der für Ihre Bereitstellung geeignet ist.

Clusteringanbieter

siloBuilder.UseAzureStorageClustering(
    options => options.ConfigureTableServiceClient(connectionString))

In der Regel wird ein auf Orleans basierender Dienst auf einem Cluster mit Knoten bereitgestellt, entweder auf dedizierter Hardware oder in der Cloud. Für die Entwicklung und grundlegende Tests kann Orleans in einer Konfiguration mit nur einem Knoten bereitgestellt werden. Bei der Bereitstellung in einem Cluster mit Knoten implementiert Orleans intern eine Reihe von Protokollen zum Ermitteln und Verwalten der Mitgliedschaft von Orleans-Silos im Cluster, einschließlich Erkennung von Knotenfehlern und automatischer Neukonfiguration.

Für die zuverlässige Verwaltung der Clustermitgliedschaft verwendet Orleans Azure Table, SQL Server oder Apache ZooKeeper für die Synchronisierung von Knoten.

In diesem Beispiel wird Azure Table als Mitgliedschaftsanbieter verwendet.

Informationen zum Orleans-Clustering

Verwenden Sie zum optionalen Konfigurieren des Clusterings ClusterOptions als Typparameter für die Configure-Methode in der ISiloBuilder-Instanz.

siloBuilder.Configure<ClusterOptions>(options =>
{
    options.ClusterId = "my-first-cluster";
    options.ServiceId = "SampleApp";
})

Hier geben Sie zwei Optionen an:

  • Legen Sie ClusterId auf "my-first-cluster" fest: Dies ist eine eindeutige ID für den Orleans-Cluster. Alle Clients und Silos, die diese ID verwenden, können direkt miteinander kommunizieren. Sie können jedoch eine andere Cluster-ID (ClusterId) für verschiedene Bereitstellungen verwenden.
  • Legen Sie ServiceId auf "SampleApp" fest: Dies ist eine eindeutige ID für Ihre Anwendung, die von einigen Anbietern (z. B. Persistenzanbietern) verwendet wird. Diese ID sollte gleich bleiben und sich nicht über Bereitstellungen hinweg ändern.

Standardmäßig verwendet Orleans den Wert "default" für ServiceId und ClusterId. Diese Werte müssen in den meisten Fällen nicht geändert werden. ServiceId ist der wichtigere der beiden Werte. Er wird verwendet, um verschiedene logische Dienste voneinander zu unterscheiden, sodass sie Back-End-Speichersysteme gemeinsam nutzen können, ohne sich gegenseitig zu beeinträchtigen. Mithilfe von ClusterId wird ermittelt, welche Hosts eine Verbindung miteinander herstellen und einen Cluster bilden.

In den einzelnen Clustern müssen alle Hosts dieselbe Dienst-ID (ServiceId) verwenden. Mehrere Cluster können jedoch die gleiche Dienst-ID (ServiceId) nutzen. Dadurch werden Szenarien für Blau-Grün-Bereitstellungen ermöglicht, in denen eine neue Bereitstellung (Cluster) gestartet wird, bevor eine andere heruntergefahren wird. Dies ist typisch für Systeme, die in Azure App Service gehostet werden.

Gängiger ist, dass ServiceId und ClusterId während der Lebensdauer der Anwendung beibehalten werden und eine Rolling-Bereitstellungsstrategie verwendet wird. Dies ist typisch für Systeme, die in Kubernetes und Service Fabric gehostet werden.

Endpunkte

Orleans überwacht standardmäßig alle Schnittstellen am Port 11111 für die Kommunikation zwischen Silos und am Port 30000 für die Kommunikation zwischen Clients und Silos. Um dieses Verhalten zu überschreiben, rufen Sie ConfigureEndpoints(ISiloBuilder, Int32, Int32, AddressFamily, Boolean) auf, und übergeben Sie die zu verwendenden Portnummern.

siloBuilder.ConfigureEndpoints(siloPort: 17_256, gatewayPort: 34_512)

Für den Code oben gilt:

  • Der Siloport ist auf 17_256 festgelegt.
  • Der Gatewayport ist auf 34_512 festgelegt.

Ein Orleans-Silo weist zwei typische Arten von Endpunktkonfigurationen auf:

  • Silo-zu-Silo-Endpunkte werden für die Kommunikation zwischen Silos im selben Cluster verwendet.
  • Client-zu-Silo-Endpunkte (oder Gatewayendpunkte) werden für die Kommunikation zwischen Clients und Silos im selben Cluster verwendet.

Diese Methode sollte in den meisten Fällen ausreichend sein, Sie können sie jedoch bei Bedarf weiter anpassen. Hier sehen Sie ein Beispiel für die Verwendung einer externen IP-Adresse mit einer Portweiterleitung:

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);
})

Intern lauscht das Silo an 0.0.0.0:40000 und 0.0.0.0:50000, aber die im Mitgliedschaftsanbieter veröffentlichten Werte lauten 172.16.0.42:11111 und 172.16.0.42:30000.

Ein Silo wird programmgesteuert über SiloHostBuilder und mehrere zusätzliche Optionsklassen konfiguriert. Optionsklassen in Orleans folgen dem Optionsmuster in .NET und können über Dateien, Umgebungsvariablen und jeden gültigen Konfigurationsanbieter geladen werden.

Es gibt mehrere wichtige Aspekte bei der Silokonfiguration:

  • Informationen zum Orleans-Clustering
  • Clusteringanbieter
  • Endpunkte für die Kommunikation zwischen Silos und für die Kommunikation zwischen Clients und Silos
  • Teile der Anwendung

Im Anschluss sehen Sie ein Beispiel für eine Silokonfiguration, die Clusterinformationen definiert, Azure-Clustering verwendet und die Anwendungsparts konfiguriert:

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();

Sehen Sie sich die in diesem Beispiel verwendeten Schritte genauer an:

Clusteringanbieter

siloBuilder.UseAzureStorageClustering(
    options => options.ConnectionString = connectionString)

In der Regel wird ein auf Orleans basierender Dienst auf einem Cluster mit Knoten bereitgestellt, entweder auf dedizierter Hardware oder in der Cloud. Für die Entwicklung und grundlegende Tests kann Orleans in einer Konfiguration mit nur einem Knoten bereitgestellt werden. Bei der Bereitstellung in einem Cluster mit Knoten implementiert Orleans intern eine Reihe von Protokollen zum Ermitteln und Verwalten der Mitgliedschaft von Orleans-Silos im Cluster, einschließlich Erkennung von Knotenfehlern und automatischer Neukonfiguration.

Für die zuverlässige Verwaltung der Clustermitgliedschaft verwendet Orleans Azure Table, SQL Server oder Apache ZooKeeper für die Synchronisierung von Knoten.

In diesem Beispiel wird Azure Table als Mitgliedschaftsanbieter verwendet.

Informationen zum Orleans-Clustering

.Configure<ClusterOptions>(options =>
{
    options.ClusterId = "my-first-cluster";
    options.ServiceId = "AspNetSampleApp";
})

Hier führen Sie zwei Schritte aus:

  • Legen Sie ClusterId auf "my-first-cluster" fest: Dies ist eine eindeutige ID für den Orleans-Cluster. Alle Clients und Silos, die diese ID verwenden, können direkt miteinander kommunizieren. Sie können jedoch eine andere Cluster-ID (ClusterId) für verschiedene Bereitstellungen verwenden.
  • Legen Sie ServiceId auf "AspNetSampleApp" fest: Dies ist eine eindeutige ID für Ihre Anwendung, die von einigen Anbietern (z. B. Persistenzanbietern) verwendet wird. Diese ID sollte gleich bleiben und sich nicht über Bereitstellungen hinweg ändern.

Standardmäßig verwendet Orleans den Wert "default" für ServiceId und ClusterId. Diese Werte müssen in den meisten Fällen nicht geändert werden. ServiceId ist der wichtigere der beiden Werte. Er wird verwendet, um verschiedene logische Dienste voneinander zu unterscheiden, sodass sie Back-End-Speichersysteme gemeinsam nutzen können, ohne sich gegenseitig zu beeinträchtigen. Mithilfe von ClusterId wird ermittelt, welche Hosts eine Verbindung miteinander herstellen und einen Cluster bilden.

In den einzelnen Clustern müssen alle Hosts dieselbe Dienst-ID (ServiceId) verwenden. Mehrere Cluster können jedoch die gleiche Dienst-ID (ServiceId) nutzen. Dadurch werden Szenarien für Blau-Grün-Bereitstellungen ermöglicht, in denen eine neue Bereitstellung (Cluster) gestartet wird, bevor eine andere heruntergefahren wird. Dies ist typisch für Systeme, die in Azure App Service gehostet werden.

Gängiger ist, dass ServiceId und ClusterId während der Lebensdauer der Anwendung beibehalten werden und eine Rolling-Bereitstellungsstrategie verwendet wird. Dies ist typisch für Systeme, die in Kubernetes und Service Fabric gehostet werden.

Endpunkte

siloBuilder.ConfigureEndpoints(siloPort: 11111, gatewayPort: 30000)

Ein Orleans-Silo weist zwei typische Arten von Endpunktkonfigurationen auf:

  • Silo-zu-Silo-Endpunkte. Diese werden für die Kommunikation zwischen Silos im selben Cluster verwendet.
  • Client-zu-Silo-Endpunkte (oder Gatewayendpunkte). Diese werden für die Kommunikation zwischen Clients und Silos im selben Cluster verwendet.

Im Beispiel verwenden Sie die Hilfsmethode .ConfigureEndpoints(siloPort: 11111, gatewayPort: 30000), die den für die Kommunikation zwischen Silos verwendeten Port auf 11111 und den Port für das Gateway auf 30000 festlegt. Diese Methode erkennt, auf welche Schnittstelle gelauscht werden soll.

Diese Methode sollte in den meisten Fällen ausreichend sein, Sie können sie jedoch bei Bedarf weiter anpassen. Hier sehen Sie ein Beispiel für die Verwendung einer externen IP-Adresse mit einer Portweiterleitung:

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);
})

Intern lauscht das Silo an 0.0.0.0:40000 und 0.0.0.0:50000, aber die im Mitgliedschaftsanbieter veröffentlichten Werte lauten 172.16.0.42:11111 und 172.16.0.42:30000.

Teile der Anwendung

siloBuilder.ConfigureApplicationParts(
    parts => parts.AddApplicationPart(
        typeof(ValueGrain).Assembly)
        .WithReferences())

Obwohl dieser Schritt technisch nicht erforderlich ist, wird Entwicklern empfohlen, ihn zu konfigurieren. (Wenn er nicht konfiguriert wird, überprüft Orleans alle Assemblys im aktuellen Ordner.) Dieser Schritt hilft Orleans beim Laden von Benutzerassemblys und -typen. Diese Assemblys werden als Anwendungsparts bezeichnet. Alle Grains, Grainschnittstellen und Serialisierungsmodule werden mithilfe von Anwendungsparts ermittelt.

Anwendungsparts werden mithilfe von IApplicationPartManager konfiguriert. Darauf kann mithilfe der ConfigureApplicationParts-Erweiterungsmethode für IClientBuilder und ISiloHostBuilder zugegriffen werden kann. Die ConfigureApplicationParts-Methode akzeptiert den Delegaten Action<IApplicationPartManager>.

Die folgenden Erweiterungsmethoden für IApplicationPartManager unterstützen gängige Anwendungsfälle:

Assemblys, die von den oben genannten Methoden hinzugefügt werden, können mithilfe der folgenden Erweiterungsmethoden für ihren Rückgabetyp ergänzt werden (IApplicationPartManagerWithAssemblies):

  • ApplicationPartManagerExtensions.WithReferences fügt alle Assemblys, auf die verwiesen wird, aus den hinzugefügten Parts hinzu. Dadurch werden sofort alle Assemblys geladen, auf die transitiv verwiesen wird. Fehler beim Laden von Assemblys werden ignoriert.
  • ApplicationPartManagerCodeGenExtensions.WithCodeGeneration generiert Unterstützungscode für die hinzugefügten Parts und fügt ihn dem Part-Manager hinzu. Beachten Sie, dass hierfür das Paket Microsoft.Orleans.OrleansCodeGenerator installiert werden muss und der Vorgang häufig als Codegenerierung während der Laufzeit bezeichnet wird.

Die Typermittlung erfordert, dass die bereitgestellten Anwendungsparts bestimmte Attribute enthalten. Das Hinzufügen des Pakets für die Codegenerierung zur Buildzeit (Microsoft.Orleans.CodeGenerator.MSBuild oder Microsoft.Orleans.OrleansCodeGenerator.Build) zu jedem Projekt, das Grains, Grainschnittstellen oder Serialisierungsmodule enthält, ist der empfohlene Ansatz, um sicherzustellen, dass diese Attribute vorhanden sind. Die Codegenerierung zur Buildzeit unterstützt nur C#. Für F#, Visual Basic und andere .NET-Sprachen kann Code während der Konfiguration über die oben beschriebene WithCodeGeneration-Methode generiert werden. Weitere Informationen zur Codegenerierung finden Sie im entsprechenden Abschnitt.