Criando aplicativos altamente disponíveis usando o armazenamento com redundância geográfica com acesso de leituraDesigning highly available applications using read-access geo-redundant storage

Um recurso comum das infraestruturas baseadas em nuvem como o Armazenamento do Azure é que elas fornecem uma plataforma altamente disponível para hospedar aplicativos.A common feature of cloud-based infrastructures like Azure Storage is that they provide a highly available platform for hosting applications. Os desenvolvedores de aplicativos baseados em nuvem devem considerar cuidadosamente como aproveitar essa plataforma para fornecer aplicativos altamente disponíveis aos usuários.Developers of cloud-based applications must consider carefully how to leverage this platform to deliver highly available applications to their users. Este artigo se concentra em como os desenvolvedores podem usar uma das opções de replicação com redundância geográfica do Azure para garantir que seus aplicativos de armazenamento do Azure estejam altamente disponíveis.This article focuses on how developers can use one of Azure's geo-redundant replication options to ensure that their Azure Storage applications are highly available.

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, em seguida, replicadas assincronamente para uma região secundária que está a centenas de quilômetros de distância.Storage accounts configured for geo-redundant replication are synchronously replicated in the primary region, and then asynchronously replicated to a secondary region that is hundreds of miles away. O armazenamento do Azure oferece dois tipos de replicação com redundância geográfica:Azure Storage offers two types of geo-redundant replication:

  • O armazenamento com redundância de zona geográfica (GZRS) (visualização) fornece replicação para cenários que exigem alta disponibilidade e máxima durabilidade.Geo-zone-redundant storage (GZRS) (preview) provides replication for scenarios requiring both high availability and maximum durability. Os dados são replicados de forma síncrona em três zonas de disponibilidade do Azure na região primária usando o ZRS (armazenamento com redundância de zona) e, em seguida, replicados assincronamente para a região secundária.Data is replicated synchronously across three Azure availability zones in the primary region using zone-redundant storage (ZRS), then replicated asynchronously to the secondary region. Para acesso de leitura aos dados na região secundária, habilite o armazenamento com redundância de zona geográfica com acesso de leitura (RA-GZRS).For read access to data in the secondary region, enable read-access geo-zone-redundant storage (RA-GZRS).
  • O grs (armazenamento com redundância geográfica) fornece replicação entre regiões para proteger contra interrupções regionais.Geo-redundant storage (GRS) provides cross-regional replication to protect against regional outages. Os dados são replicados de forma síncrona três vezes na região primária usando o LRS (armazenamento com redundância local) e, em seguida, replicados assincronamente para a região secundária.Data is replicated synchronously three times in the primary region using locally redundant storage (LRS), then replicated asynchronously to the secondary region. Para acesso de leitura aos dados na região secundária, habilite o armazenamento com redundância geográfica com acesso de leitura (RA-GRS).For read access to data in the secondary region, enable read-access geo-redundant storage (RA-GRS).

Este artigo mostra como projetar seu aplicativo para lidar com uma interrupção na região primária.This article shows how to design your application to handle an outage in the primary region. Se a região primária ficar indisponível, seu aplicativo poderá se adaptar para executar operações de leitura em vez da região secundária.If the primary region becomes unavailable, your application can adapt to perform read operations against the secondary region instead. Verifique se sua conta de armazenamento está configurada para RA-GRS ou RA-GZRS antes de começar.Make sure that your storage account is configured for RA-GRS or RA-GZRS before you get started.

Para obter informações sobre quais regiões primárias são emparelhadas com quais regiões secundárias, consulte Continuidade dos negócios e recuperação de desastres (BCDR): Regiões Emparelhadas do Azure.For information about which primary regions are paired with which secondary regions, see Business continuity and disaster recovery (BCDR): Azure Paired Regions.

Há snippets de código incluídos neste artigo e um link para um exemplo completo no fim, que você pode baixar e executar.There are code snippets included in this article, and a link to a complete sample at the end that you can download and run.

Considerações de design de aplicativo ao ler do secundárioApplication design considerations when reading from the secondary

A finalidade deste artigo é mostrar como criar um aplicativo que continuará funcionando (embora com capacidade limitada) mesmo que ocorra um grande desastre no data center primário.The purpose of this article is to show you how to design an application that will continue to function (albeit in a limited capacity) even in the event of a major disaster at the primary data center. Você pode projetar seu aplicativo para resolver problemas transitórios ou de execução longa com a leitura da região secundária quando há um problema que interfere na leitura da região primária.You can design your application to handle transient or long-running issues by reading from the secondary region when there is a problem that interferes with reading from the primary region. Quando a região primária estiver disponível novamente, o aplicativo poderá retornar com a leitura da região primária.When the primary region is available again, your application can return to reading from the primary region.

