Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
O Orleans foi desenvolvido para simplificar muito a criação de aplicativos escalonáveis distribuídos, especialmente para a nuvem. O Orleans inventou o Modelo de Ator Virtual como uma evolução do Modelo de Ator otimizado para cenários de nuvem.
Granularidade (atores virtuais) são os blocos de construção base de um aplicativo baseado em Orleans. Eles encapsulam o estado e o comportamento das entidades de aplicativo e mantêm seu ciclo de vida. O modelo de programação do Orleans e as características de seu runtime se ajustam melhor a alguns tipos de aplicativos do que outros. A finalidade deste documento é capturar alguns dos padrões de aplicativo testados e comprovados que funcionam bem no Orleans.
Aplicativos adequados
Considere Orleans quando:
- Número significativo (centenas, milhões, bilhões e até trilhões) de entidades vagamente acopladas. Para colocar o número em perspectiva, o Orleans pode facilmente criar uma granularidade para cada pessoa na Terra em um pequeno cluster, desde que um subconjunto desse número total esteja ativo a qualquer momento.
- Exemplos: perfis de usuário, pedidos de compra, sessões de aplicativo/jogo, ações.
- As entidades são pequenas o suficiente para serem de thread único.
- Exemplo: determine se a ação deve ser comprada com base no preço atual.
- A carga de trabalho é interativa.
- Exemplo: request-response, start/monitor/complete.
- Mais de um servidor é esperado ou pode ser necessário.
- O Orleans é executado em um cluster que é expandido adicionando servidores para expandir o cluster.
- A coordenação global não é necessária ou em uma escala menor entre algumas entidades de cada vez.
- A escalabilidade e o desempenho da execução são obtidos paralelizando e distribuindo um grande número de tarefas, na sua maior parte independentes sem um único ponto de sincronização.
Aplicativos inadequados
O Orleans não é a melhor opção quando:
- A memória deve ser compartilhada entre entidades.
- Cada granularidade mantém seus estados e não deve ser compartilhado.
- Um pequeno número de entidades grandes pode ser multithreaded.
- Um microsserviço pode ser uma opção melhor ao dar suporte à lógica complexa em um único serviço.
- Coordenação global e/ou consistência são necessárias.
- Essa coordenação global limitaria severamente o desempenho de um aplicativo baseado no Orleans. O Orleans foi desenvolvido para escalar facilmente para uma escala global sem a necessidade de coordenação manual aprofundada.
- Operações que são executadas por muito tempo.
- Trabalhos em lote, tarefas SIMD (Single Instruction Multiple Data).
- Isso depende da necessidade do aplicativo e pode ser adequado para o Orleans.
Visão geral de granularidades
- As granularidades se assemelham a objetos. No entanto, elas são distribuídas, virtuais e assíncronas.
- Elas são vagamente acopladas, isoladas e primariamente independentes.
- Cada granularidade é encapsulado, o que também mantém seu estado independentemente de outras granularidades.
- As granularidades falham de forma independente.
- Evite a comunicação intensa entre granularidades.
- O uso de memória direta é significativamente menos caro do que a passagem de mensagens.
- Granularidades altamente ativas podem ser melhor combinadas como uma única granularidade.
- A complexidade/tamanho dos argumentos e da serialização precisa ser considerada.
- Desserializar duas vezes pode ser mais caro do que reenviar uma mensagem binária.
- Evite granularidades de gargalo.
- Coordenador único/Registro/Monitor.
- Faça a agregação em etapas, se necessário.
Assíncronicidade
- Sem bloqueio de thread: todos os itens devem ser Assíncronos (TAP [Programação Assíncrona da Tarefa]).
- await é a melhor sintaxe a ser usada ao redigir operações assíncronas.
- Cenários comuns:
Retornar um valor concreto:
return Task.FromResult(value);
Retornar um
Task
do mesmo tipo:return foo.Bar();
await
umTask
e continuar a execução:var x = await bar.Foo(); var y = DoSomething(x); return y;
Fan-out:
var tasks = new List<Task>(); foreach (var grain in grains) { tasks.Add(grain.Foo()); } await Task.WhenAll(tasks); DoMoreWork();
Implementação de granularidades
- Nunca execute uma operação de bloqueio de thread em uma granularidade. Todas as operações que não sejam computações locais devem ser explicitamente assíncronas.
- Exemplos: aguardando de forma síncrona uma operação de E/S ou uma chamada de serviço Web, bloqueio, execução de um loop excessivo que está aguardando uma condição e assim por diante.
- Quando usar StatelessWorkerAttribute:
- Operações funcionais, como descriptografia, descompactação e antes do encaminhamento para processamento.
- Quando somente granularidades locais são necessárias em várias ativações.
- Exemplo: executa bem com a agregação em etapas no silo local primeiro.
- As granularidades não são reentrantes por padrão.
- O deadlock pode ocorrer devido a ciclos de chamada.
- Exemplos:
- A granularidade chama a si mesmo.
- A granularidade A chama B que chama C que por sua vez está chamando A (A -> B -> C -> A).
- Ganularidade A chama B como Granularidade B está chamando a A (A -> B -> A).
- Os tempos limite são usados para interromper automaticamente deadlocks.
- ReentrantAttribute pode ser usado para permitir a reentrância da classe de granularidade.
- O reentrante ainda é de thread único, no entanto, ele pode se intercalar (dividir processamento/memória entre tarefas).
- O tratamento de intercalação aumenta o risco por ser propenso a erros.
- Herança:
- As classes granuladas herdam da classe de base de granularidade. As interfaces de granularidade (uma ou mais) podem ser adicionadas a cada granularidade.
- A desambiguação pode ser necessária para implementar a mesma interface em várias classes de granularidade.
- Há suporte para genéricos.
Persistência de estado de granularidade
As APIs de persistência de estado de granularidade do Orleans foram criadas para serem fáceis de usar e fornecer funcionalidade de armazenamento extensível.
- Orleans.IGrainState é estendida por uma interface .NET que contém campos que devem ser incluídos no estado persistente do granularidade.
- As granularidades apresentam persistência usando IPersistentState<TState> é estendido pela classe de granularidades que adiciona uma propriedade com um forte tipo
State
na classe base do granularidade. - A inicialização Grain<TGrainState>.ReadStateAsync() ocorre automaticamente antes
ActiveAsync()
de ter sido chamada para granularidade. - Quando os dados do objeto de estado de granularidade são alterados, ela deve chamar Grain<TGrainState>.WriteStateAsync().
- Normalmente, as granularidades chamam
State.WriteStateAsync()
no final do método de granularidade para retornar a promessa de gravação. - O provedor de armazenamento poderia tentar colocar gravações em lote que podem aumentar a eficiência, mas os contratos comportamentais e as configurações são ortogonais (independentes) para a API de armazenamento usada pelo granularidade.
- Um temporizador é um método alternativo para gravar atualizações periodicamente.
- O temporizador permite que o aplicativo determine a quantidade de "consistência eventual"/apátrida permitida.
- O tempo (imediato/nenhum/minutos) também pode ser controlado quanto a quando atualizar.
- PersistentStateAttribute classes decoradas, como outras classes de granularidade, só podem ser associadas a um provedor de armazenamento.
- O atributo StorageProvider(ProviderName = "name") associa a classe de granularidade a um provedor específico.
-
<StorageProvider>
precisará ser adicionado ao arquivo de configuração do silo, que também deve incluir o "nome" correspondente de[StorageProvider(ProviderName="name")]
.
- Normalmente, as granularidades chamam
Provedores de armazenamento
Provedores embutidos de armazenamento:
O Orleans.Storage abriga todos os provedores de armazenamento internos.
MemoryStorage (Os dados armazenados na memória sem persistência durável) são usados apenas para depuração e teste de unidade.
AzureTableStorage:
- Configure as informações da conta de armazenamento do Azure com uma opção AzureTableStorageOptions.DeleteStateOnClear (exclusões rígidas ou temporárias).
- O serializador do Orleans armazena com eficiência dados JSON em uma célula de tabela do Azure.
- Limite de tamanho de dados == tamanho máximo da coluna do Azure, que é de 64 kb de dados binários.
- Código de contribuição da comunidade que estende o uso de várias colunas de tabela, o que aumenta o tamanho máximo geral para 1MB.
Dicas de depuração do provedor de armazenamento
- TraceOverride Verbose3 registrará muito mais informações sobre operações de armazenamento.
- Atualizar o arquivo de configuração do silo.
- LogPrefix="Storage" para todos os provedores ou tipo específico usando "Storage.Memory" / "Storage.Azure" / "Storage.Shard".
Como lidar com falhas de operação de armazenamento:
- Os provedores de armazenamento e granularidades podem aguardar as operações de armazenamento e tentar novamente as falhas, conforme necessário.
- Falhas sem tratamento serão propagadas de volta para o chamador e serão vistas pelo cliente como uma promessa quebrada.
- Além da leitura inicial, não há um conceito que destrua automaticamente as ativações se uma operação de armazenamento falhar.
- Repetir o armazenamento com falha não é um recurso padrão para provedores de armazenamento internos.
Dicas de persistência de granularidade
Tamanho da granularidade:
- A taxa de transferência ideal é obtida usando várias granularidades menores em vez de algumas maiores. No entanto, a melhor prática de escolher um tamanho e tipo de granularidade baseia-se no modelo de domínio do aplicativo.
- Exemplo: usuários, pedidos etc.
Alteração externa de dados:
As granularidades podem ler novamente os dados de estado atuais do armazenamento usando
State.ReadStateAsync()
.Um temporizador também pode ser usado para ler novamente os dados do armazenamento periodicamente também.
- Os requisitos funcionais podem ser baseados em uma "desatualização" adequada das informações.
- Exemplo: granularidade de cache de conteúdo.
Adicionando e removendo campos.
- O provedor de armazenamento determinará os efeitos da adição e remoção de campos adicionais de seu estado persistente.
- A tabela do Azure não dá suporte a esquemas e deve se ajustar automaticamente aos campos adicionais.
Gravando provedores personalizados:
- Os provedores de armazenamento são simples de escrever, o que também é um elemento de extensão significativo para o Orleans.
- O contrato de API GrainState da API orienta o contrato de API de armazenamento (
Write
,Clear
,ReadStateAsync
). - O comportamento de armazenamento normalmente é configurável (gravação em lote, exclusões rígidas ou temporárias e assim por diante) e definido pelo provedor de armazenamento.
Gerenciamento de clusters
- O Orleans gerencia clusters automaticamente.
- Nós com falha, ou seja, que podem falhar e ingressar a qualquer momento, são tratados automaticamente pelo Orleans.
- A mesma tabela de instância de silo criada para o protocolo de clustering também pode ser usada para diagnóstico. A tabela mantém um histórico de todos os silos no cluster.
- Há também opções de configuração de detecção de falha agressiva ou mais branda.
- Falhas podem ocorrer a qualquer momento e são uma ocorrência normal.
- Caso um silo falhe, as granularidades que foram ativadas no silo com falha serão automaticamente reativadas posteriormente em outros silos dentro do cluster.
- As granularidades podem ter tempo limite. Uma solução de repetição, como Polly, pode ajudar com novas tentativas.
- O Orleans fornece uma garantia de entrega de mensagens em que cada mensagem é entregue no máximo uma vez.
- É responsabilidade do chamador repetir as chamadas com falha, se necessário.
- A prática comum é tentar novamente de ponta a ponta do cliente/front-end.
Gerenciamento de implantação e produção
Aumento e redução de escala:
- Monitorar o SLA (Contrato de Nível de Serviço)
- Adicionar ou remover instâncias
- O Orleans reequilibra automaticamente e aproveita o novo hardware. No entanto, as granularidades ativadas não são rebalanceadas quando um novo silo é adicionado ao cluster.
Depuração e testes
- Monitoramento, rastreamento e registro em log:
Injetar registro em log usando a injeção de dependência:
public HelloGrain(ILogger<HelloGrain> logger) { _logger = logger; }
Microsoft.Extensions.Logging é utilizado para registro em log funcional e flexível.
Teste:
- O pacote NuGet
Microsoft.Orleans.TestingHost
contém TestCluster que pode ser usado para criar um cluster na memória, por padrão composto por dois silos, que podem ser usados para testar granularidades. - Para obter mais informações, confira Teste de unidade com Orleans.
Solucionar problemas:
- Use a associação baseada em tabela do Azure para desenvolvimento e teste.
- Funciona com o Emulador de Armazenamento do Azure para solução de problemas local.
- A tabela OrleansSiloInstances exibe o estado do cluster.
- Use IDs de implantação exclusivas (chaves de partição) para mantê-la simples.
- O Silo não está iniciando.
- Verifique OrleansSiloInstances para determinar se o silo foi registrado lá.
- Verifique se o firewall está aberto para portas TCP: 11111 e 30000.
- Verifique os logs, incluindo o log extra que contém erros de inicialização.
- O front-end (Cliente) não pode se conectar ao cluster de silo.
- O cliente deve ser hospedado no mesmo serviço que os silos.
- Verifique OrleansSiloInstances para verificar se os silos (gateways) estão registrados.
- Verifique o log do cliente para verificar se os gateways correspondem aos listados na tabela OrleansSiloInstances.
- Verifique o log do cliente para validar se o cliente foi capaz de se conectar a um ou mais gateways.