Backup e restauração de serviços confiáveis e atores confiáveis
O Azure Service Fabric é uma plataforma de alta disponibilidade que replica o estado em vários nós para manter essa alta disponibilidade. Assim, mesmo que um nó no cluster falhe, os serviços continuarão disponíveis. Embora essa redundância embutida fornecida pela plataforma possa ser suficiente para alguns, em certos casos é desejável que o serviço faça backup de dados (para um armazenamento externo).
Nota
É fundamental fazer backup e restaurar seus dados (e testar se eles funcionam conforme o esperado) para que você possa se recuperar de cenários de perda de dados.
Nota
A Microsoft recomenda o uso de backup e restauração periódicos para configurar o backup de dados de serviços com estado confiável e atores confiáveis.
Por exemplo, um serviço pode querer fazer backup de dados para se proteger dos seguintes cenários:
- No caso da perda permanente de um cluster inteiro do Service Fabric.
- Perda permanente da maioria das réplicas de uma partição de serviço
- Erros administrativos em que o estado acidentalmente é excluído ou corrompido. Por exemplo, isso pode acontecer se um administrador com privilégios suficientes excluir erroneamente o serviço.
- Bugs no serviço que causam corrupção de dados. Por exemplo, isso pode acontecer quando uma atualização de código de serviço começa a gravar dados defeituosos em uma Coleção Confiável. Nesse caso, tanto o código como os dados podem ter de ser revertidos para um estado anterior.
- Processamento de dados offline. Pode ser conveniente ter processamento offline de dados para business intelligence que acontece separadamente do serviço que gera os dados.
O recurso Backup/Restore permite que serviços criados na API de Serviços Confiáveis criem e restaurem backups. As APIs de backup fornecidas pela plataforma permitem backup(s) do estado de uma partição de serviço, sem bloquear operações de leitura ou gravação. As APIs de restauração permitem que o estado de uma partição de serviço seja restaurado a partir de um backup escolhido.
Tipos de backup
Há duas opções de backup: Completo e Incremental. Um backup completo é um backup que contém todos os dados necessários para recriar o estado da réplica: pontos de verificação e todos os registros de log. Como ele tem os pontos de verificação e o log, um backup completo pode ser restaurado por si só.
O problema com backups completos surge quando os pontos de verificação são grandes.
Por exemplo, uma réplica com 16 GB de estado terá pontos de verificação que somam aproximadamente 16 GB.
Se tivermos um Objetivo de Ponto de Recuperação de cinco minutos, será necessário fazer backup da réplica a cada cinco minutos.
Cada vez que faz backup, ele precisa copiar 16 GB de pontos de verificação, além de 50 MB (configurável usando CheckpointThresholdInMB
) de logs.
A solução para esse problema são backups incrementais, onde o backup contém apenas os registros de log alterados desde o último backup.
Como os backups incrementais são apenas alterações desde o último backup (não inclui os pontos de verificação), eles tendem a ser mais rápidos, mas não podem ser restaurados por conta própria. Para restaurar um backup incremental, toda a cadeia de backup é necessária. Uma cadeia de backup é uma cadeia de backups que começa com um backup completo e é seguida por vários backups incrementais contíguos.
Serviços confiáveis de backup
O autor do serviço tem controle total de quando fazer backups e onde os backups serão armazenados.
Para iniciar um backup, o serviço precisa invocar a função BackupAsync
de membro herdada.
Os backups só podem ser feitos a partir de réplicas primárias e exigem que o status de gravação seja concedido.
Como mostrado abaixo, BackupAsync
leva em um BackupDescription
objeto, onde se pode especificar um backup completo ou incremental, bem como uma função de retorno de chamada, Func<< BackupInfo, CancellationToken, Task<bool>>>
que é invocada quando a pasta de backup foi criada localmente e está pronta para ser movida para algum armazenamento externo.
BackupDescription myBackupDescription = new BackupDescription(BackupOption.Incremental,this.BackupCallbackAsync);
await this.BackupAsync(myBackupDescription);
A solicitação para fazer um backup incremental pode falhar com FabricMissingFullBackupException
o . Essa exceção indica que uma das seguintes coisas está acontecendo:
- a réplica nunca fez um backup completo desde que se tornou principal,
- alguns dos registros de log desde o último backup foram truncados ou
- réplica passou do
MaxAccumulatedBackupLogSizeInMB
limite.
Os usuários podem aumentar a probabilidade de poder fazer backups incrementais configurando MinLogSizeInMB
ou TruncationThresholdFactor
.
Aumentar esses valores aumenta o uso por disco de réplica.
Para obter mais informações, consulte Configuração de serviços confiáveis
BackupInfo
Fornece informações sobre o backup, incluindo o local da pasta onde o tempo de execução salvou o backup (BackupInfo.Directory
). A função de retorno de chamada pode mover o BackupInfo.Directory
para uma loja externa ou outro local. Essa função também retorna um bool que indica se ele foi capaz de mover com êxito a pasta de backup para seu local de destino.
O código a seguir demonstra como o BackupCallbackAsync
método pode ser usado para carregar o backup no Armazenamento do Azure:
private async Task<bool> BackupCallbackAsync(BackupInfo backupInfo, CancellationToken cancellationToken)
{
var backupId = Guid.NewGuid();
await externalBackupStore.UploadBackupFolderAsync(backupInfo.Directory, backupId, cancellationToken);
return true;
}
No exemplo anterior, ExternalBackupStore
é a classe de exemplo usada para fazer interface com o armazenamento de Blob do Azure e UploadBackupFolderAsync
é o método que compacta a pasta e a coloca no repositório de Blob do Azure.
Tenha em atenção que:
- Pode haver apenas uma operação de backup em voo por réplica a qualquer momento. Mais de uma
BackupAsync
chamada de cada vez será lançadaFabricBackupInProgressException
para limitar os backups a bordo a um. - Se uma réplica fizer failover enquanto um backup estiver em andamento, o backup pode não ter sido concluído. Assim, uma vez que o failover termine, é responsabilidade do serviço reiniciar o backup invocando
BackupAsync
conforme necessário.
Restaure serviços confiáveis
Em geral, os casos em que você pode precisar executar uma operação de restauração se enquadram em uma destas categorias:
- A partição de serviço perdeu dados. Por exemplo, o disco de duas das três réplicas de uma partição (incluindo a réplica primária) é corrompido ou apagado. O novo primário pode precisar restaurar dados de um backup.
- Todo o serviço é perdido. Por exemplo, um administrador remove todo o serviço e, portanto, o serviço e os dados precisam ser restaurados.
- O serviço replicou dados de aplicativos corrompidos (por exemplo, devido a um bug do aplicativo). Nesse caso, o serviço deve ser atualizado ou revertido para remover a causa da corrupção e os dados não corrompidos devem ser restaurados.
Embora muitas abordagens sejam possíveis, oferecemos alguns exemplos sobre como usar RestoreAsync
para recuperar dos cenários acima.
Perda de dados de partição em serviços confiáveis
Nesse caso, o tempo de execução detetaria automaticamente a perda de dados e invocaria a OnDataLossAsync
API.
O autor do serviço precisa executar o seguinte para recuperar:
- Substitua o método
OnDataLossAsync
de classe base virtual . - Encontre o backup mais recente no local externo que contém os backups do serviço.
- Transfira a cópia de segurança mais recente (e descomprima a cópia de segurança para a pasta de cópia de segurança, caso tenha sido submetida a compressão de cópias de segurança).
- O
OnDataLossAsync
método fornece umRestoreContext
arquivo . Chame aRestoreAsync
API no arquivoRestoreContext
. - Retorno verdadeiro se a restauração foi um sucesso.
Segue-se um exemplo de implementação do OnDataLossAsync
método:
protected override async Task<bool> OnDataLossAsync(RestoreContext restoreCtx, CancellationToken cancellationToken)
{
var backupFolder = await this.externalBackupStore.DownloadLastBackupAsync(cancellationToken);
var restoreDescription = new RestoreDescription(backupFolder);
await restoreCtx.RestoreAsync(restoreDescription);
return true;
}
RestoreDescription
passado para a RestoreContext.RestoreAsync
chamada contém um membro chamado BackupFolderPath
.
Ao restaurar um único backup completo, isso BackupFolderPath
deve ser definido como o caminho local da pasta que contém o backup completo.
Ao restaurar um backup completo e vários backups incrementais, BackupFolderPath
deve ser definido para o caminho local da pasta que não só contém o backup completo, mas também todos os backups incrementais.
RestoreAsync
chamada pode ser lançada FabricMissingFullBackupException
se o BackupFolderPath
fornecido não contiver um backup completo.
Ele também pode ser lançado ArgumentException
se BackupFolderPath
tiver uma cadeia quebrada de backups incrementais.
Por exemplo, se ele contiver o backup completo, o primeiro backup incremental e o terceiro backup incremental, mas não o segundo backup incremental.
Nota
A RestorePolicy está definida como Safe por padrão. Isso significa que a RestoreAsync
API falhará com ArgumentException se detetar que a pasta de backup contém um estado mais antigo ou igual ao estado contido nessa réplica. RestorePolicy.Force
pode ser usado para pular esta verificação de segurança. Isso é especificado como parte do RestoreDescription
.
Serviço excluído ou perdido
Se um serviço for removido, você deve primeiro recriá-lo antes que os dados possam ser restaurados. É importante criar o serviço com a mesma configuração, por exemplo, esquema de particionamento, para que os dados possam ser restaurados perfeitamente. Uma vez que o serviço está ativo, a API para restaurar dados (OnDataLossAsync
acima) tem que ser invocada em cada partição deste serviço. Uma maneira de conseguir isso é usando FabricClient.TestManagementClient.StartPartitionDataLossAsync em cada partição.
A partir deste ponto, a implementação é a mesma que o cenário acima. Cada partição precisa restaurar o backup relevante mais recente do armazenamento externo. Uma ressalva é que o ID da partição pode ter sido alterado, já que o tempo de execução cria IDs de partição dinamicamente. Assim, o serviço precisa armazenar as informações de partição apropriadas e o nome do serviço para identificar o backup mais recente correto para restaurar para cada partição.
Nota
Não é recomendável usar FabricClient.ServiceManager.InvokeDataLossAsync
em cada partição para restaurar o serviço inteiro, pois isso pode corromper o estado do cluster.
Replicação de dados de aplicativos corrompidos
Se a atualização do aplicativo recém-implantado tiver um bug, isso pode causar corrupção de dados. Por exemplo, uma atualização de aplicativo pode começar a atualizar todos os registros de número de telefone em um dicionário confiável com um código de área inválido. Nesse caso, os números de telefone inválidos serão replicados, pois o Service Fabric não está ciente da natureza dos dados que estão sendo armazenados.
A primeira coisa a fazer depois de detetar um bug tão flagrante que causa corrupção de dados é congelar o serviço no nível do aplicativo e, se possível, atualizar para a versão do código do aplicativo que não tem o bug. No entanto, mesmo depois que o código de serviço é corrigido, os dados ainda podem estar corrompidos e, portanto, os dados podem precisar ser restaurados. Nesses casos, pode não ser suficiente para restaurar o backup mais recente, uma vez que os backups mais recentes também podem estar corrompidos. Assim, você tem que encontrar o último backup que foi feito antes que os dados foram corrompidos.
Se não tiver certeza de quais backups estão corrompidos, você pode implantar um novo cluster do Service Fabric e restaurar os backups das partições afetadas, assim como o cenário "Serviço excluído ou perdido" acima. Para cada partição, comece a restaurar os backups do mais recente para o menor. Depois de encontrar um backup que não tenha a corrupção, mova / exclua todos os backups dessa partição que foram mais recentes (do que esse backup). Repita este processo para cada partição. Agora, quando OnDataLossAsync
é chamado na partição no cluster de produção, o último backup encontrado no armazenamento externo será o escolhido pelo processo acima.
Agora, as etapas na seção "Serviço excluído ou perdido" podem ser usadas para restaurar o estado do serviço para o estado antes que o código buggy corrompesse o estado.
Tenha em atenção que:
- Quando você restaura, há uma chance de que o backup que está sendo restaurado seja mais antigo do que o estado da partição antes que os dados fossem perdidos. Por isso, você deve restaurar apenas como último recurso para recuperar o máximo de dados possível.
- A cadeia de caracteres que representa o caminho da pasta de backup e os caminhos dos arquivos dentro da pasta de backup pode ter mais de 255 caracteres, dependendo do caminho FabricDataRoot e do comprimento do nome do tipo de aplicativo. Isso pode fazer com que alguns métodos .NET, como
Directory.Move
, lancem aPathTooLongException
exceção. Uma solução alternativa é chamar diretamente as APIs do kernel32, comoCopyFile
.
Faça backup e restaure atores confiáveis
A Estrutura de Atores Confiáveis é construída com base em Serviços Confiáveis. O ActorService, que hospeda o(s) ator(es), é um serviço confiável com estado. Assim, toda a funcionalidade de backup e restauração disponível nos Serviços Confiáveis também está disponível para Atores Confiáveis (exceto comportamentos específicos do provedor de estado). Como os backups serão feitos por partição, os estados de todos os atores dessa partição serão copiados (e a restauração é semelhante e acontecerá por partição). Para executar backup/restauração, o proprietário do serviço deve criar uma classe de serviço de ator personalizada que derive da classe ActorService e, em seguida, fazer backup/restauração semelhante aos Serviços Confiáveis, conforme descrito acima nas seções anteriores.
class MyCustomActorService : ActorService
{
public MyCustomActorService(StatefulServiceContext context, ActorTypeInformation actorTypeInfo)
: base(context, actorTypeInfo)
{
}
//
// Method overrides and other code.
//
}
Quando você cria uma classe de serviço de ator personalizada, você precisa registrá-la também ao registrar o ator.
ActorRuntime.RegisterActorAsync<MyActor>(
(context, typeInfo) => new MyCustomActorService(context, typeInfo)).GetAwaiter().GetResult();
O provedor de estado padrão para Reliable Actors é KvsActorStateProvider
. O backup incremental não está habilitado por padrão para KvsActorStateProvider
o . Você pode habilitar o backup incremental criando KvsActorStateProvider
com a configuração apropriada em seu construtor e, em seguida, passando-o para o construtor ActorService, conforme mostrado no seguinte trecho de código:
class MyCustomActorService : ActorService
{
public MyCustomActorService(StatefulServiceContext context, ActorTypeInformation actorTypeInfo)
: base(context, actorTypeInfo, null, null, new KvsActorStateProvider(true)) // Enable incremental backup
{
}
//
// Method overrides and other code.
//
}
Depois que o backup incremental for habilitado, fazer um backup incremental pode falhar com FabricMissingFullBackupException por um dos seguintes motivos e você precisará fazer um backup completo antes de fazer backup(s) incremental(is):
- A réplica nunca fez um backup completo desde que se tornou principal.
- Alguns dos registros de log foram truncados desde que o último backup foi feito.
Quando o backup incremental está habilitado, KvsActorStateProvider
não usa o buffer circular para gerenciar seus registros de log e o trunca periodicamente. Se nenhum backup for feito pelo usuário por um período de 45 minutos, o sistema truncará automaticamente os registros de log. Esse intervalo pode ser configurado especificando logTruncationIntervalInMinutes
no KvsActorStateProvider
construtor (semelhante ao habilitar o backup incremental). Os registros de log também podem ficar truncados se a réplica primária precisar criar outra réplica enviando todos os seus dados.
Ao fazer a restauração a partir de uma cadeia de backup, semelhante aos Serviços Confiáveis, o BackupFolderPath deve conter subdiretórios com um subdiretório contendo backup completo e outros subdiretórios contendo backup(s) incremental(is). A API de restauração lançará FabricException com uma mensagem de erro apropriada se a validação da cadeia de backup falhar.
Nota
KvsActorStateProvider
atualmente ignora a opção RestorePolicy.Safe. O suporte para este recurso está planejado em uma próxima versão.
Testando backup e restauração
É importante garantir que os dados críticos estejam sendo copiados e possam ser restaurados. Isso pode ser feito invocando o cmdlet no PowerShell que pode induzir a Start-ServiceFabricPartitionDataLoss
perda de dados em uma partição específica para testar se a funcionalidade de backup e restauração de dados para seu serviço está funcionando conforme o esperado. Também é possível invocar programaticamente a perda de dados e restaurar a partir desse evento também.
Nota
Você pode encontrar um exemplo de implementação da funcionalidade de backup e restauração no Aplicativo de Referência da Web no GitHub. Por favor, veja o Inventory.Service
serviço para mais detalhes.
Nos bastidores: mais detalhes sobre backup e restauração
Aqui estão mais alguns detalhes sobre backup e restauração.
Backup
O Reliable State Manager oferece a capacidade de criar backups consistentes sem bloquear quaisquer operações de leitura ou gravação. Para fazer isso, ele utiliza um mecanismo de persistência de ponto de verificação e log. O Reliable State Manager usa pontos de verificação difusos (leves) em determinados pontos para aliviar a pressão do log transacional e melhorar os tempos de recuperação. Quando BackupAsync
é chamado, o Reliable State Manager instrui todos os objetos Reliable a copiar seus arquivos de ponto de verificação mais recentes para uma pasta de backup local. Em seguida, o Reliable State Manager copia todos os registros de log, começando do "ponteiro de início" para o registro de log mais recente na pasta de backup. Como todos os registros de log até o registro de log mais recente são incluídos no backup e o Reliable State Manager preserva o registro de write-ahead, o Reliable State Manager garante que todas as transações confirmadas (CommitAsync
retornadas com êxito) sejam incluídas no backup.
Qualquer transação que seja confirmada após BackupAsync
ter sido chamada pode ou não estar no backup. Depois que a pasta de backup local tiver sido preenchida pela plataforma (ou seja, o backup local for concluído pelo tempo de execução), o retorno de chamada de backup do serviço será invocado. Esse retorno de chamada é responsável por mover a pasta de backup para um local externo, como o Armazenamento do Azure.
Restauro
O Reliable State Manager fornece a capacidade de restaurar a partir de um backup usando a RestoreAsync
API.
O RestoreAsync
método em RestoreContext
pode ser chamado apenas dentro do OnDataLossAsync
método.
O bool retornado por OnDataLossAsync
indica se o serviço restaurou seu estado de uma fonte externa.
Se os retornos true, o OnDataLossAsync
Service Fabric reconstruirá todas as outras réplicas a partir dessa primária. O Service Fabric garante que as réplicas que receberão OnDataLossAsync
chamada primeiro façam a transição para a função principal, mas não recebam status de leitura ou de gravação.
Isso implica que, para implementadores StatefulService, RunAsync
não serão chamados até OnDataLossAsync
que sejam concluídos com êxito.
Em seguida, OnDataLossAsync
será invocado na nova primária.
Até que um serviço conclua essa API com êxito (retornando true ou false) e conclua a reconfiguração relevante, a API continuará sendo chamada uma de cada vez.
RestoreAsync
Primeiro, descarta todo o estado existente na réplica primária em que foi chamado.
Em seguida, o Reliable State Manager cria todos os objetos Reliable que existem na pasta de backup.
Em seguida, os objetos confiáveis são instruídos a restaurar a partir de seus pontos de verificação na pasta de backup.
Finalmente, o Reliable State Manager recupera seu próprio estado dos registros de log na pasta de backup e executa a recuperação.
Como parte do processo de recuperação, as operações a partir do "ponto de partida" que confirmaram registros de log na pasta de backup são reproduzidas para os objetos confiáveis. Esta etapa garante que o estado recuperado seja consistente.