Tenha em mente estes pontos-chave ao projetar seu aplicativo para RA-GRS ou RA-GZRS:Keep in mind these key points when designing your application for RA-GRS or RA-GZRS:

  • O Armazenamento do Azure mantém uma cópia somente leitura dos dados armazenados na região primária em uma região secundária.Azure Storage maintains a read-only copy of the data you store in your primary region in a secondary region. Conforme observado acima, o serviço de armazenamento determina o local da região secundária.As noted above, the storage service determines the location of the secondary region.

  • A cópia somente leitura é eventualmente consistente com os dados na região primária.The read-only copy is eventually consistent with the data in the primary region.

  • Para blobs, tabelas e filas, você pode consultar a região secundária para obter um valor de Hora da Última Sincronização que informa quando ocorreu a última replicação da região primária para a secundária.For blobs, tables, and queues, you can query the secondary region for a Last Sync Time value that tells you when the last replication from the primary to the secondary region occurred. (Não há suporte para isso nos Arquivos do Azure, que, no momento, não têm redundância RA-GRS.)(This is not supported for Azure Files, which doesn't have RA-GRS redundancy at this time.)

  • Você pode usar a biblioteca de cliente de armazenamento para ler e gravar dados na região primária ou secundária.You can use the Storage Client Library to read and write data in either the primary or secondary region. Você também poderá redirecionar as solicitações de leitura automaticamente para a região secundária se uma solicitação de leitura para a região primária atingir o tempo limite.You can also redirect read requests automatically to the secondary region if a read request to the primary region times out.

  • Se a região primária ficar indisponível, você pode iniciar um failover de conta.If the primary region becomes unavailable, you can initiate an account failover. Quando você executa o 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.When you fail over to the secondary region, the DNS entries pointing to the primary region are changed to point to the secondary region. Após o failover estar concluído, o acesso de gravação é restaurado para as contas GRS e RA-GRS.After the failover is complete, write access is restored for GRS and RA-GRS accounts. Para obter mais informações, confira Recuperação de desastre e failover de conta de armazenamento (versão prévia) no Armazenamento do Azure.For more information, see Disaster recovery and storage account failover (preview) in Azure Storage.

Observação

O failover de conta gerenciada pelo cliente (versão prévia) ainda não está disponível em regiões com suporte para GZRS/RA-GZRS, para que os clientes não possam gerenciar eventos de failover de conta no momento com contas GZRS e RA-GZRS.Customer-managed account failover (preview) is not yet available in regions supporting GZRS/RA-GZRS, so customers cannot currently manage account failover events with GZRS and RA-GZRS accounts. Durante a versão prévia, a Microsoft gerenciará qualquer evento de failover que afete contas GZRS/RA-GZRS.During the preview, Microsoft will manage any failover events affecting GZRS/RA-GZRS accounts.

Usando dados eventualmente consistentesUsing eventually consistent data

A solução proposta pressupõe que é aceitável retornar dados potencialmente obsoletos ao aplicativo de chamada.The proposed solution assumes that it is acceptable to return potentially stale data to the calling application. Como os dados na região secundária são finalmente consistentes, é possível que a região primária se torne inacessível antes que uma atualização para a região secundária tenha concluído a replicação.Because data in the secondary region is eventually consistent, it is possible the primary region may become inaccessible before an update to the secondary region has finished replicating.

Por exemplo, suponha que o cliente envie uma atualização com êxito, mas a região primária falhe antes que a atualização seja propagada para a região secundária.For example, suppose your customer submits an update successfully, but the primary region fails before the update is propagated to the secondary region. Quando o cliente pede para ler os dados de volta, eles recebem os dados obsoletos da região secundária em vez dos dados atualizados.When the customer asks to read the data back, they receive the stale data from the secondary region instead of the updated data. Ao projetar seu aplicativo, você deve decidir se isso é aceitável e, nesse caso, como você enviará uma mensagem ao cliente.When designing your application, you must decide whether this is acceptable, and if so, how you will message the customer.

Neste artigo, mostramos como verificar a Hora da Última Sincronização para os dados secundários para verificar se o secundário está atualizado.Later in this article, we show how to check the Last Sync Time for the secondary data to check whether the secondary is up-to-date.

Tratamento de serviços separadamente ou em conjuntoHandling services separately or all together

Embora não seja provável, é possível que um serviço não fique disponível enquanto os outros serviços ainda estão totalmente funcionais.While unlikely, it is possible for one service to become unavailable while the other services are still fully functional. Você pode lidar com as repetições e o modo somente leitura para cada serviço separadamente (blobs, filas, tabelas) ou pode lidar com as repetições de forma genérica para todos os serviços de armazenamento em conjunto.You can handle the retries and read-only mode for each service separately (blobs, queues, tables), or you can handle retries generically for all the storage services together.

Por exemplo, se usar filas e blobs no aplicativo, você poderá optar por incluir código separado para lidar com erros com nova tentativa para cada um desses itens.For example, if you use queues and blobs in your application, you may decide to put in separate code to handle retryable errors for each of these. Em seguida, se você receber uma repetição do serviço blob, mas o serviço fila ainda estiver funcionando, somente a parte do aplicativo que lida com os blobs será afetada.Then if you get a retry from the blob service, but the queue service is still working, only the part of your application that handles blobs will be impacted. Se você decidir lidar com todas as tentativas de serviço de armazenamento de forma genérica e uma chamada ao serviço blob retornar um erros com nova tentativa, as solicitações para o serviço blob e o serviço fila serão afetadas.If you decide to handle all storage service retries generically and a call to the blob service returns a retryable error, then requests to both the blob service and the queue service will be impacted.

Em última análise, isso depende da complexidade do aplicativo.Ultimately, this depends on the complexity of your application. Você pode optar por não lidar com as falhas de serviço, mas, em vez disso, redirecionar as solicitações de leitura a todos os serviços de armazenamento para a região secundária e executar o aplicativo no modo somente leitura ao detectar um problema em qualquer serviço de armazenamento na região primária.You may decide not to handle the failures by service, but instead to redirect read requests for all storage services to the secondary region and run the application in read-only mode when you detect a problem with any storage service in the primary region.

Outras consideraçõesOther considerations

Essas são as outras considerações que discutiremos no restante deste artigo.These are the other considerations we will discuss in the rest of this article.

  • Lidar com repetições de solicitações de leitura usando o padrão de DisjuntorHandling retries of read requests using the Circuit Breaker pattern

  • Dados eventualmente consistentes e a Hora da Última SincronizaçãoEventually-consistent data and the Last Sync Time

  • TestandoTesting

Executando o aplicativo no modo somente leituraRunning your application in read-only mode

Para se preparar efetivamente para uma interrupção na região primária, você deve ser capaz de lidar com solicitações de leitura com falha e solicitações de atualização com falha (com Update neste caso, significa inserções, atualizações e exclusões).To effectively prepare for an outage in the primary region, you must be able to handle both failed read requests and failed update requests (with update in this case meaning inserts, updates, and deletions). Se a região primária falhar, as solicitações de leitura poderão ser redirecionadas para a região secundária.If the primary region fails, read requests can be redirected to the secondary region. No entanto, as solicitações de atualização não podem ser redirecionadas para o secundário porque o secundário é somente leitura.However, update requests cannot be redirected to the secondary because the secondary is read-only. Por esse motivo, você precisa projetar o aplicativo para ser executado no modo somente leitura.For this reason, you need to design your application to run in read-only mode.

Por exemplo, você pode definir um sinalizador que é verificado antes que todas as solicitações de atualização sejam enviadas ao Armazenamento do Azure.For example, you can set a flag that is checked before any update requests are submitted to Azure Storage. Quando uma das solicitações de atualização chega, você pode ignorá-la e retornar uma resposta apropriada para o cliente.When one of the update requests comes through, you can skip it and return an appropriate response to the customer. Talvez você até ainda queira desabilitar totalmente determinados recursos até que o problema seja resolvido e notificar os usuários de que esses recursos estão temporariamente indisponíveis.You may even want to disable certain features altogether until the problem is resolved and notify users that those features are temporarily unavailable.

Se optar por lidar com os erros em cada serviço separadamente, você também precisará lidar com a capacidade de executar o aplicativo no modo somente leitura pelo serviço.If you decide to handle errors for each service separately, you will also need to handle the ability to run your application in read-only mode by service. Por exemplo, você pode ter sinalizadores somente leitura para cada serviço que pode ser habilitado e desabilitado.For example, you may have read-only flags for each service that can be enabled and disabled. Em seguida, você pode manipular o sinalizador nos lugares apropriados do código.Then you can handle the flag in the appropriate places in your code.

Ser capaz de executar o aplicativo no modo somente leitura tem outro benefício: a capacidade de garantir funcionalidade limitada durante uma atualização importante do aplicativo.Being able to run your application in read-only mode has another side benefit – it gives you the ability to ensure limited functionality during a major application upgrade. Você pode disparar o aplicativo para ser executado no modo somente leitura e apontar para o data center secundário, garantindo que ninguém acessa os dados na região primária enquanto você faz atualizações.You can trigger your application to run in read-only mode and point to the secondary data center, ensuring nobody is accessing the data in the primary region while you're making upgrades.

Tratamento de atualizações ao executar no modo somente leituraHandling updates when running in read-only mode

Há várias maneiras de lidar com solicitações de atualização durante a execução no modo somente leitura.There are many ways to handle update requests when running in read-only mode. Não abordaremos isso de forma abrangente, mas, em geral, há alguns padrões a serem considerados.We won't cover this comprehensively, but generally, there are a couple of patterns that you consider.

  1. Você pode responder ao usuário e informar que não está aceitando atualizações.You can respond to your user and tell them you are not currently accepting updates. Por exemplo, um sistema de gerenciamento de contatos pode habilitar os clientes a acessar informações de contato, mas não fazer atualizações.For example, a contact management system could enable customers to access contact information but not make updates.

  2. Você pode enfileirar as atualizações em outra região.You can enqueue your updates in another region. Nesse caso, você gravaria as solicitações de atualização pendentes em uma fila em uma região diferente e teria uma maneira de processar essas solicitações depois que o data center primário ficasse online novamente.In this case, you would write your pending update requests to a queue in a different region, and then have a way to process those requests after the primary data center comes online again. Nesse cenário, você deve informar ao cliente que a atualização solicitada está na fila para processamento posterior.In this scenario, you should let the customer know that the update requested is queued for later processing.

  3. Você pode gravar as atualizações em uma conta de armazenamento em outra região.You can write your updates to a storage account in another region. Em seguida, quando o data center primário ficar online novamente, você poderá ter uma maneira de mesclar essas atualizações nos dados principais, dependendo da estrutura dos dados.Then when the primary data center comes back online, you can have a way to merge those updates into the primary data, depending on the structure of the data. Por exemplo, se estiver criando arquivos separados com um carimbo de data/hora no nome, você poderá copiar esses arquivos de volta para a região primária.For example, if you are creating separate files with a date/time stamp in the name, you can copy those files back to the primary region. Isso funciona para algumas cargas de trabalho, como dados de log e iOT.This works for some workloads such as logging and iOT data.

Lidar com repetiçõesHandling retries

A biblioteca de cliente de armazenamento do Azure ajuda a determinar quais erros podem ser repetidos.The Azure Storage client library helps you determine which errors can be retried. Por exemplo, um erro 404 (recurso não encontrado) pode ser repetido porque repetir não é provável que ele resulte em sucesso.For example, a 404 error (resource not found) can be retried because retrying it is not likely to result in success. Por outro lado, um erro 500 não pode ser repetido porque é um erro de servidor e pode ser simplesmente um problema transitório.On the other hand, a 500 error cannot be retried because it is a server error, and it may simply be a transient issue. Para obter mais detalhes, confira abrir o código-fonte para a classe ExponentialRetry na biblioteca de cliente de armazenamento do .NET.For more details, check out the open source code for the ExponentialRetry class in the .NET storage client library. (Procure o método ShouldRetry.)(Look for the ShouldRetry method.)

Solicitações de leituraRead requests

Solicitações de leitura poderão ser redirecionadas para o armazenamento secundário, se houver um problema no armazenamento primário.Read requests can be redirected to secondary storage if there is a problem with primary storage. Conforme observado acima em Usando dados eventualmente consistentes, deve ser aceitável que o aplicativo potencialmente leia dados obsoletos.As noted above in Using Eventually Consistent Data, it must be acceptable for your application to potentially read stale data. Se você estiver usando a biblioteca de cliente de armazenamento para acessar dados do secundário, poderá especificar o comportamento de repetição de uma solicitação de leitura definindo um valor para a propriedade locationmode como um dos seguintes:If you are using the storage client library to access data from the secondary, you can specify the retry behavior of a read request by setting a value for the LocationMode property to one of the following:

  • PrimaryOnly (o padrão)PrimaryOnly (the default)

  • PrimaryThenSecondaryPrimaryThenSecondary

  • SecondaryOnlySecondaryOnly

  • SecondaryThenPrimarySecondaryThenPrimary

Quando você define o locationmode como PrimaryThenSecondary, se a solicitação de leitura inicial para o ponto de extremidade primário falhar com um erro que pode ser repetido, o cliente fará automaticamente outra solicitação de leitura para o ponto de extremidade secundário.When you set the LocationMode to PrimaryThenSecondary, if the initial read request to the primary endpoint fails with an error that can be retried, the client automatically makes another read request to the secondary endpoint. Se o erro for um tempo limite do servidor, o cliente terá que aguardar até que o tempo limite expire antes de receber um erro com nova tentativa do serviço.If the error is a server timeout, then the client will have to wait for the timeout to expire before it receives a retryable error from the service.

Existem basicamente dois cenários a serem considerados ao decidir como reagir a um erro com nova tentativa:There are basically two scenarios to consider when you are deciding how to respond to a retryable error:

  • Esse é um problema isolado, e solicitações subsequentes para o ponto de extremidade primário não retornarão um erro com nova tentativa.This is an isolated problem and subsequent requests to the primary endpoint will not return a retryable error. Um exemplo é quando há um erro de rede temporário.An example of where this might happen is when there is a transient network error.

    Nesse cenário, não há uma redução de desempenho significativa quando LocationMode é definido como PrimaryThenSecondary, pois isso ocorre apenas raramente.In this scenario, there is no significant performance penalty in having LocationMode set to PrimaryThenSecondary as this only happens infrequently.

  • Esse é um problema pelo menos para um dos serviços de armazenamento na região primária, e todas as solicitações subsequentes desse serviço na região primária provavelmente retornarão erros com nova tentativa por um período de tempo.This is a problem with at least one of the storage services in the primary region and all subsequent requests to that service in the primary region are likely to return retryable errors for a period of time. Um exemplo disso é se a região primária está totalmente inacessível.An example of this is if the primary region is completely inaccessible.

    Nesse cenário, há uma redução de desempenho porque todas as solicitações de leitura tentarão primeiro o ponto de extremidade primário, aguardarão até que o tempo limite expire e alternarão para o ponto de extremidade secundário.In this scenario, there is a performance penalty because all your read requests will try the primary endpoint first, wait for the timeout to expire, then switch to the secondary endpoint.

Nesses cenários, você deve identificar que há um problema contínuo no ponto de extremidade primário e enviar todas as solicitações de leitura diretamente para o ponto de extremidade secundário, definindo a propriedade LocationMode como SecondaryOnly.For these scenarios, you should identify that there is an ongoing issue with the primary endpoint and send all read requests directly to the secondary endpoint by setting the LocationMode property to SecondaryOnly. Nesse momento, você também deve alterar o aplicativo para que seja executado no modo somente leitura.At this time, you should also change the application to run in read-only mode. Essa abordagem é conhecida como Padrão de Disjuntor.This approach is known as the Circuit Breaker Pattern.

Solicitações de atualizaçãoUpdate requests

O padrão de Disjuntor também pode ser aplicado a solicitações de atualização.The Circuit Breaker pattern can also be applied to update requests. No entanto, as solicitações de atualização não poderão ser redirecionadas para o armazenamento secundário, que é somente leitura.However, update requests cannot be redirected to secondary storage, which is read-only. Para essas solicitações, você deve deixar a propriedade LocationMode definida como PrimaryOnly (o padrão).For these requests, you should leave the LocationMode property set to PrimaryOnly (the default). Para lidar com esses erros, você pode aplicar uma métrica para essas solicitações (por exemplo, 10 falhas contínuas) e, quando o limite for atingido, alternar o aplicativo para o modo somente leitura.To handle these errors, you can apply a metric to these requests – such as 10 failures in a row – and when your threshold is met, switch the application into read-only mode. Você pode usar os mesmos métodos para retornar para o modo de atualização que são descritos abaixo na seção seguinte sobre o padrão de Disjuntor.You can use the same methods for returning to update mode as those described below in the next section about the Circuit Breaker pattern.

Padrão de DisjuntorCircuit Breaker pattern

Usar o padrão de Disjuntor no aplicativo pode impedi-lo de repetir uma operação que provavelmente falhará repetidas vezes.Using the Circuit Breaker pattern in your application can prevent it from retrying an operation that is likely to fail repeatedly. Ele permite que o aplicativo continue a ser executado em vez de gastar tempo enquanto a operação é repetida exponencialmente.It allows the application to continue to run rather than taking up time while the operation is retried exponentially. Ele também detecta quando a falha é corrigida e, nesse momento, o aplicativo pode tentar a operação novamente.It also detects when the fault has been fixed, at which time the application can try the operation again.

Como implementar o padrão de disjuntorHow to implement the circuit breaker pattern

Para identificar um problema contínuo em um ponto de extremidade primário, você pode monitorar com que frequência o cliente encontra erros com nova tentativa.To identify that there is an ongoing problem with a primary endpoint, you can monitor how frequently the client encounters retryable errors. Como cada caso é diferente, você precisa decidir sobre o limite que deseja usar para a decisão de alternar para o ponto de extremidade secundário e executar o aplicativo no modo somente leitura.Because each case is different, you have to decide on the threshold you want to use for the decision to switch to the secondary endpoint and run the application in read-only mode. Por exemplo, você poderá decidir executar a mudança se houver 10 falhas contínuas sem sucesso.For example, you could decide to perform the switch if there are 10 failures in a row with no successes. Outro exemplo é alternar se 90% das solicitações em um período de dois minutos falharem.Another example is to switch if 90% of the requests in a 2-minute period fail.

Para o primeiro cenário, você pode simplesmente manter uma contagem de falhas e, se houver êxito antes de atingir o máximo, definir a contagem como zero.For the first scenario, you can simply keep a count of the failures, and if there is a success before reaching the maximum, set the count back to zero. Para o segundo cenário, uma maneira de implementá-lo é usar o objeto MemoryCache (no .NET).For the second scenario, one way to implement it is to use the MemoryCache object (in .NET). Para cada solicitação, adicione um CacheItem no cache, defina o valor para sucesso (1) ou falha (0) e defina o tempo de expiração de dois minutos a partir de agora (ou a restrição de tempo que desejar).For each request, add a CacheItem to the cache, set the value to success (1) or fail (0), and set the expiration time to 2 minutes from now (or whatever your time constraint is). Quando o tempo de expiração de uma entrada for atingido, a entrada será removida automaticamente.When an entry's expiration time is reached, the entry is automatically removed. Isso lhe dará uma janela de dois minutos sem interrupção.This will give you a rolling 2-minute window. Sempre que faz uma solicitação ao serviço de armazenamento, primeiro você usa uma consulta Linq no objeto MemoryCache para calcular a porcentagem de êxitos somando os valores e dividindo pela contagem.Each time you make a request to the storage service, you first use a Linq query across the MemoryCache object to calculate the percent success by summing the values and dividing by the count. Quando a porcentagem de êxitos ficar abaixo de determinado limite (como 10%), defina a propriedade LocationMode para solicitações de leitura como SecondaryOnly e alterne o aplicativo para o modo somente leitura antes de continuar.When the percent success drops below some threshold (such as 10%), set the LocationMode property for read requests to SecondaryOnly and switch the application into read-only mode before continuing.

O limite de erros usado para determinar quando alternar pode variar dependendo do serviço no aplicativo. Portanto, você deve considerar torná-los parâmetros configuráveis.The threshold of errors used to determine when to make the switch may vary from service to service in your application, so you should consider making them configurable parameters. Esse também é o momento para decidir se erros com nova tentativa de cada serviço devem ser tratados separadamente ou em conjunto, conforme discutido anteriormente.This is also where you decide to handle retryable errors from each service separately or as one, as discussed previously.

Outra consideração é como lidar com várias instâncias de um aplicativo e o que fazer ao detectar erros com nova tentativa em cada instância.Another consideration is how to handle multiple instances of an application, and what to do when you detect retryable errors in each instance. Por exemplo, você pode ter 20 VMs em execução com o mesmo aplicativo carregado.For example, you may have 20 VMs running with the same application loaded. Você lida com cada instância separadamente?Do you handle each instance separately? Se uma instância começar a apresentar problemas, você deseja limitar a resposta para apenas se uma instância ou deseja tentar fazer com que todas as instâncias respondam da mesma forma quando uma instância tiver um problema?If one instance starts having problems, do you want to limit the response to just that one instance, or do you want to try to have all instances respond in the same way when one instance has a problem? Tratar as instâncias separadamente é muito mais simples do que tentar coordenar a resposta entre elas, mas a maneira de fazer isso depende da arquitetura do aplicativo.Handling the instances separately is much simpler than trying to coordinate the response across them, but how you do this depends on your application's architecture.

Opções de monitoramento da frequência de errosOptions for monitoring the error frequency

Você tem três opções principais para monitorar a frequência de novas tentativas na região primária para determinar quando passar para a região secundária e alterar o aplicativo para que seja executado no modo somente leitura.You have three main options for monitoring the frequency of retries in the primary region in order to determine when to switch over to the secondary region and change the application to run in read-only mode.

  • Adicionar um manipulador para o evento Retrying do objeto OperationContext que você passa para solicitações de armazenamento. Esse é o método apresentado neste artigo e usado no exemplo que o acompanha.Add a handler for the Retrying event on the OperationContext object you pass to your storage requests – this is the method displayed in this article and used in the accompanying sample. Esses eventos são acionados sempre que o cliente tenta novamente uma solicitação, permitindo que você controle com que frequência o cliente encontra erros com nova tentativa em um ponto de extremidade primário.These events fire whenever the client retries a request, enabling you to track how often the client encounters retryable errors on a primary endpoint.

    operationContext.Retrying += (sender, arguments) =>
    {
        // Retrying in the primary region
        if (arguments.Request.Host == primaryhostname)
            ...
    };
    
  • No método Evaluate em uma política de repetição personalizada, você pode executar código personalizado sempre que uma repetição ocorre.In the Evaluate method in a custom retry policy, you can run custom code whenever a retry takes place. Além de gravação quando uma repetição ocorre, isso também lhe dá a oportunidade de modificar o comportamento de repetição.In addition to recording when a retry happens, this also gives you the opportunity to modify your retry behavior.

    public RetryInfo Evaluate(RetryContext retryContext,
    OperationContext operationContext)
    {
        var statusCode = retryContext.LastRequestResult.HttpStatusCode;
        if (retryContext.CurrentRetryCount >= this.maximumAttempts
            || ((statusCode >= 300 && statusCode < 500 && statusCode != 408)
            || statusCode == 501 // Not Implemented
            || statusCode == 505 // Version Not Supported
            ))
        {
            // Do not retry
            return null;
        }
    
        // Monitor retries in the primary location
        ...
    
        // Determine RetryInterval and TargetLocation
        RetryInfo info =
            CreateRetryInfo(retryContext.CurrentRetryCount);
    
        return info;
    }
    
  • A terceira abordagem é implementar um componente de monitoramento personalizado no aplicativo que continuamente executa ping no ponto de extremidade de armazenamento primário com solicitações de leitura fictícias (como ler um blob pequeno) para determinar sua integridade.The third approach is to implement a custom monitoring component in your application that continually pings your primary storage endpoint with dummy read requests (such as reading a small blob) to determine its health. Isso deve exigir alguns recursos, mas não uma quantidade significativa.This would take up some resources, but not a significant amount. Quando é descoberto um problema que atinge o limite você executa a mudança para SecondaryOnly e o modo somente leitura.When a problem is discovered that reaches your threshold, you would then perform the switch to SecondaryOnly and read-only mode.

Em algum momento, convém alternar de volta para o ponto de extremidade primário e permitir atualizações.At some point, you will want to switch back to using the primary endpoint and allowing updates. Se usar um dos dois primeiros métodos listados acima, você poderá simplesmente alternar de novo para o ponto de extremidade primário e habilitar o modo de atualização após um período arbitrariamente selecionado ou a execução de determinado número de operações.If using one of the first two methods listed above, you could simply switch back to the primary endpoint and enable update mode after an arbitrarily selected amount of time or number of operations has been performed. Você pode permitir que ele percorra a lógica de repetição novamente.You can then let it go through the retry logic again. Se o problema tiver sido corrigido, ele continuará a usar o ponto de extremidade primário e a permitir atualizações.If the problem has been fixed, it will continue to use the primary endpoint and allow updates. Se ainda houver um problema, ele alternará mais uma vez para o ponto de extremidade secundário e o modo somente leitura depois de ser reprovado nos critérios que você definiu.If there is still a problem, it will once more switch back to the secondary endpoint and read-only mode after failing the criteria you've set.

Para o terceiro cenário, quando a execução de ping no ponto de extremidade de armazenamento primário tiver êxito novamente, você poderá alternar de volta para PrimaryOnly e continuar permitindo atualizações.For the third scenario, when pinging the primary storage endpoint becomes successful again, you can trigger the switch back to PrimaryOnly and continue allowing updates.

Manipulação de dados eventualmente consistentesHandling eventually consistent data

O armazenamento com redundância geográfica funciona replicando as transações da região primária para a secundária.Geo-redundant storage works by replicating transactions from the primary to the secondary region. Esse processo de replicação garante que os dados na região secundária sejam eventualmente consistentes.This replication process guarantees that the data in the secondary region is eventually consistent. Isso significa que todas as transações na região primária eventualmente aparecerão na região secundária, mas pode haver um atraso antes de aparecerem e não há garantia de que as transações chegarão na região secundária na mesma ordem que em que foram aplicadas originalmente na região primária.This means that all the transactions in the primary region will eventually appear in the secondary region, but that there may be a lag before they appear, and that there is no guarantee the transactions arrive in the secondary region in the same order as that in which they were originally applied in the primary region. Se as transações chegarem na região secundária fora de ordem, você poderá considerar que os dados na região secundária estão em um estado inconsistente até que o serviço restabeleça a ordem.If your transactions arrive in the secondary region out of order, you may consider your data in the secondary region to be in an inconsistent state until the service catches up.

A tabela a seguir mostra um exemplo do que pode acontecer quando você atualiza os detalhes de um funcionário para torná-los membros da função Administradores .The following table shows an example of what might happen when you update the details of an employee to make them a member of the administrators role. Para este exemplo, isso requer que você atualize a entidade funcionário e atualize uma entidade função de administrador com uma contagem do número total de administradores.For the sake of this example, this requires you update the employee entity and update an administrator role entity with a count of the total number of administrators. Observe como as atualizações são aplicadas fora de ordem na região secundária.Notice how the updates are applied out of order in the secondary region.

HoraTime TransaçãoTransaction ReplicaçãoReplication Hora da Última SincronizaçãoLast Sync Time ResultadoResult
T0T0 Transação A:Transaction A:
Inserir funcionárioInsert employee
entidade no principalentity in primary
Transação A inserida no primário,Transaction A inserted to primary,
ainda não replicada.not replicated yet.
T1T1 Transação ATransaction A
replicada parareplicated to
secundáriosecondary
T1T1 A transação A foi replicada para o secundário.Transaction A replicated to secondary.
Hora da Última Sincronização atualizada.Last Sync Time updated.
T2T2 Transação B:Transaction B:
AtualizarUpdate
entidade de funcionárioemployee entity
no principalin primary
T1T1 Transação B gravada no principal,Transaction B written to primary,
ainda não replicada.not replicated yet.
T3T3 Transação C:Transaction C:
AtualizarUpdate
administratoradministrator
entidade de função emrole entity in
primaryprimary
T1T1 Transação C gravada no principal,Transaction C written to primary,
ainda não replicada.not replicated yet.
T4T4 Transação CTransaction C
replicada parareplicated to
secundáriosecondary
T1T1 Transação C replicada para o secundário.Transaction C replicated to secondary.
LastSyncTime não atualizado porqueLastSyncTime not updated because
a transação B ainda não foi replicada.transaction B has not been replicated yet.
T5T5 Ler entidadesRead entities
de secundáriofrom secondary
T1T1 Você obtém o valor obsoleto para a entidade de funcionárioYou get the stale value for employee
porque a transação B não foientity because transaction B hasn't
replicada ainda.replicated yet. Você obtém o novo valor paraYou get the new value for
a entidade de função de administrador porque C foiadministrator role entity because C has
replicada.replicated. A Hora da Última Sincronização ainda nãoLast Sync Time still hasn't
foi atualizada porque a transação Bbeen updated because transaction B
não foi replicada.hasn't replicated. Você pode ver que aYou can tell the
entidade da função de administrador está inconsistenteadministrator role entity is inconsistent
porque a data/hora da entidade é posteriorbecause the entity date/time is after
à Hora da Última Sincronização.the Last Sync Time.
T6T6 Transação BTransaction B
replicada parareplicated to
secundáriosecondary
T6T6 T6 – todas as transações até CT6 – All transactions through C have
foram replicadas; a Hora da Última Sincronizaçãobeen replicated, Last Sync Time
foi atualizada.is updated.

Neste exemplo, suponha que o cliente alterne para leitura da região secundária em T5.In this example, assume the client switches to reading from the secondary region at T5. Ele pode ler com êxito a entidade de função de administrador nesse momento, mas a entidade contém um valor para a contagem de administradores que não é consistente com o número de entidades funcionário que são marcadas como administradores na região secundária nesse momento.It can successfully read the administrator role entity at this time, but the entity contains a value for the count of administrators that is not consistent with the number of employee entities that are marked as administrators in the secondary region at this time. O cliente simplesmente pode exibir esse valor, com o risco de que se trata de informações inconsistentes.Your client could simply display this value, with the risk that it is inconsistent information. 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 esse fato ao usuário.Alternatively, the client could attempt to determine that the administrator role is in a potentially inconsistent state because the updates have happened out of order, and then inform the user of this fact.

Para reconhecer que ele tem dados potencialmente inconsistentes, o cliente pode usar o valor da Hora da Última Sincronização, que você pode obter a qualquer momento consultando um serviço de armazenamento.To recognize that it has potentially inconsistent data, the client can use the value of the Last Sync Time that you can get at any time by querying a storage service. Isso indica a hora em que os dados na região secundária estiveram consistentes pela última vez e quando o serviço aplicou todas as transações antes desse ponto no tempo.This tells you the time when the data in the secondary region was last consistent and when the service had applied all the transactions prior to that point in time. No exemplo mostrado acima, após o serviço inserir a entidade funcionário na região secundária, a Hora da Última Sincronização é definida como T1.In the example shown above, after the service inserts the employee entity in the secondary region, the last sync time is set to T1. Ela permanece em T1 até que as atualizações de serviço da entidade funcionário na região secundária, quando ela é definida como T6.It remains at T1 until the service updates the employee entity in the secondary region when it is set to T6. Se o cliente recupera a hora da última sincronização ao ler a entidade em T5, pode compará-la ao carimbo de data/hora na entidade.If the client retrieves the last sync time when it reads the entity at T5, it can compare it with the timestamp on the entity. Se o carimbo de data/hora na entidade é posterior à hora da última sincronização, a entidade está em um estado potencialmente inconsistente, e você pode tomar a ação apropriada para o aplicativo.If the timestamp on the entity is later than the last sync time, then the entity is in a potentially inconsistent state, and you can take whatever is the appropriate action for your application. Usar esse campo requer que você saiba quando a última atualização do primário foi concluída.Using this field requires that you know when the last update to the primary was completed.

Obtendo a hora da última sincronizaçãoGetting the last sync time

Você pode usar o PowerShell ou CLI do Azure para recuperar a hora da última sincronização para determinar quando os dados foram gravados pela última vez no secundário.You can use PowerShell or Azure CLI to retrieve the last sync time to determine when data was last written to the secondary.

PowerShellPowerShell

Para obter a hora da última sincronização para a conta de armazenamento usando o PowerShell, instale um módulo de visualização do armazenamento do Azure que dá suporte à obtenção de estatísticas de replicação geográfica. Por exemplo:To get the last sync time for the storage account by using PowerShell, install an Azure Storage preview module that supports getting geo-replication stats. For example:

Install-Module Az.Storage –Repository PSGallery -RequiredVersion 1.1.1-preview –AllowPrerelease –AllowClobber –Force

Em seguida, verifique a propriedade GeoReplicationStats. LastSyncTime da conta de armazenamento.Then check the storage account's GeoReplicationStats.LastSyncTime property. Lembre-se de substituir os valores de espaço reservado pelos seus próprios valores:Remember to replace the placeholder values with your own values:

$lastSyncTime = $(Get-AzStorageAccount -ResourceGroupName <resource-group> `
    -Name <storage-account> `
    -IncludeGeoReplicationStats).GeoReplicationStats.LastSyncTime

Azure CLIAzure CLI

Para obter a hora da última sincronização para a conta de armazenamento usando CLI do Azure, verifique a propriedade geoReplicationStats. lastSyncTime da conta de armazenamento.To get the last sync time for the storage account by using Azure CLI, check the storage account's geoReplicationStats.lastSyncTime property. Use o parâmetro --expand para retornar valores para as propriedades aninhadas em geoReplicationStats.Use the --expand parameter to return values for the properties nested under geoReplicationStats. Lembre-se de substituir os valores de espaço reservado pelos seus próprios valores:Remember to replace the placeholder values with your own values:

$lastSyncTime=$(az storage account show \
    --name <storage-account> \
    --resource-group <resource-group> \
    --expand geoReplicationStats \
    --query geoReplicationStats.lastSyncTime \
    --output tsv)

TestandoTesting

É importante testar se o aplicativo se comporta conforme o esperado ao encontra erros com nova tentativa.It's important to test that your application behaves as expected when it encounters retryable errors. Por exemplo, você precisa testar se o aplicativo alterna para o secundário e o modo somente leitura ao detectar um problema e alterna de volta quando a região primária fica disponível novamente.For example, you need to test that the application switches to the secondary and into read-only mode when it detects a problem, and switches back when the primary region becomes available again. Para fazer isso, você precisa de uma maneira de simular erros com nova tentativa e controlar com que frequência eles ocorrem.To do this, you need a way to simulate retryable errors and control how often they occur.

Você pode usar o Fiddler para interceptar e modificar respostas HTTP em um script.You can use Fiddler to intercept and modify HTTP responses in a 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 Cliente de Armazenamento o reconheça como um erros com nova tentativa.This script can identify responses that come from your primary endpoint and change the HTTP status code to one that the Storage Client Library recognizes as a retryable error. Este snippet de código mostra um exemplo simples de um script do Fiddler que intercepta as respostas para ler as solicitações em relação à tabela employeedata para retornar um status 502:This code snippet shows a simple example of a Fiddler script that intercepts responses to read requests against the employeedata table to return a 502 status:

static function OnBeforeResponse(oSession: Session) {
    ...
    if ((oSession.hostname == "\[yourstorageaccount\].table.core.windows.net")
      && (oSession.PathAndQuery.StartsWith("/employeedata?$filter"))) {
        oSession.responseCode = 502;
    }
}

Você pode estender esse exemplo para interceptar uma maior gama de solicitações e alterar apenas o responseCode em alguns deles para simular melhor um cenário do mundo real.You could extend this example to intercept a wider range of requests and only change the responseCode on some of them to better simulate a real-world scenario. Para obter mais informações sobre como personalizar os scripts do Fiddler, confira Modificando uma solicitação ou resposta na documentação do Fiddler.For more information about customizing Fiddler scripts, see Modifying a Request or Response in the Fiddler documentation.

Se você tiver tornado configuráveis os limites para alternar o aplicativo para o modo somente leitura, será mais fácil testar o comportamento com volumes de transações de não produção.If you have made the thresholds for switching your application to read-only mode configurable, it will be easier to test the behavior with non-production transaction volumes.

Próximas etapasNext Steps