Configuración del servidor

Un silo se configura mediante programación con el método de extensión UseOrleans(IHostBuilder, Action<HostBuilderContext,ISiloBuilder>) y varias clases de opciones complementarias. Las clases de opciones de Orleans siguen el Patrón de opciones de .NET y pueden cargarse mediante archivos, variables de entorno o cualquier otro proveedor de configuración válido.

Hay varios aspectos clave de la configuración del silo:

  • Proveedor de la agrupación en clústeres
  • (Opcional) Información de la agrupación en clústeres de Orleans
  • (Opcional) Puntos de conexión que se usarán para las comunicaciones de silo a silo y de cliente a silo

Este es un ejemplo de una configuración de silo que define la información del clúster, usa la agrupación en clústeres de Azure y configura los elementos de la aplicación:

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

Sugerencia

Al desarrollar para Orleans, puede llamar a UseLocalhostClustering(ISiloBuilder, Int32, Int32, IPEndPoint, String, String) para configurar un clúster local. En entornos de producción, debe usar un proveedor de agrupación en clústeres adecuado para la implementación en cuestión.

Proveedor de la agrupación en clústeres

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

Por lo general, un servicio basado en Orleans se implementa en un clúster de nodos, ya sea en hardware dedicado o en la nube. Para el desarrollo y las pruebas básicas, Orleans se puede implementar en una configuración de nodo único. Cuando se implementa en un clúster de nodos, Orleans implementa internamente un conjunto de protocolos para detectar y mantener la pertenencia a silos de Orleans en el clúster, incluida la detección de errores de nodo y la reconfiguración automática.

Para una administración confiable de la pertenencia a clústeres, Orleans usa Azure Table, SQL Server o Apache ZooKeeper para la sincronización de nodos.

En este ejemplo, se usa Azure Table como proveedor de pertenencia.

Información de la agrupación en clústeres de Orleans

Para configurar opcionalmente la agrupación en clústeres, use ClusterOptions como parámetro de tipo para el método Configure en la instancia de ISiloBuilder.

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

Aquí se especifican dos opciones:

  • Establecer ClusterId en "my-first-cluster": se trata de un identificador único para el clúster de Orleans. Todos los clientes y silos que usan este Id. podrán comunicarse directamente entre sí. Sin embargo, puede optar por usar otro ClusterId para diferentes implementaciones.
  • Establezca ServiceId en "SampleApp": se trata de un Id. único para la aplicación que usarán algunos proveedores, como los proveedores de persistencia. Este Id. debería permanecer estable y no cambiar entre implementaciones.

De manera predeterminada, Orleans usará un valor de "default" para ServiceId y ClusterId. En la mayoría de los casos, no es necesario cambiar estos valores. ServiceId es el más significativo de los dos y se utiliza para distinguir los distintos servicios lógicos para que puedan compartir sistemas de almacenamiento back-end sin interferir entre sí. ClusterId se usa para determinar los hosts que se conectarán entre sí y formarán un clúster.

Dentro de cada clúster, todos los hosts deben usar el mismo ServiceId. Sin embargo, varios clústeres pueden compartir un ServiceId. Esto permite escenarios de implementación azul-verde en los que se inicia una implementación nueva (clúster) antes de apagar otra. Esto es típico para los sistemas que se hospedan en Azure App Service.

El caso más común es que ServiceId y ClusterId permanecen fijos durante la vigencia de la aplicación y se usa una estrategia de implementación gradual. Esto es típico para los sistemas que se hospedan en Kubernetes y Service Fabric.

Puntos de conexión

De manera predeterminada, Orleans escuchará en todas las interfaces en el puerto 11111 para la comunicación de silo a silo y en el puerto 30000 para la comunicación de cliente a silo. Para reemplazar este comportamiento, llame a ConfigureEndpoints(ISiloBuilder, Int32, Int32, AddressFamily, Boolean) y pase los números de puerto que desea usar.

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

En el código anterior:

  • El puerto de silo se establece en 17_256.
  • El puerto de puerta de enlace se establece en 34_512.

Un silo de Orleans tiene dos tipos típicos de configuración de punto de conexión:

  • Los puntos de conexión de silo a silo se usan para la comunicación entre silos en el mismo clúster.
  • Los puntos de conexión de cliente a silo (o puerta de enlace) se usan para la comunicación entre clientes y silos en el mismo clúster.

Este método debe ser suficiente en la mayoría de los casos, pero puede personalizarlo aún más si es necesario. Este es un ejemplo de cómo usar una dirección IP externa con reenvío de puertos:

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, el silo escuchará en 0.0.0.0:40000 y 0.0.0.0:50000, pero el valor publicado en el proveedor de pertenencia será 172.16.0.42:11111 y 172.16.0.42:30000.

Un silo se configura mediante programación a través de SiloHostBuilder y de varias clases de opciones complementarias. Las clases de opciones de Orleans siguen el Patrón de opciones de .NET y pueden cargarse mediante archivos, variables de entorno o cualquier otro proveedor de configuración válido.

Hay varios aspectos clave de la configuración del silo:

  • Información de la agrupación en clústeres de Orleans
  • Proveedor de la agrupación en clústeres
  • Puntos de conexión que se usarán para las comunicaciones de silo a silo y de cliente a silo
  • Elementos de la aplicación

Este es un ejemplo de una configuración de silo que define la información del clúster, usa la agrupación en clústeres de Azure y configura los elementos de la aplicación:

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

Vamos a desglosar los pasos que se usan en este ejemplo:

Proveedor de la agrupación en clústeres

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

