Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Orleans proporciona administración de clústeres a través de un protocolo de pertenencia integrado, a veces denominado pertenencia a clústeres. El objetivo de este protocolo es que todos los silos (servidores Orleans) acuerden sobre el grupo de silos actualmente activos, detecten silos con fallos y permitan que nuevos silos se unan al clúster.
Configuración del protocolo de pertenencia
El protocolo de pertenencia usa la siguiente configuración predeterminada:
- Cada silo es supervisado por 10 otros silos
- Se requieren 2 sospechas para declarar un silo como inactivo
- Las sospechas son válidas durante 3 minutos
- Los sondeos se envían cada 10 segundos.
- 3 sondeos perdidos desencadenan una sospecha
Con estos valores predeterminados, el tiempo de detección de errores típico es de aproximadamente 15 segundos. En escenarios de recuperación ante desastres en los que los silos se bloquean sin una limpieza adecuada, el clúster usa la IAmAlive marca de tiempo (actualizada cada 30 segundos de forma predeterminada) para recuperarse; los silos que no han actualizado su marca de tiempo durante varios períodos se omiten durante las comprobaciones de conectividad de inicio. Al omitir estos silos que no responden, los nuevos silos pueden iniciarse y limpiar rápidamente el clúster de silos defectuosos declarándolos inactivos.
Configuración
Puede configurar las opciones del protocolo de pertenencia mediante ClusterMembershipOptions:
siloBuilder.Configure<ClusterMembershipOptions>(options =>
{
// Number of silos each silo monitors (default: 10)
options.NumProbedSilos = 10;
// Number of suspicions required to declare a silo dead (default: 2)
options.NumVotesForDeathDeclaration = 2;
// Time window for suspicions to be valid (default: 180 seconds)
options.DeathVoteExpirationTimeout = TimeSpan.FromSeconds(180);
// Interval between probes (default: 10 seconds)
options.ProbeTimeout = TimeSpan.FromSeconds(10);
// Number of missed probes before suspecting a silo (default: 3)
options.NumMissedProbesLimit = 3;
});
Cuándo ajustar la configuración
En la mayoría de los casos, la configuración predeterminada es adecuada. Sin embargo, puede considerar los ajustes en estos escenarios:
-
Redes de alta latencia: aumente
ProbeTimeoutsi sus silos están distribuidos entre regiones con alta latencia de red. -
Requisitos de disponibilidad críticos: disminuya
DeathVoteExpirationTimeoutpara una detección de errores más rápida, pero tenga cuidado con los falsos positivos.
Configuración del protocolo de pertenencia
El protocolo de pertenencia usa la siguiente configuración predeterminada:
- Cada silo está supervisado por 3 otros silos
- Se requieren 2 sospechas para declarar un silo como inactivo
- Las sospechas son válidas durante 3 minutos
- Los sondeos se envían cada 10 segundos.
- 3 sondeos perdidos desencadenan una sospecha
Configuración del protocolo de pertenencia
El protocolo de pertenencia usa la siguiente configuración predeterminada:
- Cada silo está supervisado por 3 otros silos
- Se requieren 2 sospechas para declarar un silo como inactivo
- Las sospechas son válidas durante 3 minutos
El protocolo se basa en un servicio externo para proporcionar una abstracción de IMembershipTable.
IMembershipTable es una tabla plana y duradera que se usa para dos propósitos. En primer lugar, sirve como punto de encuentro para que los silos se localicen mutuamente y para que los Orleans clientes encuentren los silos. En segundo lugar, almacena la vista actual de pertenencia (lista de silos activos) y ayuda a coordinar el acuerdo sobre esta vista.
Las siguientes implementaciones oficiales de IMembershipTable están disponibles actualmente:
- ADO.NET (PostgreSQL, MySQL/MariaDB, SQL Server, Oracle),
- AWS DynamoDB,
- Apache Cassandra,
- Apache ZooKeeper,
- Azure Cosmos DB,
- Azure Table Storage,
- HashiCorp Consul,
- Redis,
- y una implementación en memoria para desarrollo.
Configuración de clústeres de Redis
Configure Redis como proveedor de clúster utilizando el método de extensión UseRedisClustering.
using StackExchange.Redis;
var builder = Host.CreateApplicationBuilder(args);
builder.UseOrleans(siloBuilder =>
{
siloBuilder.UseRedisClustering(options =>
{
options.ConfigurationOptions = new ConfigurationOptions
{
EndPoints = { "localhost:6379" },
AbortOnConnectFail = false
};
});
});
Como alternativa, puede usar una cadena de conexión:
siloBuilder.UseRedisClustering("localhost:6379");
La RedisClusteringOptions clase proporciona las siguientes opciones de configuración:
| Propiedad | Tipo | Description |
|---|---|---|
ConfigurationOptions |
ConfigurationOptions |
Configuración del cliente StackExchange.Redis. Obligatorio. |
EntryExpiry |
TimeSpan? |
Hora de expiración opcional para las entradas. Establezca esto solo para entornos efímeros como las pruebas. El valor predeterminado es null. |
CreateMultiplexer |
Func<RedisClusteringOptions, Task<IConnectionMultiplexer>> |
Fábrica personalizada para crear el multiplexor de conexiones de Redis. |
CreateRedisKey |
Func<ClusterOptions, RedisKey> |
Función personalizada para generar la clave de Redis para la tabla de pertenencia. El formato predeterminado es {ServiceId}/members/{ClusterId}. |
Importante
Las implementaciones de la IMembershipTable interfaz deben usar un almacén de datos duradero. Por ejemplo, si usa Redis, asegúrese de que la persistencia está habilitada explícitamente. Las configuraciones volátiles pueden dar lugar a que el clúster no esté disponible.
Aspire integración para la agrupación en clústeres
Al usar Aspire, puedes configurar de forma declarativa la agrupación en clúster de Orleans en tu proyecto AppHost. Aspire inyecta automáticamente la configuración necesaria en tus proyectos de silo mediante variables de entorno.
Agrupamiento de clústeres de Redis con Aspire
Proyecto AppHost (Program.cs):
var builder = DistributedApplication.CreateBuilder(args);
var redis = builder.AddRedis("redis");
var orleans = builder.AddOrleans("cluster")
.WithClustering(redis);
builder.AddProject<Projects.MySilo>("silo")
.WithReference(orleans)
.WithReference(redis);
builder.Build().Run();
Proyecto de silo (Program.cs):
var builder = Host.CreateApplicationBuilder(args);
builder.AddServiceDefaults();
builder.AddKeyedRedisClient("redis");
builder.UseOrleans();
builder.Build().Run();
Agrupación en clústeres de Azure Table Storage con Aspire
Proyecto AppHost (Program.cs):
var builder = DistributedApplication.CreateBuilder(args);
var storage = builder.AddAzureStorage("storage")
.RunAsEmulator(); // Use Azurite for local development
var tables = storage.AddTables("clustering");
var orleans = builder.AddOrleans("cluster")
.WithClustering(tables);
builder.AddProject<Projects.MySilo>("silo")
.WithReference(orleans)
.WaitFor(storage);
builder.Build().Run();
Proyecto de silo (Program.cs):
var builder = Host.CreateApplicationBuilder(args);
builder.AddServiceDefaults();
builder.AddKeyedAzureTableServiceClient("clustering");
builder.UseOrleans();
builder.Build().Run();
Sugerencia
Para usar el emulador de Azurite para el desarrollo local, llame a .RunAsEmulator() en el recurso de Azure Storage. Sin esta llamada, Aspire espera una conexión de Azure Storage real.
Agrupación en clústeres de Azure Cosmos DB con Aspire
Proyecto AppHost (Program.cs):
var builder = DistributedApplication.CreateBuilder(args);
var cosmos = builder.AddAzureCosmosDB("cosmos")
.RunAsEmulator(); // Use emulator for local development
var database = cosmos.AddCosmosDatabase("orleans");
var orleans = builder.AddOrleans("cluster")
.WithClustering(database);
builder.AddProject<Projects.MySilo>("silo")
.WithReference(orleans)
.WaitFor(cosmos);
builder.Build().Run();
Proyecto de silo (Program.cs):
var builder = Host.CreateApplicationBuilder(args);
builder.AddServiceDefaults();
builder.AddKeyedAzureCosmosClient("cosmos");
builder.UseOrleans();
builder.Build().Run();
Nota:
AspireLa integración de Cosmos DB para Orleans actualmente solo admite la agrupación en clústeres. Para el almacenamiento de granos y recordatorios con Cosmos DB, deberá configurar esos proveedores manualmente en el proyecto de silo.
Importante
Debe llamar al método AddKeyed* adecuado (como AddKeyedRedisClient, AddKeyedAzureTableServiceClient o AddKeyedAzureCosmosClient) para registrar el recurso subyacente en el contenedor de inyección de dependencias.
Orleans los proveedores buscan recursos por su nombre de servicio con clave: si omite este paso, Orleans no podrá resolver el recurso y producirá un error de resolución de dependencias en tiempo de ejecución.
Para obtener más información sobre Orleans e Aspire integración, consulte Orleans e Aspire integración.
Configuración de clústeres de Cassandra
Configure Apache Cassandra como proveedor de clustering mediante el método de extensión UseCassandraClustering. Instale el paquete NuGet Orleans
dotnet add package Microsoft.Orleans.Clustering.Cassandra
Configure la agrupación en clústeres de Cassandra con una cadena de conexión:
using Orleans.Clustering.Cassandra.Hosting;
var builder = Host.CreateApplicationBuilder(args);
builder.UseOrleans(siloBuilder =>
{
siloBuilder.UseCassandraClustering(
connectionString: "Contact Points=localhost;Port=9042",
keyspace: "orleans");
});
Como alternativa, use la configuración basada en opciones para obtener más control:
siloBuilder.UseCassandraClustering(options =>
{
options.ConfigureClient("Contact Points=cassandra-node1,cassandra-node2;Port=9042", "orleans");
options.UseCassandraTtl = true;
options.InitializeRetryMaxDelay = TimeSpan.FromSeconds(30);
});
O bien, proporcione un generador de sesiones personalizado para escenarios avanzados:
using Cassandra;
siloBuilder.UseCassandraClustering(async serviceProvider =>
{
var cluster = Cluster.Builder()
.AddContactPoints("cassandra-node1", "cassandra-node2")
.WithPort(9042)
.WithCredentials("username", "password")
.WithQueryOptions(new QueryOptions().SetConsistencyLevel(ConsistencyLevel.Quorum))
.Build();
return await cluster.ConnectAsync("orleans");
});
La CassandraClusteringOptions clase proporciona las siguientes opciones de configuración:
| Propiedad | Tipo | Predeterminado | Description |
|---|---|---|---|
UseCassandraTtl |
bool |
false |
Cuando true, configura el tiempo de vida para las filas de la tabla de pertenencia en Cassandra, permitiendo limpiar silos defectuosos incluso si el clúster ya no está en ejecución. Usa DefunctSiloExpiration de ClusterMembershipOptions. |
InitializeRetryMaxDelay |
TimeSpan | 20 segundos | Retraso máximo entre reintentos al encontrar contención durante la inicialización. Esto suele ser necesario con un gran número de silos que se conectan simultáneamente a clústeres de Cassandra de varios centros de datos. |
Cuándo usar la agrupación en clústeres de Cassandra
Considere Cassandra para la agrupación en clústeres cuando:
- Ya tiene una infraestructura de Cassandra en su organización
- Necesita un proveedor de agrupación en clústeres que funcione en varios centros de datos con coherencia ajustable.
- Necesita limpieza automática de silos defectuosos mediante Cassandra TTL incluso cuando el clúster Orleans no se está ejecutando
- Necesita un alto rendimiento de escritura para clústeres grandes
Configuración de clústeres de Azure Cosmos DB
Configure Azure Cosmos DB como proveedor de clústeres mediante el método de extensión UseCosmosClustering. Instale el paquete NuGet Orleans:
dotnet add package Microsoft.Orleans.Clustering.Cosmos
Configure la agrupación en clústeres de Cosmos DB con una cadena de conexión:
using Azure.Identity;
var builder = Host.CreateApplicationBuilder(args);
builder.UseOrleans(siloBuilder =>
{
siloBuilder.UseCosmosClustering(options =>
{
options.ConfigureCosmosClient(
"https://myaccount.documents.azure.com:443/",
new DefaultAzureCredential());
options.DatabaseName = "Orleans";
options.ContainerName = "OrleansCluster";
options.IsResourceCreationEnabled = true;
});
});
Como alternativa, puede usar una cadena de conexión:
siloBuilder.UseCosmosClustering(options =>
{
options.ConfigureCosmosClient("AccountEndpoint=https://myaccount.documents.azure.com:443/;AccountKey=...");
});
La clase CosmosClusteringOptions hereda de CosmosOptions y proporciona las siguientes opciones de configuración:
| Propiedad | Tipo | Predeterminado | Description |
|---|---|---|---|
DatabaseName |
string |
"Orleans" |
Nombre de la base de datos de Cosmos DB. |
ContainerName |
string |
"OrleansCluster" |
Nombre del contenedor para los datos de pertenencia al clúster. |
IsResourceCreationEnabled |
bool |
false |
Cuando true, se crean automáticamente la base de datos y el contenedor si no existen. |
DatabaseThroughput |
int? |
null |
El rendimiento aprovisionado de la base de datos. Si null, usa el modo sin servidor. |
ContainerThroughputProperties |
ThroughputProperties? |
null |
Propiedades de rendimiento del contenedor. |
ClientOptions |
CosmosClientOptions |
new() |
Las opciones que se pasan al cliente de Cosmos DB. |
CleanResourcesOnInitialization |
bool |
false |
Elimina la base de datos en la inicialización. Solo para pruebas. |
Cuándo usar la agrupación en clústeres de Cosmos DB
Tenga en cuenta Azure Cosmos DB para la agrupación en clústeres cuando:
- Ya usa Azure Cosmos DB en la aplicación.
- Necesita una base de datos distribuida globalmente con funcionalidades de escritura en varias regiones.
- Quiere una opción totalmente administrada y sin servidor con escalado automático
- Necesita lecturas y escrituras de baja latencia con SLA garantizados
Para los clientes Orleans, use UseCosmosGatewayListProvider para configurar la detección de puerta de enlace.
builder.UseOrleansClient(clientBuilder =>
{
clientBuilder.UseCosmosGatewayListProvider(options =>
{
options.ConfigureCosmosClient(
"https://myaccount.documents.azure.com:443/",
new DefaultAzureCredential());
});
});
Además de IMembershipTable, cada silo participa en un protocolo de pertenencia punto a punto totalmente distribuido que detecta silos con errores y llega a un acuerdo sobre un conjunto de silos activos. La implementación interna del protocolo de membresía de Orleans se describe a continuación.
Protocolo de pertenencia
Al iniciarse, cada silo agrega una entrada para sí misma a una tabla compartida conocida mediante una implementación de IMembershipTable. Orleans usa una combinación de la identidad del silo (
ip:port:epoch) y el ID de implementación del servicio (ID de clúster) como claves únicas en la tabla. La época es simplemente el tiempo en tics de cuando se inició el silo y, como tal, se garantiza queip:port:epochsea único en una implementación de Orleans determinada.Los silos se supervisan directamente a través de sondeos de aplicación ("¿estás vivo?"
heartbeats). Los sondeos se envían como mensajes directos de silo a silo utilizando los mismos sockets TCP usados para la comunicación normal. De este modo, los sondeos se correlacionan completamente con los problemas de red reales y el estado del servidor. Cada silo sondea un conjunto configurable de otros silos. Un silo elige a quién sondear calculando hashes consistentes sobre las identidades de otros silos, formando un anillo virtual de todas las identidades y seleccionando X silos sucesores en el anillo. (Se trata de una técnica distribuida conocida denominada hash coherente y se usa ampliamente en muchas tablas hash distribuidas, como Chord DHT).Si un silo S no obtiene Y respuestas de sondeo de un servidor P supervisado, sospecha de P escribiendo su sospecha con una marca de tiempo en la fila P de
IMembershipTable.Si P tiene más de Z sospechas dentro de K segundos, S escribe que P está inactivo en la fila de P y envía una instantánea de la tabla de pertenencia actual a todos los demás silos. Silos actualiza la tabla periódicamente, por lo que la instantánea es una optimización para reducir el tiempo necesario para que todos los silos obtengan información sobre la nueva vista de pertenencia.
Con más detalle:
La sospecha se escribe en
IMembershipTable, en una columna especial en la fila que se corresponde con P. Cuando S sospecha de P escribe: «a la hora TTT, S sospechó de P».Una sospecha no es suficiente para declarar A P muerto. Para declarar que P está muerto, necesita reunir Z sospechas de diferentes silos dentro de un período de tiempo configurable T (normalmente 3 minutos). La sospecha se escribe con el control de simultaneidad optimista que ofrece la
IMembershipTable.El silo S que sospecha lee la fila de P.
Si
Ses el último sospechoso (ya ha habido sospechosos Z-1 en el período T, como se registra en la columna de sospecha), S decide declarar P muerto. En este caso, S se agrega a la lista de sospechosos y también escribe en la columna de estado de P que P está Muerto.De lo contrario, si S no es el último sospechoso, S solo se agrega a la columna del sospechoso.
En cualquier caso, la escritura utiliza el número de versión o ETag leído previamente, serializando las actualizaciones de esa fila. Si se produce un error en la escritura debido a un error de coincidencia de versión/ETag, S reintenta (vuelve a leer e intenta escribir, a menos que P ya estuviera marcado como inactivo).
En un nivel alto, esta secuencia de "lectura, modificación local, reescritura" es una transacción. Sin embargo, las transacciones de almacenamiento no se usan necesariamente. El código de «transacción», se ejecuta localmente en un servidor y la simultaneidad optimista proporcionada por
IMembershipTablegarantiza el aislamiento y la atomicidad.
Cada silo periódicamente lee la tabla de pertenencia completa para su implementación. De este modo, los silos aprenden sobre los nuevos silos que se unen y sobre otros silos que se declaran muertos.
Difusión de instantáneas: para reducir la frecuencia de lecturas periódicas de la tabla, cada vez que un silo escribe en la tabla (sospecha, nueva combinación, etc.), envía una instantánea del estado de la tabla actual a todos los demás silos. Dado que la tabla de miembros tiene una versión coherente y monotónica, cada actualización genera una instantánea con una versión única que se puede compartir de forma segura. Esto permite la propagación inmediata de los cambios de pertenencia sin tener que esperar al ciclo de lectura periódico. La lectura periódica se sigue manteniendo como un mecanismo de reserva en caso de que falle la distribución de instantáneas.
Vistas de pertenencia ordenadas: el protocolo de pertenencia garantiza que todas las configuraciones de pertenencia están totalmente ordenadas globalmente. Esta ordenación proporciona dos ventajas clave:
conectividad garantizada: cuando un nuevo silo se une al clúster, debe validar la conectividad bidireccional con cada otro silo activo. Si algún silo existente no responde (lo que podría indicar un problema de conectividad de red), el nuevo silo no puede unirse. Esto garantiza la conectividad completa entre todos los silos del clúster en tiempo de inicio. Consulte la siguiente nota sobre
IAmAlivepara ver una excepción en escenarios de recuperación ante desastres.Actualizaciones coherentes de directorios: los protocolos de nivel superior, como el directorio de grano distribuido, dependen de todos los silos que tengan una vista monotónica coherente de la pertenencia. Esto permite una resolución más inteligente de activaciones de activación duplicadas. Para obtener más información, consulte la documentación del directorio Grain .
detalles de implementación:
El
IMembershipTablerequiere actualizaciones atómicas para garantizar un orden total global de cambios:- Las implementaciones deben actualizar las entradas de tabla (lista de silos) y el número de versión de forma atómica.
- Para ello, use transacciones de base de datos (como en SQL Server) o operaciones de comparación y intercambio atómicas mediante ETags (como en Azure Table Storage).
- El mecanismo específico depende de las funcionalidades del sistema de almacenamiento subyacente.
Una fila especial de versión de pertenencia en la tabla realiza un seguimiento de los cambios:
- Cada escritura en la tabla (sospechas, declaraciones de inactividad, combinaciones) incrementa este número de versión.
- Todas las escrituras se serializan a través de esta fila mediante actualizaciones atómicas.
- La versión que aumenta monótonamente garantiza una ordenación total de todos los cambios en la membresía.
Cuando silo S actualiza el estado del silo P:
- S lee primero el estado de la tabla más reciente.
- En una sola operación atómica, actualiza la fila de P e incrementa el número de versión.
- Si se produce un error en la actualización atómica (por ejemplo, debido a modificaciones simultáneas), la operación se reintenta con retroceso exponencial.
consideraciones de escalabilidad:
La serialización de todas las escrituras a través de la fila de versión puede afectar a la escalabilidad debido a un aumento de la contención. El protocolo ha demostrado ser eficaz en producción con hasta 200 silos, pero podría enfrentar desafíos más allá de mil silos. En el caso de implementaciones muy grandes, otras partes de Orleans (mensajería, directorio de granos, alojamiento) permanecen escalables incluso si las actualizaciones de membresía se convierten en un cuello de botella.
configuración predeterminada: la configuración predeterminada se ha ajustado manualmente durante el uso de producción en Azure. De forma predeterminada: cada silo está supervisado por tres otros silos, dos sospechas son suficientes para declarar un silo muerto, y las sospechas solo se consideran de los últimos tres minutos (de lo contrario, están obsoletas). Los sondeos se envían cada diez segundos y se necesitan tres sondeos para sospechar de un silo.
Autosupervisión: el detector de errores incorpora ideas de la investigación Lifeguard de Hashicorp (artículo, charla, blog) para mejorar la estabilidad del clúster durante eventos catastróficos en los que una gran parte del clúster experimenta un fallo parcial. El componente
LocalSiloHealthMonitorpuntúa el estado de cada silo mediante varias heurística:- Estado activo en la tabla de miembros
- No hay sospechas por parte de otros silos
- Respuestas de sondeo correctos recientes
- Solicitudes de sondeo recientes recibidas
- Capacidad de respuesta del grupo de subprocesos (elementos de trabajo que se ejecutan en menos de un segundo)
- Precisión del temporizador (activación dentro de los 3 segundos del horario programado)
La puntuación de salud de un silo afecta a sus tiempos de espera de sondeo: los silos no saludables (puntuación 1-8) tienen tiempos de espera prolongados en comparación con los silos saludables (puntuación 0). Esto proporciona dos ventajas:
- Proporciona más tiempo para que los sondeos se realicen correctamente cuando la red o el sistema están bajo estrés.
- Hace más probable que los silos incorrectos se voten como inactivos antes de que puedan votar incorrectamente silos correctos.
Esto es especialmente valioso durante escenarios como el agotamiento del grupo de subprocesos hilos, donde los nodos lentos podrían sospechar incorrectamente de nodos que están en buen estado, simplemente porque no pueden procesar las respuestas con la suficiente rapidez.
Sondeo indirecto: otra característica inspirada en Lifeguard que mejora la precisión de la detección de errores al reducir la probabilidad de que un silo averiado o particionado declare incorrectamente como inactivo a un silo saludable. Cuando un silo de supervisión tiene dos intentos de sondeo restantes para un silo de destino antes de declararlo inactivo, emplea sondeos indirectos:
- El silo de supervisión selecciona aleatoriamente otro silo como intermediario y le pide que sondee el destino.
- El intermediario intenta ponerse en contacto con el silo de destino.
- Si el destino no responde dentro del período de tiempo de espera, el intermediario envía una confirmación negativa.
- Si el silo de supervisión recibe una confirmación negativa del intermediario, y el intermediario se declara correcto (mediante autosupervisión), el silo de supervisión emite un voto para declarar inactivo al objetivo.
- Con la configuración predeterminada de dos votos necesarios, una confirmación negativa de un sondeo indirecto cuenta como ambos votos, lo que permite declarar silos inactivos más rápidamente cuando múltiples perspectivas confirman el fallo.
Aplicación de detección perfecta de fallos: una vez que un silo se declara inactivo en la tabla, todos lo consideran inactivo, aunque en realidad no lo esté (por ejemplo, si solo está temporalmente particionado o se han perdido mensajes de latido). Todo el mundo deja de comunicarse con él. Una vez que el silo aprende que está muerto (leyendo su nuevo estado de la tabla), finaliza su proceso. Como consecuencia, debe existir una infraestructura que reinicie el silo como un nuevo proceso (se genera un nuevo número de época al iniciarse). Cuando se hospeda en Azure, esto se produce automáticamente. De lo contrario, se requiere otra infraestructura, como un servicio de Windows configurado para reiniciar automáticamente en caso de error o una implementación de Kubernetes.
¿Qué ocurre si la tabla no es accesible durante algún tiempo:
Cuando el servicio de almacenamiento está inactivo, no disponible o experimenta problemas de comunicación, el Orleans protocolo no declara erróneamente silos inactivos. Los silos operativos siguen funcionando sin problemas. Sin embargo, Orleans no podrá declarar un silo inactivo (si detecta un silo inactivo a través de sondeos perdidos, no puede escribir este hecho en la tabla) y no podrá permitir que los nuevos silos se unan. Por lo tanto, la integridad se ve afectada, pero la exactitud no: la partición de la tabla nunca hace que Orleans declare erróneamente un silo como inactivo. Además, en una partición de red parcial (donde algunos silos pueden tener acceso a la tabla y otros no), Orleans pueden declarar un silo inactivo, pero se tarda tiempo en que todos los demás silos puedan obtener información sobre él. La detección puede retrasarse, pero Orleans nunca elimina erróneamente un silo debido a la indisponibilidad de la tabla.
IAmAliveescribe para diagnósticos y recuperación ante desastres:Además de los latidos enviados entre silos, cada silo actualiza periódicamente una marca de tiempo “Estoy activo” en su fila de la tabla. Esto sirve para dos propósitos:
Diagnósticos: proporciona a los administradores del sistema una manera sencilla de comprobar la vida del clúster y determinar cuándo estaba activo por última vez un silo. La marca de tiempo se actualiza de forma predeterminada cada 30 segundos.
Recuperación ante desastres: si un silo no ha actualizado su marca de tiempo durante varios períodos (configurado a través
NumMissedTableIAmAliveLimitde , valor predeterminado: 3), los nuevos silos lo omiten durante las comprobaciones de conectividad de inicio. Esto permite que el clúster se recupere de escenarios donde los silos se bloquean sin una limpieza adecuada.
Tabla de pertenencia
Como se mencionó, IMembershipTable sirve como punto de encuentro para que los silos se encuentren entre sí y para que Orleans los clientes encuentren silos. También ayuda a coordinar el acuerdo sobre la vista de pertenencia.
La lista siguiente contiene notas de implementación para algunas de las implementaciones oficiales de IMembershipTable:
Azure Table Storage: en esta implementación, el identificador de implementación de Azure actúa como clave de partición y la identidad de silo (
ip:port:epoch) actúa como clave de fila. Juntos, garantizan una clave única por silo. Para el control de simultaneidad, se usa el control de simultaneidad optimista basado en azure Table ETags . Cada vez que se leen los datos de la tabla, se almacena la etiqueta ETag de cada fila de lectura y se usa al intentar volver a escribir. El servicio de tablas de Azure asigna y comprueba automáticamente las etiquetas ETag en cada escritura. En el caso de las transacciones de varias filas, se usa la compatibilidad con transacciones por lotes proporcionadas por Azure Table , lo que garantiza transacciones serializables a través de filas con la misma clave de partición.SQL Server: en esta implementación, el identificador de implementación configurado distingue entre las implementaciones y las silos que pertenecen a las implementaciones. La identidad del silo se define como una combinación de
deploymentID, ip, port, epochen las tablas y columnas correspondientes. El back-end relacional utiliza el control de simultaneidad optimista y las transacciones, de forma parecida a cómo se usan las ETags en la implementación de Azure Table. La implementación relacional espera que el motor de base de datos genere la ETag. Para SQL Server 2000, la ETag generada se adquiere de una llamada aNEWID(). En SQL Server 2005 y versiones posteriores, se usa ROWVERSION . Orleans lee y escribe ETag relacionales como etiquetasVARBINARY(16)opacas y las almacena en memoria como cadenas codificadas en base64. Orleans admite inserciones de varias filas medianteUNION ALL(para Oracle, incluidoDUAL), que se usa actualmente para insertar datos de estadísticas. La implementación y la justificación exactas de SQL Server están disponibles en CreateOrleansTables_SqlServer.sql.Apache ZooKeeper: en esta implementación, el identificador de implementación configurado se usa como nodo raíz y la identidad de silo (
ip:port@epoch) como su nodo secundario. Juntos, garantizan una ruta única para cada silo. Para el control de simultaneidad, se usa el control de simultaneidad optimista basado en la versión del nodo . Cada vez que se leen datos desde el nodo raíz de implementación, se almacena la versión de cada nodo de silo secundario de lectura y se usa esa versión cuando se intenta volver a escribir. Cada vez que cambian los datos de un nodo, el servicio ZooKeeper aumenta de forma atómica el número de versión. En el caso de las transacciones de varias filas, se utiliza el método múltiple , lo que garantiza transacciones serializables a través de nodos de silo con el mismo nodo de identificador de implementación primario.HashiCorp Consul: El almacén Key/Value de Consul se usó para implementar la tabla de pertenencia. Consulte Implementación de Consul para obtener más información.
AWS DynamoDB: en esta implementación, el identificador de implementación del clúster se usa como clave de partición e identidad de silo (
ip-port-generation) como RangeKey, lo que hace que el registro sea único. La concurrencia optimista se logra utilizando el atributoETagpara realizar escrituras condicionales en DynamoDB. La lógica de implementación es bastante parecida a la de Azure Table Storage.Apache Cassandra: en esta implementación, la composición del identificador de servicio y el identificador de clúster actúa como clave de partición y la identidad de silo (
ip:port:epoch) como clave de fila. Juntos, garantizan que haya una única fila por cada silo. Para el control de concurrencia, se usa el control de concurrencia optimista basado en una versión de columna estática mediante una transacción ligera. Esta columna de versión se comparte para todas las filas de la partición o clúster y proporciona un número de versión creciente y consistente para la tabla de miembros de cada clúster. No hay transacciones de varias filas en esta implementación.Emulación en memoria para la configuración de desarrollo: se usa un grano especial del sistema para esta implementación. Este grano reside en un silo primario designado, usado solo en una configuración de desarrollo. En cualquier uso real de producción, no se requiere un silo principal.
Justificación del diseño
Una pregunta natural sería por qué no se debería depender completamente de Apache ZooKeeper o etcd para la implementación de pertenencia al clúster, utilizando potencialmente el soporte integrado de ZooKeeper para la pertenencia de grupos mediante nodos efímeros. ¿Por qué implementar nuestro protocolo de pertenencia? Fundamentalmente, por tres razones:
Implementación u hospedaje en la nube:
Zookeeper no es un servicio hospedado. Esto significa que en un entorno en la nube, Orleans los clientes tendrían que implementar, ejecutar y administrar su instancia de un clúster de ZK. Esta es una carga innecesaria que no se les impuso a los clientes. Con Azure Table, Orleans se basa en un servicio hospedado y administrado, lo que hace que la vida de los clientes sea mucho más sencilla. Básicamente, en la nube, use Cloud como plataforma, no como infraestructura. Por otro lado, al ejecutar en el entorno local y administrar los servidores, confiar en ZK como una implementación de
IMembershipTablees una opción viable.Detección directa de errores:
Al usar la pertenencia a grupos de ZK con nodos efímeros, la detección de errores se realiza entre los servidores de Orleans (clientes ZK) y los servidores ZK. Esto podría no correlacionarse necesariamente con problemas de red reales entre Orleans servidores. El deseo era que la detección de errores refleje con precisión el estado dentro del clúster de comunicación. En concreto, en este diseño, si un Orleans silo no se puede comunicar con
IMembershipTable, no se considera inactivo y puede continuar trabajando. Por el contrario, si se utilizara pertenencia de grupo ZK con nodos efímeros, una desconexión de un servidor ZK podría causar que un silo de Orleans (cliente ZK) se declare inactivo, aunque podría estar activo y completamente funcional.Portabilidad y flexibilidad:
Como parte de la filosofía de Orleans, Orleans no impone una fuerte dependencia de ninguna tecnología concreta o particular, sino que proporciona un diseño flexible donde los distintos componentes se pueden cambiar fácilmente con distintas implementaciones. Este es exactamente el propósito que sirve la
IMembershipTableabstracción.
Propiedades del protocolo de pertenencia
Poder controlar cualquier número de errores:
Este algoritmo puede controlar cualquier número de errores (f<=n), incluido el reinicio completo del clúster. Esto contrasta con las soluciones basadas en Paxos "tradicionales", que requieren un cuórum (normalmente mayoría). Las situaciones de producción han mostrado escenarios en los que más de la mitad de los silos estaban inactivos. El sistema se mantuvo funcional y la pertenencia basada en Paxos no podía avanzar.
El tráfico a la tabla de datos es muy ligero
Los sondeos reales van directamente entre servidores, no a la tabla. Enrutar los sondeos a través de la tabla generaría mucho tráfico y sería menos preciso desde el punto de vista de detección de fallos: si un silo no pudiera acceder a la tabla, no podría escribir su latido “Estoy activo”, y otros lo declararían inactivo.
Comparación entre la precisión ajustable y la integridad:
Aunque no se puede lograr la detección de errores tanto perfecta como precisa, normalmente se desea la capacidad de compensar la precisión (no querer declarar un silo vivo como muerto) con la completitud (desear declarar un silo muerto como tal tan pronto como sea posible). Es posible negociar los dos aspectos mediante los votos configurables para declarar sondeos inactivos y perdidos. Si desea más información, lea Yale University: Computer Science Failure Detector, (Universidad de Yale: Detectores de errores informáticos).
Escala:
El protocolo puede controlar miles, probablemente incluso decenas de miles, de servidores. Esto contrasta con las soluciones tradicionales basadas en Paxos, como los protocolos de comunicación de grupo, que se sabe que no se escalan más allá de decenas de nodos.
Diagnósticos:
La tabla también es muy adecuada para diagnosticar y solucionar problemas. Los administradores del sistema pueden encontrar instantáneamente en la tabla la lista actual de silos activos, además de ver el historial de todos los silos que se desactivaron y las sospechas. Resulta especialmente útil al diagnosticar problemas.
¿Por qué se necesita almacenamiento persistente confiable para la implementación de
IMembershipTable:El almacenamiento persistente se usa para
IMembershipTablepara los dos propósitos. En primer lugar, sirve como punto de encuentro para que los silos se localicen mutuamente y para que los Orleans clientes encuentren los silos. En segundo lugar, el almacenamiento fiable ayuda a coordinar el acuerdo sobre la vista de pertenencia. Aunque la detección de errores se hace directamente de punto a punto entre los silos, se almacena la vista de pertenencia en un almacenamiento seguro y se usa el mecanismo de control de simultaneidad de este almacenamiento para llegar a un acuerdo de quién está activo y quién está inactivo. En cierto sentido, este protocolo externaliza el difícil problema de consenso distribuido a la nube. Al hacerlo, se utiliza toda la potencia de la plataforma en la nube subyacente, usándola verdaderamente como plataforma como servicio (PaaS).IAmAlivedirecto escribe solo en la tabla para diagnósticos:Además de los latidos enviados entre silos, cada silo actualiza periódicamente una marca de tiempo “Estoy activo” en su columna de la tabla. Esta columna "I Am Alive" solo se usa para la solución de problemas y diagnósticos manuales y no la usa el propio protocolo de pertenencia. Normalmente se escribe con una frecuencia mucho menor (una vez cada 5 minutos) y sirve como una herramienta muy útil para que los administradores del sistema comprueben la vida del clúster o averigüen fácilmente cuándo el silo estaba vivo por última vez.
Agradecimientos
Confirmaciones por la contribución de Alex Kogan al diseño e implementación de la primera versión de este protocolo. Este trabajo formó parte de unas prácticas de verano en Microsoft Research en el verano de 2011.
La implementación de ZooKeeper IMembershipTable fue realizada por Shay Hazor, la implementación de SQL IMembershipTable fue realizada por Veikko Eeva, la implementación de AWS DynamoDB IMembershipTable fue realizada por Gutemberg Ribeiro, la implementación de Consul basada IMembershipTable en Fue realizada por Paul North, y finalmente la implementación de Apache Cassandra IMembershipTable fue adaptada de OrleansCassandraUtilsArshia001.