Compartilhar via


Grãos replicados

Às vezes, várias instâncias do mesmo grão podem estar ativas, como ao operar um cluster múltiplo e usar o OneInstancePerClusterAttribute. JournaledGrain foi projetado para dar suporte a instâncias replicadas com o mínimo de atrito. Ele depende de provedores de consistência de log para executar os protocolos necessários, garantindo que todas as instâncias concordem com a mesma sequência de eventos. Em particular, ele lida com os seguintes aspectos:

  • Versões consistentes: todas as versões do estado de grão (exceto versões provisórias) são baseadas na mesma sequência global de eventos. Em particular, se duas instâncias virem o mesmo número de versão, elas verão o mesmo estado.

  • Eventos de corrida: várias instâncias podem gerar simultaneamente um evento. O provedor de consistência resolve essa corrida e garante que todas as instâncias concordem com a mesma sequência.

  • Notificações/Reatividade: depois que um evento é gerado em uma instância de grão, o provedor de consistência não apenas atualiza o armazenamento, mas também notifica todas as outras instâncias de grãos.

Para obter uma discussão geral sobre o modelo de consistência, consulte nosso TechReport e o artigo GSP (Global Sequence Protocol).

Eventos condicionais

Eventos de corrida podem ser problemáticos se entrarem em conflito, ou seja, ambos não devem se comprometer por algum motivo. Por exemplo, ao retirar dinheiro de uma conta bancária, duas instâncias podem determinar independentemente que existem fundos suficientes para um saque e emitir um evento de retirada. No entanto, a combinação de ambos os eventos pode sobrecarregar a conta. Para evitar isso, a JournaledGrain API dá suporte ao RaiseConditionalEvent método.

bool success = await RaiseConditionalEvent(
    new WithdrawalEvent() { /* ... */ });

Eventos condicionais verificam duas vezes se a versão local corresponde à versão no armazenamento. Caso contrário, significa que a sequência de eventos cresceu nesse ínterim, indicando que esse evento perdeu uma disputa contra outro evento. Nesse caso, o evento condicional não é acrescentado ao log e RaiseConditionalEvent retorna false.

Isso é análoga ao uso de etiquetas eletrônicas com atualizações condicionais de armazenamento e fornece um mecanismo simples para evitar o registro de conflitos.

É possível e sensato usar eventos condicionais e incondicionales para o mesmo grão, como DepositEvent e WithdrawalEvent. Os depósitos não precisam ser condicionais: mesmo que uma DepositEvent perca uma corrida, ela não precisa ser cancelada, mas ainda pode ser acrescentada à sequência de eventos global.

RaiseConditionalEvent Aguardar a tarefa retornada é suficiente para confirmar o evento; você não precisa chamar ConfirmEvents também.

Sincronização explícita

Às vezes, talvez você queira garantir que um grão esteja totalmente atualizado com a versão mais recente. Você pode impor isso chamando:

await RefreshNow();

Essa chamada faz duas coisas:

  1. Confirma todos os eventos não confirmados.
  2. Carrega a versão mais recente a partir do armazenamento.