Colocação de grãos
Orleans Garante que, quando uma chamada de grão é feita, há uma instância desse grão disponível na memória em algum servidor no cluster para lidar com a solicitação. Se o grão não estiver atualmente ativo no cluster, Orleans escolhe um dos servidores para ativá-lo. Isso é chamado de colocação de grãos. O posicionamento também é uma maneira de equilibrar a carga: até mesmo o posicionamento de grãos ocupados ajuda até mesmo a carga de trabalho em todo o cluster.
O processo de colocação é totalmente configurável: os desenvolvedores podem escolher entre um conjunto de políticas de posicionamento prontas para uso, como lógica aleatória, preferencial local e baseada em Orleans carga, ou lógica personalizada pode ser configurada. Isso permite total flexibilidade na decisão de onde os grãos são criados. Por exemplo, os grãos podem ser colocados em um servidor perto de recursos que eles precisam operar ou perto de outros grãos com os quais eles se comunicam. Por padrão, Orleans escolherá um servidor compatível aleatoriamente.
A estratégia de posicionamento que Orleans usa pode ser configurada globalmente ou por classe de grão.
Colocação aleatória
Um servidor é selecionado aleatoriamente entre os servidores compatíveis no cluster. Essa estratégia de posicionamento é configurada adicionando o RandomPlacementAttribute a um grão.
Colocação local
Se o servidor local for compatível, selecione o servidor local, caso contrário, selecione um servidor aleatório. Essa estratégia de posicionamento é configurada adicionando o PreferLocalPlacementAttribute a um grão.
Posicionamento baseado em hash
Hash o grain id para um inteiro não negativo e modulo-lo com o número de servidores compatíveis. Selecione o servidor correspondente na lista de servidores compatíveis ordenados por endereço do servidor. Observe que não é garantido que isso permaneça estável à medida que a associação do cluster muda. Especificamente, adicionar, remover ou reiniciar servidores pode alterar o servidor selecionado para um determinado ID de grão. Como os grãos colocados usando essa estratégia são registrados no diretório de grãos, essa mudança na decisão de colocação como alterações de associação normalmente não tem um efeito percetível.
Essa estratégia de posicionamento é configurada adicionando o HashBasedPlacementAttribute a um grão.
Posicionamento baseado na contagem de ativação
Esta estratégia de colocação pretende colocar novas ativações de grãos no servidor menos carregado com base no número de grãos ocupados recentemente. Ele inclui um mecanismo no qual todos os servidores publicam periodicamente sua contagem total de ativação para todos os outros servidores. Em seguida, o diretor de posicionamento seleciona um servidor que se prevê ter o menor número de ativações examinando a contagem de ativação relatada mais recentemente e prevê a contagem de ativação atual com base na contagem de ativação recente feita pelo diretor de posicionamento no servidor atual. O diretor seleciona vários servidores aleatoriamente ao fazer essa previsão, para evitar que vários servidores separados sobrecarreguem o mesmo servidor. Por padrão, dois servidores são selecionados aleatoriamente, mas esse valor é configurável via ActivationCountBasedPlacementOptions.
Este algoritmo é baseado na tese The Power of Two Choices in Randomized Load Balancing de Michael David Mitzenmacher, e também é usado no Nginx para balanceamento de carga distribuído, conforme descrito no artigo NGINX e no algoritmo de balanceamento de carga "Power of Two Choices".
Essa estratégia de posicionamento é configurada adicionando o ActivationCountBasedPlacementAttribute a um grão.
Colocação de trabalhadores apátridas
A colocação de trabalhadores apátridas é uma estratégia especial de colocação usada por trabalhadores apátridas. Este posicionamento opera de forma PreferLocalPlacement quase idêntica, exceto que cada servidor pode ter várias ativações do mesmo grão e o grão não está registrado no diretório de grãos, pois não há necessidade.
Essa estratégia de posicionamento é configurada adicionando o StatelessWorkerAttribute a um grão.
Colocação baseada em silos
Uma estratégia determinística de colocação que coloca grãos em silos com um papel específico. Essa estratégia de posicionamento é configurada adicionando o SiloRoleBasedPlacementAttribute a um grão.
Posicionamento otimizado para recursos
A estratégia de posicionamento otimizado para recursos tenta otimizar os recursos do cluster equilibrando ativações de grãos entre silos com base na memória disponível e no uso da CPU. Ele atribui pesos às estatísticas de tempo de execução para priorizar recursos diferentes e calcula uma pontuação normalizada para cada silo. O silo com a pontuação mais baixa é escolhido para colocar a próxima ativação. A normalização garante que cada propriedade contribua proporcionalmente para a pontuação geral. Os pesos podem ser ajustados ResourceOptimizedPlacementOptions com base nos requisitos e prioridades específicos do utilizador para diferentes recursos.
Além disso, essa estratégia de posicionamento expõe uma opção para construir uma preferência mais forte pelo silo local (aquele que recebeu o pedido para fazer um novo posicionamento) a ser escolhido como alvo para a ativação. Isto é controlado através da LocalSiloPreferenceMargin
propriedade que faz parte das opções.
Além disso, um algoritmo on-line adaptativo fornece um efeito de suavização que evita quedas rápidas de sinal, transformando-o em um processo de decaimento polinomial. Isso é especialmente importante para o uso da CPU e, em geral, contribui para evitar a saturação de recursos nos silos, especialmente recém-ingressados uma vez.
Este algoritmo baseia-se em: Colocação baseada em recursos com filtragem cooperativa de modo duplo Kalman
Essa estratégia de posicionamento é configurada adicionando o ResourceOptimizedPlacementAttribute a um grão.
Escolha uma estratégia de posicionamento
Escolher a estratégia de colocação de grãos adequada, além dos padrões que Orleans fornece, requer monitoramento e avaliação do desenvolvedor. A escolha da estratégia de posicionamento deve ser baseada no tamanho e na complexidade do aplicativo, nas características da carga de trabalho e no ambiente de implantação.
A colocação aleatória depende da Lei dos Grandes Números, por isso geralmente é um bom padrão quando há uma carga imprevisível espalhada por um grande número de grãos (mais de 10.000).
O posicionamento baseado na contagem de ativação também tem um elemento aleatório, confiando no princípio Power of Two Choices, que é um algoritmo comumente usado para balanceamento de carga distribuído e é usado em balanceadores de carga populares. Os silos frequentemente publicam estatísticas de tempo de execução para outros silos no cluster, incluindo:
- Memória disponível, memória física total e uso de memória.
- Utilização da CPU.
- Contagem total de ativações e contagem de ativações ativas recentes.
- Uma janela deslizante de ativações que estavam ativas nos últimos segundos, às vezes referida como o conjunto de trabalho de ativação.
A partir dessas estatísticas, apenas as contagens de ativação são atualmente usadas para determinar a carga em um determinado silo.
Em última análise, você deve experimentar diferentes estratégias e monitorar métricas de desempenho para determinar o melhor ajuste. Ao selecionar a estratégia de posicionamento de grãos correta, você pode otimizar o desempenho, a escalabilidade e a relação custo-benefício de seus Orleans aplicativos.
Configurar a estratégia de posicionamento padrão
Orleans usará posicionamento aleatório, a menos que o padrão seja substituído. A estratégia de posicionamento padrão pode ser substituída registrando uma implementação de PlacementStrategy durante a configuração:
siloBuilder.ConfigureServices(services =>
services.AddSingleton<PlacementStrategy, MyPlacementStrategy>());
Configurar a estratégia de posicionamento para um grão
A estratégia de posicionamento para um tipo de grão é configurada adicionando o atributo apropriado na classe de grão. Os atributos relevantes são especificados nas seções de estratégias de posicionamento.
Exemplo de estratégia de posicionamento personalizada
Primeiro, defina uma classe que implemente a IPlacementDirector interface, exigindo um único método. Neste exemplo, assumimos que você tem uma função GetSiloNumber
definida que retornará um número de silo dado o Guid do grão prestes a ser criado.
public class SamplePlacementStrategyFixedSiloDirector : IPlacementDirector
{
public Task<SiloAddress> OnAddActivation(
PlacementStrategy strategy,
PlacementTarget target,
IPlacementContext context)
{
var silos = context.GetCompatibleSilos(target).OrderBy(s => s).ToArray();
int silo = GetSiloNumber(target.GrainIdentity.PrimaryKey, silos.Length);
return Task.FromResult(silos[silo]);
}
}
Em seguida, você precisa definir duas classes para permitir que classes de grãos sejam atribuídas à estratégia:
[Serializable]
public sealed class SamplePlacementStrategy : PlacementStrategy
{
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class SamplePlacementStrategyAttribute : PlacementAttribute
{
public SamplePlacementStrategyAttribute() :
base(new SamplePlacementStrategy())
{
}
}
Em seguida, basta marcar todas as classes de grãos que você deseja usar essa estratégia com o atributo:
[SamplePlacementStrategy]
public class MyGrain : Grain, IMyGrain
{
// ...
}
E, finalmente, registre a estratégia quando você construir o SiloHost:
private static async Task<ISiloHost> StartSilo()
{
var builder = new HostBuilder(c =>
{
// normal configuration methods omitted for brevity
c.ConfigureServices(ConfigureServices);
});
var host = builder.Build();
await host.StartAsync();
return host;
}
private static void ConfigureServices(IServiceCollection services)
{
services.AddSingletonNamedService<
PlacementStrategy, SamplePlacementStrategy>(
nameof(SamplePlacementStrategy));
services.AddSingletonKeyedService<
Type, IPlacementDirector, SamplePlacementStrategyFixedSiloDirector>(
typeof(SamplePlacementStrategy));
}
Para um segundo exemplo simples mostrando o uso adicional do contexto de posicionamento, consulte o PreferLocalPlacementDirector
Orleans repositório no código-fonte