Por lo general, un servicio basado en Orleans se implementa en un clúster de nodos, ya sea en hardware dedicado o en la nube. Para el desarrollo y las pruebas básicas, Orleans se puede implementar en una configuración de nodo único. Cuando se implementa en un clúster de nodos, Orleans implementa internamente un conjunto de protocolos para detectar y mantener la pertenencia a silos de Orleans en el clúster, incluida la detección de errores de nodo y la reconfiguración automática.

Para una administración confiable de la pertenencia a clústeres, Orleans usa Azure Table, SQL Server o Apache ZooKeeper para la sincronización de nodos.

En este ejemplo, usamos Azure Table como proveedor de pertenencia.

Información de la agrupación en clústeres de Orleans

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

Aquí hacemos dos cosas:

  • Establecer ClusterId en "my-first-cluster": se trata de un identificador único para el clúster de Orleans. Todos los clientes y silos que usan este Id. podrán comunicarse directamente entre sí. Sin embargo, puede optar por usar otro ClusterId para diferentes implementaciones.
  • Establezca ServiceId en "AspNetSampleApp": se trata de un Id. único para la aplicación que usarán algunos proveedores, como los proveedores de persistencia. Este Id. debería permanecer estable y no cambiar entre implementaciones.

De manera predeterminada, Orleans usará un valor de "default" para ServiceId y ClusterId. En la mayoría de los casos, no es necesario cambiar estos valores. ServiceId es el más significativo de los dos y se utiliza para distinguir los distintos servicios lógicos para que puedan compartir sistemas de almacenamiento back-end sin interferir entre sí. ClusterId se usa para determinar los hosts que se conectarán entre sí y formarán un clúster.

Dentro de cada clúster, todos los hosts deben usar el mismo ServiceId. Sin embargo, varios clústeres pueden compartir un ServiceId. Esto permite escenarios de implementación azul-verde en los que se inicia una implementación nueva (clúster) antes de apagar otra. Esto es típico para los sistemas que se hospedan en Azure App Service.

El caso más común es que ServiceId y ClusterId permanecen fijos durante la vigencia de la aplicación y se usa una estrategia de implementación gradual. Esto es típico para los sistemas que se hospedan en Kubernetes y Service Fabric.

Puntos de conexión

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

Un silo de Orleans tiene dos tipos típicos de configuración de punto de conexión:

  • Puntos de conexión de silo a silo, que se usan para la comunicación entre silos en el mismo clúster
  • Puntos de conexión de cliente a silo (o puerta de enlace), que se usan para la comunicación entre clientes y silos en el mismo clúster

En el ejemplo, se usa el método auxiliar .ConfigureEndpoints(siloPort: 11111, gatewayPort: 30000), que establece el puerto usado para la comunicación de silo a silo en 11111 y el puerto de la puerta de enlace en 30000. Este método detectará la interfaz que hay que escuchar.

Este método debe ser suficiente en la mayoría de los casos, pero puede personalizarlo aún más si es necesario. Este es un ejemplo de cómo usar una dirección IP externa con reenvío de puertos:

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, el silo escuchará en 0.0.0.0:40000 y 0.0.0.0:50000, pero el valor publicado en el proveedor de pertenencia será 172.16.0.42:11111 y 172.16.0.42:30000.

Elementos de la aplicación

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

Aunque este paso no es técnicamente necesario (si no está configurado, Orleans examinará todos los ensamblados de la carpeta actual), se recomienda a los desarrolladores que lo configuren. Este paso ayudará a Orleans a cargar los ensamblados y tipos de usuario. Estos ensamblados se conocen como Elementos de la aplicación. Todos los Granos, Interfaces de granos y Serializadores se detectan mediante Elementos de la aplicación.

Los Elementos de la aplicación se configuran mediante IApplicationPartManager, al que se puede tener acceso mediante el método de extensión ConfigureApplicationParts en IClientBuilder y ISiloHostBuilder. El método ConfigureApplicationParts acepta un delegado, Action<IApplicationPartManager>.

Los métodos de extensión siguientes en IApplicationPartManager admiten usos comunes:

Los ensamblados agregados por los métodos anteriores se pueden complementar mediante los métodos de extensión siguientes en su tipo de valor devuelto, IApplicationPartManagerWithAssemblies:

  • ApplicationPartManagerExtensions.WithReferences agrega todos los ensamblados de las partes agregadas a los que se hace referencia. Esto carga inmediatamente los ensamblados a los que se hace referencia transitivamente. Los errores de carga de los ensamblados se omiten.
  • ApplicationPartManagerCodeGenExtensions.WithCodeGeneration genera código de compatibilidad para los elementos agregados y lo agrega al administrador de elementos. Tenga en cuenta que esto requiere que se instale el paquete Microsoft.Orleans.OrleansCodeGenerator y se conoce normalmente como generación de código en tiempo de ejecución.

La detección de tipos requiere que los Elementos de aplicación proporcionados incluyan atributos específicos. Agregar el paquete de generación de código en tiempo de compilación (Microsoft.Orleans.CodeGenerator.MSBuild o Microsoft.Orleans.OrleansCodeGenerator.Build) a cada proyecto que contiene Granos, Interfaces de granos o Serializadores es el enfoque recomendado para asegurarse de que estos atributos están presentes. La generación de código en tiempo de compilación solo admite C#. En el caso de F#, Visual Basic y otros lenguajes de .NET, el código se puede generar durante el tiempo de configuración mediante el método WithCodeGeneration descrito anteriormente. Puede encontrar más información sobre la generación de código en la sección correspondiente.