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.
Infraestruturas baseadas em nuvem, como o Armazenamento do Azure, fornecem uma plataforma altamente disponível e durável para hospedar dados e aplicativos. Os desenvolvedores de aplicativos baseados em nuvem devem considerar cuidadosamente como aproveitar essa plataforma para maximizar essas vantagens para seus usuários. O Armazenamento do Azure oferece opções de redundância geográfica para garantir a alta disponibilidade mesmo durante uma interrupção regional. As contas de armazenamento configuradas para replicação com redundância geográfica são replicadas de forma síncrona na região primária e replicadas assincronamente em uma região secundária que está a centenas de quilômetros de distância.
O Armazenamento do Azure oferece duas opções para replicação com redundância geográfica: GRS (armazenamento com redundância geográfica) e GZRS (armazenamento com redundância de zona geográfica). Para usar as opções de redundância geográfica do Armazenamento do Azure, verifique se sua conta de armazenamento está configurada para redundância geográfica de acesso de leitura (RA-GRS) ou redundância de zona geográfica de acesso de leitura (RA-GZRS). Se não estiver, você poderá saber mais sobre como alterar o tipo de replicação da conta de armazenamento.
Este artigo mostra como projetar um aplicativo que continuará funcionando, embora em uma capacidade limitada, mesmo quando houver uma interrupção significativa na região primária. Se a região primária ficar indisponível, seu aplicativo poderá alternar sem problemas para executar operações de leitura na região secundária até que a região primária se torne responsiva novamente.
Considerações sobre design de aplicativo
Você pode projetar seu aplicativo para lidar com falhas transitórias ou interrupções significativas lendo da região secundária quando há um problema que interfere na leitura da região primária. Quando a região primária estiver disponível novamente, seu aplicativo poderá retornar à leitura da região primária.
Tenha em mente essas principais considerações ao criar seu aplicativo para disponibilidade e resiliência usando RA-GRS ou RA-GZRS:
Uma cópia somente leitura dos dados armazenados na região primária é replicada de forma assíncrona em uma região secundária. Essa replicação assíncrona significa que a cópia somente leitura na região secundária é eventualmente consistente com os dados na região primária. O serviço de armazenamento determina o local da região secundária.
Você pode usar as bibliotecas de cliente do Azure Storage para realizar solicitações de leitura e atualização para o endereço da região primária. Se a região primária não estiver disponível, você poderá redirecionar automaticamente as solicitações de leitura para a região secundária. Você também pode configurar seu aplicativo para enviar solicitações de leitura diretamente para a região secundária, se desejado, mesmo quando a região primária estiver disponível.
Se a região primária ficar indisponível, você poderá iniciar um failover de conta. Quando você faz failover para a região secundária, as entradas DNS que apontam para a região primária são alteradas para apontar para a região secundária. Depois que o failover for concluído, o acesso de gravação será restaurado para contas GRS e RA-GRS. Para saber mais, confira Recuperação de desastre e failover da conta de armazenamento.
Trabalhar com dados eventualmente consistentes
A solução proposta pressupõe que é aceitável retornar dados potencialmente obsoletos para o aplicativo de chamada. Como os dados na região secundária são eventualmente consistentes, é possível que a região primária possa ficar inacessível antes que uma atualização para a região secundária tenha terminado de ser replicada.
Por exemplo, suponha que seu cliente envie uma atualização com êxito, mas a região primária falhará antes que a atualização seja propagada para a região secundária. Quando o cliente pede para ler os dados de volta, ele recebe os dados obsoletos da região secundária em vez dos dados atualizados. Ao projetar seu aplicativo, você deve decidir se esse comportamento é aceitável ou não. Se estiver, você também precisará considerar como notificar o usuário.
Posteriormente neste artigo, você aprenderá mais sobre como lidar com dados eventualmente consistentes e como verificar a propriedade Hora da Última Sincronização para avaliar quaisquer discrepâncias entre os dados nas regiões primária e secundária.
Gerenciando serviços separadamente ou todos juntos
Embora seja improvável, é possível que um serviço (blobs, filas, tabelas ou arquivos) fique indisponível enquanto os outros serviços ainda estiverem totalmente funcionais. É possível tratar as tentativas para cada serviço separadamente ou você pode tratá-las de forma genérica para todos os serviços de armazenamento em conjunto.
Por exemplo, se você usar filas e blobs em seu aplicativo, poderá decidir colocar um código separado para lidar com erros retráteis para cada serviço. Dessa forma, um erro do serviço de blob afetará apenas a parte do aplicativo que lida com blobs, deixando as filas continuar funcionando normalmente. No entanto, se você decidir tratar todas as tentativas de serviço de armazenamento em conjunto, as solicitações para os serviços de blobs e filas serão afetadas se qualquer serviço retornar um erro com nova tentativa.
Em última análise, essa decisão depende da complexidade do seu aplicativo. Talvez você prefira tratar falhas por serviço para limitar o impacto das tentativas. Ou você pode decidir redirecionar solicitações de leitura para todos os serviços de armazenamento para a região secundária quando detectar um problema com qualquer serviço de armazenamento na região primária.
Executando seu aplicativo no modo somente leitura
Para se preparar efetivamente para uma interrupção na região primária, seu aplicativo deve ser capaz de lidar com solicitações de leitura com falha e solicitações de atualização com falha. Se a região primária falhar, as solicitações de leitura poderão ser redirecionadas para a região secundária. No entanto, não é possível redirecionar as solicitações de atualização, pois os dados replicados na região secundária são de leitura somente. Por esse motivo, você precisa projetar seu aplicativo para poder ser executado no modo somente leitura.
Por exemplo, você pode definir um sinalizador que é verificado antes que qualquer solicitação de atualização seja enviada ao Armazenamento do Azure. Quando uma solicitação de atualização é fornecida, você pode ignorar a solicitação e retornar uma resposta apropriada ao usuário. Você pode até optar por desabilitar determinados recursos completamente até que o problema seja resolvido e notificar os usuários de que os recursos estão temporariamente indisponíveis.
Se você decidir gerenciar erros para cada serviço separadamente, também precisará gerenciar a capacidade de executar seu aplicativo no modo somente leitura por serviço. Por exemplo, você pode configurar marcadores de leitura única para cada serviço. Em seguida, você pode habilitar ou desabilitar os sinalizadores no código, conforme necessário.
Poder executar seu aplicativo em modo somente leitura também oferece a capacidade de garantir funcionalidade limitada durante uma atualização de grande porte. Você pode disparar seu aplicativo para ser executado no modo somente leitura e apontar para o data center secundário, garantindo que ninguém esteja acessando os dados na região primária enquanto estiver fazendo atualizações.
Gerenciamento de atualizações ao executar no modo somente leitura
Há muitas maneiras de lidar com solicitações de atualização ao executar no modo somente leitura. Esta seção se concentra em alguns padrões gerais a serem considerados.
Você pode responder ao usuário e notificá-lo de que as solicitações de atualização não estão sendo processadas no momento. Por exemplo, um sistema de gerenciamento de contatos pode permitir que os usuários acessem informações de contato, mas não façam atualizações.
Você pode enfileirar suas atualizações em outra região. Nesse caso, você escreveria suas solicitações de atualização pendentes em uma fila em uma região diferente e processaria essas solicitações depois que o data center primário ficar online novamente. Nesse cenário, você deve informar ao usuário que a solicitação de atualização está na fila para processamento posterior.
Você pode gravar suas atualizações em uma conta de armazenamento em outra região. Quando a região primária voltar a ficar online, você poderá mesclar essas atualizações nos dados primários, dependendo da estrutura dos dados. Por exemplo, se você estiver criando arquivos separados com um carimbo de data/hora no nome, poderá copiar esses arquivos de volta para a região primária. Essa solução pode se aplicar a cargas de trabalho, como registro em log e dados de IoT.
Lidando com Retentativas
Os aplicativos que se comunicam com os serviços em execução na nuvem devem ser sensíveis a eventos não planejados e falhas que podem ocorrer. Essas falhas podem ser transitórias ou persistentes, desde uma perda momentânea de conectividade até uma interrupção significativa devido a um desastre natural. É importante projetar aplicativos de nuvem com tratamento de repetição apropriado para maximizar a disponibilidade e melhorar a estabilidade geral do aplicativo.
Solicitações de leitura
Se a região primária ficar indisponível, as solicitações de leitura poderão ser redirecionadas para o armazenamento secundário. Como observado anteriormente, deve ser aceitável que seu aplicativo leia dados obsoletos potencialmente. A biblioteca de clientes do Armazenamento do Azure oferece opções para lidar com novas tentativas e redirecionar solicitações de leitura para uma região secundária.
Neste exemplo, o tratamento de repetição para armazenamento de Blobs é configurado na classe BlobClientOptions
e será aplicado ao objeto BlobServiceClient
que criamos usando essas opções de configuração. Essa configuração é uma abordagem primária e secundária , em que as novas tentativas de solicitação de leitura da região primária são redirecionadas para a região secundária. Essa abordagem é melhor quando se espera que as falhas na região primária sejam temporárias.
string accountName = "<YOURSTORAGEACCOUNTNAME>";
Uri primaryAccountUri = new Uri($"https://{accountName}.blob.core.windows.net/");
Uri secondaryAccountUri = new Uri($"https://{accountName}-secondary.blob.core.windows.net/");
// Provide the client configuration options for connecting to Azure Blob storage
BlobClientOptions blobClientOptions = new BlobClientOptions()
{
Retry = {
// The delay between retry attempts for a fixed approach or the delay
// on which to base calculations for a backoff-based approach
Delay = TimeSpan.FromSeconds(2),
// The maximum number of retry attempts before giving up
MaxRetries = 5,
// The approach to use for calculating retry delays
Mode = RetryMode.Exponential,
// The maximum permissible delay between retry attempts
MaxDelay = TimeSpan.FromSeconds(10)
},
// If the GeoRedundantSecondaryUri property is set, the secondary Uri will be used for
// GET or HEAD requests during retries.
// If the status of the response from the secondary Uri is a 404, then subsequent retries
// for the request will not use the secondary Uri again, as this indicates that the resource
// may not have propagated there yet.
// Otherwise, subsequent retries will alternate back and forth between primary and secondary Uri.
GeoRedundantSecondaryUri = secondaryAccountUri
};
// Create a BlobServiceClient object using the configuration options above
BlobServiceClient blobServiceClient = new BlobServiceClient(primaryAccountUri, new DefaultAzureCredential(), blobClientOptions);
Se você determinar que a região primária provavelmente ficará indisponível por um longo período de tempo, você poderá configurar todas as solicitações de leitura para apontar para a região secundária. Essa configuração é apenas uma abordagem secundária . Conforme discutido anteriormente, você precisará de uma estratégia para lidar com solicitações de atualização durante esse tempo e uma maneira de informar aos usuários que somente as solicitações de leitura estão sendo processadas. Neste exemplo, criamos uma nova instância de BlobServiceClient
que utiliza o ponto de extremidade da região secundária.
string accountName = "<YOURSTORAGEACCOUNTNAME>";
Uri primaryAccountUri = new Uri($"https://{accountName}.blob.core.windows.net/");
Uri secondaryAccountUri = new Uri($"https://{accountName}-secondary.blob.core.windows.net/");
// Create a BlobServiceClient object pointed at the secondary Uri
// Use blobServiceClientSecondary only when issuing read requests, as secondary storage is read-only
BlobServiceClient blobServiceClientSecondary = new BlobServiceClient(secondaryAccountUri, new DefaultAzureCredential(), blobClientOptions);
Saber quando alternar para o modo somente leitura e solicitações somente secundárias é parte de um padrão de design de arquitetura chamado padrão de Disjuntor, que será discutido em uma seção posterior.
Solicitações de atualização
As solicitações de atualização não podem ser redirecionadas para o armazenamento secundário, que é somente leitura. Conforme descrito anteriormente, seu aplicativo precisa ser capaz de lidar com solicitações de atualização quando a região primária não estiver disponível.
O padrão Circuit Breaker também pode ser aplicado a solicitações de atualização. Para lidar com erros de solicitação de atualização, você pode definir um limite no código, como 10 falhas consecutivas, e acompanhar o número de falhas de solicitações para a região primária. Depois que o limite for atingido, você poderá alternar o aplicativo para o modo somente leitura para que as solicitações de atualização para a região primária não sejam mais emitidas.
Como implementar o padrão Circuit Breaker
Lidar com falhas que podem levar um tempo variável para serem recuperadas faz parte de um padrão de design arquitetônico chamado Circuit Breaker. A implementação adequada desse padrão pode impedir que um aplicativo tente executar repetidamente uma operação que provavelmente falhará, melhorando assim a estabilidade e a resiliência do aplicativo.
Um aspecto do padrão Circuit Breaker é identificar quando há um problema contínuo com um endpoint primário. Para fazer essa determinação, você pode monitorar com que frequência o cliente encontra erros retráveis. Como cada cenário é diferente, você precisa determinar um limite apropriado a ser usado para a decisão de mudar para o ponto de extremidade secundário e executar o aplicativo no modo somente leitura.
Por exemplo, você poderia decidir realizar a mudança se houver 10 falhas consecutivas na região primária. Você pode acompanhar isso mantendo uma contagem das falhas no código. Se houver êxito antes de atingir o limite, redefina a contagem como zero. Se a contagem atingir o limite, alterne o aplicativo para usar a região secundária para solicitações de leitura.
Como uma abordagem alternativa, você pode decidir implementar um componente de monitoramento personalizado em seu aplicativo. Esse componente pode realizar um ping contínuo no endpoint de armazenamento primário com solicitações de leitura triviais (como ler um pequeno blob) para determinar sua integridade. Essa abordagem ocuparia alguns recursos, mas não uma quantidade significativa. Quando é descoberto um problema que atinge o limite, é possível alternar para solicitações de leitura somente secundárias e o modo somente leitura. Para esse cenário, quando a execução de ping no ponto de extremidade do armazenamento primário tiver êxito novamente, é possível alternar de volta para a região primária e continuar permitindo atualizações.
O limite de erro usado para determinar quando fazer a opção pode variar de serviço para serviço em seu aplicativo, portanto, você deve considerar torná-los parâmetros configuráveis.
Outra consideração é como lidar com várias instâncias de um aplicativo e o que fazer ao detectar erros retráteis em cada instância. Por exemplo, você pode ter 20 VMs em execução com o mesmo aplicativo carregado. Você lida com cada instância separadamente? Se uma instância começar a ter problemas, você deseja limitar a resposta a apenas uma instância? Ou deseja que todas as instâncias respondam da mesma forma quando uma instância tiver um problema? Lidar com as instâncias separadamente é muito mais simples do que tentar coordenar a resposta entre elas, mas sua abordagem dependerá da arquitetura do aplicativo.
Manipulando dados eventualmente consistentes
O armazenamento com redundância geográfica funciona replicando transações do primário para a região secundária. O processo de replicação garante que os dados na região secundária sejam eventualmente consistentes. Isso significa que todas as transações na região primária eventualmente aparecerão na região secundária, mas que pode haver um atraso antes que elas apareçam. Também não há garantia de que as transações chegarão à região secundária na mesma ordem em que foram aplicadas originalmente na região primária. Se suas transações chegarem à região secundária fora de ordem, você poderá considerar seus dados na região secundária em um estado inconsistente até que o serviço seja atualizado.
O exemplo a seguir para o Armazenamento de Tabelas do Azure mostra o que pode acontecer quando você atualiza os detalhes de um funcionário para torná-los membros da função de administrador. Para este exemplo, isso exige que você atualize a entidade do funcionário e atualize a entidade do papel de administrador com uma contagem do número total de administradores. Observe como as atualizações são aplicadas fora de ordem na região secundária.
Hora | Transação | Replicação | Última hora de sincronização | Resultado |
---|---|---|---|---|
T0 | Transação A: Inserir funcionário entidade no ensino primário |
Transação A inserida no primário, ainda não replicado. |
||
T1 | Transação A replicado para secundário |
T1 | A transação A foi replicada para o servidor secundário. Hora da Última Sincronização atualizada. |
|
T2 | Transação B: Atualização entidade de colaborador no primário |
T1 | Transação B gravada no servidor primário. ainda não replicado. |
|
T3 | Transação C: Atualização administrador entidade de função em primário |
T1 | Transação C gravada no sistema primário. ainda não replicado. |
|
T4 | Transação C replicado para secundário |
T1 | Transação C replicada para o ambiente secundário. LastSyncTime não foi atualizado porque A transação B ainda não foi replicada. |
|
T5 | Ler entidades do ensino secundário |
T1 | Você recebe o valor desatualizado para o funcionário entidade porque a transação B não foi concluída ainda não replicado Você obtém o novo valor para entidade de função de administrador porque C tem Replicado. A hora da última sincronização ainda não foi completada. foi atualizado devido à transação B não foi replicado. Você pode dizer que A função de administrador é inconsistente. porque a data/hora da entidade é posterior a Hora da Última Sincronização. |
|
T6 | Transação B replicado para secundário |
T6 |
T6 – Todas as transações por meio de C têm foi replicado, Horário da última sincronização é atualizado. |
Neste exemplo, suponha que o cliente mude para leitura da região secundária em T5. Ele pode ler com êxito a entidade de função de administrador no momento, mas a entidade contém um valor para a contagem de administradores que não é consistente com o número de entidades de funcionário marcadas como administradores na região secundária no momento. Seu cliente pode exibir esse valor, com o risco de que as informações sejam inconsistentes. Como alternativa, o cliente pode tentar determinar que a função de administrador está em um estado potencialmente inconsistente porque as atualizações ocorreram fora de ordem e informar o usuário sobre esse fato.
Para determinar se uma conta de armazenamento tem dados potencialmente inconsistentes, o cliente pode verificar o valor da propriedade Hora da Última Sincronização . A Hora da Última Sincronização informa a hora em que os dados na região secundária eram consistentes pela última vez e quando o serviço havia aplicado todas as transações antes desse ponto no tempo. No exemplo mostrado acima, depois que o serviço insere a entidade do funcionário na região secundária, a última hora de sincronização é definida como T1. Ele permanece em T1 até que o serviço atualize a entidade de funcionário na região secundária quando ela estiver definida como T6. Se o cliente recuperar o tempo da última sincronização quando ler a entidade em T5, ele poderá compará-lo com o carimbo de data/hora na entidade. Se o carimbo de data/hora na entidade for posterior à hora da última sincronização, a entidade está em um estado potencialmente inconsistente, e você poderá executar a ação apropriada. Usar esse campo requer que você saiba quando a última atualização para o primário foi concluída.
Para saber como que verificar a hora da última sincronização, consulte Verificar a Propriedade Última Sincronização para uma Conta de Armazenamento.
Teste
É importante testar se seu aplicativo se comporta conforme o esperado quando encontra erros retráteis. Por exemplo, você precisa testar se o aplicativo alterna para a região secundária quando detecta um problema e, em seguida, alterna para trás quando a região primária fica disponível novamente. Para testar corretamente esse comportamento, você precisa de uma maneira de simular erros retráveis e controlar a frequência com que eles ocorrem.
Uma opção é usar o Fiddler para interceptar e modificar respostas HTTP em um script. Esse script pode identificar as respostas que vêm do ponto de extremidade primário e alterar o código de status HTTP de forma que a biblioteca de clientes do Armazenamento o reconheça como um erro com nova tentativa. Este snippet de código mostra um exemplo simples de um script Fiddler que intercepta respostas para ler solicitações na tabela de dados de funcionários para retornar um status 502.
static function OnBeforeResponse(oSession: Session) {
...
if ((oSession.hostname == "\[YOURSTORAGEACCOUNTNAME\].table.core.windows.net")
&& (oSession.PathAndQuery.StartsWith("/employeedata?$filter"))) {
oSession.responseCode = 502;
}
}
Você pode estender este exemplo para interceptar uma gama mais ampla de solicitações e apenas alterar o responseCode em algumas delas para simular melhor um cenário do mundo real. Para obter mais informações sobre como personalizar scripts do Fiddler, consulte Modificando uma solicitação ou resposta na documentação do Fiddler.
Se você tiver configurado limites configuráveis para mudar seu aplicativo para somente leitura, será mais fácil testar o comportamento com volumes de transação que não são de produção.
Próximas etapas
Para obter um exemplo completo mostrando como alternar entre os endpoints primário e secundário, consulte Exemplos da Azure – Usando o padrão Circuit Breaker com RA-GRS armazenamento.