Plataforma de dados para cargas de trabalho de missão crítica no Azure

Em uma arquitetura de missão crítica, qualquer estado deve ser armazenado fora da computação, tanto quanto possível. A escolha da tecnologia baseia-se nas seguintes características arquitetónicas chave:

Características Considerações
Desempenho Quanta computação é necessária?
Latência Que impacto terá a distância entre o utilizador e o armazenamento de dados na latência? Qual é o nível desejado de consistência com o tradeoff na latência?
Capacidade de Resposta É necessário que o armazenamento de dados esteja sempre disponível?
Escalabilidade Qual é o esquema de particionamento?
Durabilidade Espera-se que os dados sejam duradouros? O que é a política de retenção?
Resiliência Em caso de falha, o armazenamento de dados pode fazer failover automaticamente? Que medidas estão em vigor para reduzir o tempo de failover?
Segurança Os dados são encriptados? O armazenamento de dados pode ser acessado pela rede pública?

Nessa arquitetura, há dois armazenamentos de dados:

  • Base de dados

    Armazenamentos relacionados à carga de trabalho. Recomenda-se que todos os estados sejam armazenados globalmente em um banco de dados separado dos selos regionais. Crie redundância implantando o banco de dados entre regiões. Para cargas de trabalho de missão crítica, a sincronização de dados entre regiões deve ser a principal preocupação. Além disso, em caso de falha, as solicitações de gravação no banco de dados ainda devem ser funcionais.

    A replicação de dados em uma configuração ativa-ativa é altamente recomendada. O aplicativo deve ser capaz de se conectar instantaneamente com outra região. Todas as instâncias devem ser capazes de lidar com solicitações de leitura e gravação.

  • Agente de mensagens

    O único serviço com estado no carimbo regional é o agente de mensagens, que armazena solicitações por um curto período. O corretor atende à necessidade de buffering e mensagens confiáveis. As solicitações processadas são mantidas no banco de dados global.

Para outras considerações sobre dados, consulte Misson-critical guidance in Well-architected Framework: Data platform considerations.

Base de dados

Essa arquitetura usa o Azure Cosmos DB para NoSQL. Esta opção é escolhida porque fornece a maioria dos recursos necessários neste design:

  • Gravação em várias regiões

    A gravação em várias regiões é habilitada com réplicas implantadas em todas as regiões em que um carimbo é implantado. Cada carimbo pode escrever localmente e o Azure Cosmos DB lida com a replicação de dados e a sincronização entre os carimbos. Esse recurso reduz significativamente a latência para usuários finais geograficamente distribuídos do aplicativo. A implementação de referência de Missão Crítica do Azure usa tecnologia multimestre para fornecer máxima resiliência e disponibilidade.

    A redundância de zona também é habilitada em cada região replicada.

    Para obter detalhes sobre gravações de várias regiões, consulte Configurar gravações de várias regiões em seus aplicativos que usam o Azure Cosmos DB.

  • Gestão de conflitos

    Com a capacidade de executar gravações em várias regiões, surge a necessidade de adotar um modelo de gerenciamento de conflitos, pois gravações simultâneas podem introduzir conflitos de registro. Last Writer Wins é o modelo padrão e é usado para o design de missão crítica. O último escritor, conforme definido pelos carimbos de data/hora associados dos registros, ganha o conflito. O Azure Cosmos DB para NoSQL também permite que uma propriedade personalizada seja definida.

  • Otimização de consultas

    Uma recomendação geral de eficiência de consulta para contêineres de leitura pesada com um grande número de partições é adicionar um filtro de igualdade com o itemID identificado. Uma análise aprofundada das recomendações de otimização de consultas pode ser encontrada em Solucionar problemas de consulta ao usar o Azure Cosmos DB.

  • Recurso de backup

    É recomendável usar o recurso de backup nativo do Azure Cosmos DB para proteção de dados. O recurso de backup do Azure Cosmos DB oferece suporte a backups online e restauração de dados sob demanda.

Nota

A maioria das cargas de trabalho não são puramente OLTP. Há uma demanda crescente por relatórios em tempo real, como a execução de relatórios no sistema operacional. Isso também é conhecido como HTAP (Hybrid Transactional and Analytical Processing). O Azure Cosmos DB dá suporte a esse recurso por meio do Azure Synapse Link for Azure Cosmos DB.

Modelo de dados para a carga de trabalho

O modelo de dados deve ser projetado de modo que os recursos oferecidos pelos bancos de dados relacionais tradicionais não sejam necessários. Por exemplo, chaves estrangeiras, esquema estrito de linha/coluna, modos de exibição e outros.

A carga de trabalho tem estas características de acesso a dados:

  • Padrão de leitura:
    • Ponto lê - Obtenção de um único registo. O ID do item e a chave de partição são usados diretamente para otimização máxima (1 RU por solicitação).
    • Listar leituras - Obter itens de catálogo para exibição em uma lista. FeedIterator com limite no número de resultados é usado.
  • Padrão de escrita:
    • Pequenas gravações - As solicitações geralmente inserem um único ou um pequeno número de registros em uma transação.
  • Projetado para lidar com alto tráfego de usuários finais com a capacidade de escalar para lidar com a demanda de tráfego na ordem de milhões de usuários.
  • Pequena carga útil ou tamanho do conjunto de dados - geralmente em ordem de KB.
  • Tempo de resposta baixo (em ordem de milissegundos).
  • Baixa latência (em ordem de milissegundos).

Configuração

O Azure Cosmos DB está configurado da seguinte forma:

  • O nível de consistência é definido como a consistência de sessão padrão porque é o nível mais usado para uma única região e aplicativos distribuídos globalmente. A consistência mais fraca com uma taxa de transferência mais alta não é necessária devido à natureza assíncrona do processamento de gravação e não requer baixa latência na gravação do banco de dados.

    Nota

    O nível de consistência da sessão oferece uma compensação razoável para garantias de latência, disponibilidade e consistência para este aplicativo específico. É importante entender que o nível de consistência forte não está disponível para bancos de dados de gravação de vários mestres.

  • A chave de partição é definida como /id para todas as coleções. Esta decisão é baseada no padrão de uso, que é principalmente "escrever novos documentos com GUID como o ID" e "ler uma ampla gama de documentos por IDs". Desde que o código do aplicativo mantenha sua exclusividade de ID, os novos dados são distribuídos uniformemente em partições pelo Azure Cosmos DB, permitindo uma escala infinita.

  • A política de indexação é configurada em coleções para otimizar consultas. Para otimizar o custo e o desempenho da RU, uma política de indexação personalizada é usada. Esta política indexa apenas as propriedades que são usadas em predicados de consulta. Por exemplo, o aplicativo não usa o campo de texto de comentário como um filtro em consultas. Foi excluído da política de indexação personalizada.

Aqui está um exemplo da implementação que mostra as configurações de política de indexação usando o Terraform:

indexing_policy {

  excluded_path {
    path = "/description/?"
  }

  excluded_path {
    path = "/comments/text/?"
  }

  included_path {
    path = "/*"
  }

}

Para obter informações sobre a conexão do aplicativo ao Azure Cosmos DB nessa arquitetura, consulte Considerações sobre a plataforma de aplicativo para cargas de trabalho de missão crítica

Serviços de mensagens

Os sistemas de missão crítica geralmente utilizam serviços de mensagens para processamento de mensagens ou eventos. Esses serviços promovem acoplamentos flexíveis e atuam como um buffer que isola o sistema contra picos inesperados na demanda.

  • O Barramento de Serviço do Azure é recomendado para cargas de trabalho baseadas em mensagens ao lidar com mensagens de alto valor.
  • Os Hubs de Eventos do Azure são recomendados para sistemas baseados em eventos que processam grandes volumes de eventos ou telemetria.

A seguir estão considerações de design e recomendações para o Azure Service Bus Premium e os Hubs de Eventos do Azure em uma arquitetura de missão crítica.

Lidar com a carga

O sistema de mensagens deve ser capaz de lidar com a taxa de transferência necessária (como em MB por segundo). Considere o seguinte:

  • Os requisitos não funcionais (NFRs) do sistema devem especificar o tamanho médio da mensagem e o número máximo de mensagens/segundo que cada carimbo deve suportar. Esta informação pode ser utilizada para calcular o pico necessário de MB/segundo por carimbo.
  • O impacto de um failover deve ser considerado ao calcular o pico necessário de MB/segundo por carimbo.
  • Para o Barramento de Serviço do Azure, os NFRs devem especificar quaisquer recursos avançados do Barramento de Serviço, como sessões e mensagens de eliminação de duplicação. Esses recursos afetarão a taxa de transferência do Service Bus.
  • A taxa de transferência do Service Bus com os recursos necessários deve ser calculada por meio de testes como MB/segundo por Unidade de Mensagens (MU). Para obter mais informações sobre este tópico, consulte Camadas de mensagens padrão e premium do Service Bus.
  • A taxa de transferência dos Hubs de Eventos do Azure deve ser calculada por meio de testes como MB/segundo por unidade de taxa de transferência (TU) para a camada padrão ou unidade de processamento (PU) para a camada premium. Para obter mais informações sobre este tópico, consulte Dimensionamento com Hubs de Eventos.
  • Os cálculos acima podem ser usados para validar se o serviço de mensagens pode lidar com a carga necessária por carimbo e o número necessário de unidades de escala necessárias para atender a essa carga.
  • A seção de operações discutirá o dimensionamento automático.

Todas as mensagens devem ser processadas

A camada premium do Barramento de Serviço do Azure é a solução recomendada para mensagens de alto valor cujo processamento deve ser garantido. A seguir estão os detalhes sobre esse requisito ao usar o Azure Service Bus premium:

  • Para garantir que as mensagens sejam transferidas e aceitas corretamente pelo broker, os produtores de mensagens devem usar um dos clientes de API do Service Bus suportados. As APIs suportadas só retornarão com êxito de uma operação de envio se a mensagem persistir na fila/tópico.

  • Para garantir que as mensagens no barramento sejam processadas, você deve usar o modo de recebimento PeekLock. Este modo permite pelo menos uma vez o processamento. A seguir, descreve-se o processo:

    • O consumidor recebe a mensagem a ser processada.
    • O consumidor recebe um bloqueio exclusivo na mensagem por um determinado período de tempo.
    • Se o consumidor processar a mensagem com êxito, ele enviará uma confirmação de volta ao corretor e a mensagem será removida da fila.
    • Se uma confirmação não for recebida pelo corretor no período de tempo atribuído, ou se o manipulador abandonar explicitamente a mensagem, o bloqueio exclusivo será liberado. A mensagem fica então disponível para outros consumidores processarem a mensagem.
    • Se uma mensagem não for processada com êxito um número configurável de vezes, ou o manipulador encaminhará a mensagem para a fila de mensagens mortas.
      • Para garantir que as mensagens enviadas para a fila de mensagens mortas sejam atendidas, a fila de mensagens mortas deve ser monitorada e alertas devem ser definidos.
      • O sistema deve ter ferramentas para que os operadores possam inspecionar, corrigir e reenviar mensagens.
  • Como as mensagens podem ser processadas mais de uma vez, os manipuladores de mensagens devem ser idempotentes.

Processamento de mensagens idempotente

No RFC 7231, o protocolo de transferência de hipertexto afirma, "A ... método é considerado idempotente se o efeito pretendido no servidor de várias solicitações idênticas com esse método for o mesmo que o efeito para uma única solicitação desse tipo."

Uma técnica comum de tornar o tratamento de mensagens idempotente é verificar um armazenamento persistente, como um banco de dados, se a mensagem já foi processada. Se ele tiver sido processado, você não executaria a lógica para processá-lo novamente.

  • Pode haver situações em que o processamento da mensagem inclui operações de banco de dados, especificamente a inserção de novos registros com identificadores gerados por banco de dados. Novas mensagens podem ser emitidas para o corretor, que contém esses identificadores. Como não há transações distribuídas que abrangem o banco de dados e o agente de mensagens, pode haver uma série de complicações que podem ocorrer se o processo que executa o código falhar. Veja os seguintes exemplos de situações:
    • O código que emite as mensagens pode ser executado antes que a transação do banco de dados seja confirmada, que é quantos desenvolvedores trabalham usando o padrão Unidade de Trabalho. Essas mensagens podem escapar, se a falha ocorrer entre chamar o broker e pedir que a transação do banco de dados seja confirmada. À medida que a transação é revertida, essas IDs geradas pelo banco de dados também são desfeitas, o que as deixa disponíveis para outros códigos que podem estar sendo executados ao mesmo tempo. Isso pode fazer com que os destinatários das mensagens escapadas processem as entradas erradas do banco de dados, o que prejudica a consistência geral e a correção do seu sistema.
    • Se os desenvolvedores colocarem o código que emite a mensagem após a conclusão da transação do banco de dados, o processo ainda poderá falhar entre essas operações (transação confirmada - mensagem enviada). Quando isso acontecer, a mensagem passará por processamento novamente, mas desta vez a cláusula de proteção de idempotência verá que ela já foi processada (com base nos dados armazenados no banco de dados). A cláusula ignorará o código emissor da mensagem, acreditando que tudo foi feito com sucesso da última vez. Os sistemas a jusante, que esperavam receber notificações sobre o processo concluído, não recebem nada. Esta situação conduz, mais uma vez, a um estado global de incoerência.
  • A solução para os problemas acima envolve o uso do padrão Caixa de saída transacional, onde as mensagens de saída são armazenadas ao lado, no mesmo armazenamento transacional que os dados comerciais. As mensagens são então transmitidas para o agente de mensagens, quando a mensagem inicial tiver sido processada com êxito.
  • Como muitos desenvolvedores não estão familiarizados com esses problemas ou suas soluções, a fim de garantir que essas técnicas sejam aplicadas de forma consistente em um sistema de missão crítica, sugerimos que você tenha a funcionalidade da caixa de saída e a interação com o agente de mensagens envolvidas em algum tipo de biblioteca. Todo o processamento de código e envio de mensagens transacionais significativas deve fazer uso dessa biblioteca, em vez de interagir diretamente com o agente de mensagens.

Recuperação de elevada disponibilidade e após desastre

O corretor de mensagens deve estar disponível para que os produtores enviem mensagens e os consumidores as recebam. Seguem-se pormenores sobre este requisito:

  • Para garantir a mais alta disponibilidade com o Service Bus, use a camada premium, que tem suporte para zonas de disponibilidade em regiões de suporte. Com zonas de disponibilidade, mensagens e metadados são replicados em três data centers diferentes na mesma região.
  • Use SDKs de Service Bus ou Hubs de Eventos suportados para repetir automaticamente as falhas de leitura ou gravação.
  • Considere padrões de replicação ativa-ativa ou ativa-passiva para se isolar contra desastres regionais.

Nota

A recuperação de desastres geográficos do Barramento de Serviço do Azure replica apenas metadados entre regiões. Esse recurso não replica mensagens.

Monitorização

O sistema de mensagens funciona como um buffer entre os produtores de mensagens e os consumidores. Existem tipos de indicadores-chave que você deve monitorar em um sistema de missão crítica que fornecem informações valiosas descritas abaixo:

  • Limitação - A limitação indica que o sistema não tem os recursos necessários para processar a solicitação. Tanto o Service Bus quanto os Hubs de Eventos oferecem suporte ao monitoramento de solicitações limitadas. Deve alertar para este indicador.
  • Profundidade da fila - Uma profundidade de fila crescente pode indicar que os processadores de mensagens não estão funcionando ou que não há processadores suficientes para lidar com a carga atual. A profundidade da fila pode ser usada para informar a lógica de dimensionamento automático dos manipuladores.
    • Para o Service Bus, a profundidade da fila é exposta como contagem de mensagens
    • Para Hubs de Eventos, os consumidores precisam calcular a profundidade da fila por partição e enviar a métrica para o software de monitoramento. Para cada leitura, o consumidor obtém o número de sequência do evento atual e as propriedades do evento do último evento enfileirado. O consumidor pode calcular a compensação.
  • Fila de mensagens mortas - As mensagens na fila de mensagens mortas representam mensagens que não puderam ser processadas. Essas mensagens geralmente exigem intervenção manual. Os alertas devem ser definidos na fila de mensagens mortas.
    • O Service Bus tem uma fila de mensagens mortas e uma métrica DeadLetteredMessages.
    • Para Hubs de Eventos, essa funcionalidade deve ser lógica personalizada incorporada ao consumidor.
  • Uso de CPU/Memória - CPU e memória devem ser monitoradas para garantir que o sistema de mensagens tenha recursos suficientes para processar a carga atual. Tanto o Service Bus Premium quanto o Event Hubs Premium expõem o uso da CPU e da memória.
    • As unidades de mensagens (MUs) são usadas no Service Bus para isolar recursos como CPU e memória para um namespace. CPU e memória acima de um limite podem indicar que não há MUs suficientes configuradas, enquanto ficar abaixo de outros limites pode indicar que há muitas MUs configuradas. Esses indicadores podem ser usados para dimensionar automaticamente MUs.
    • A camada premium dos Hubs de Eventos usa unidades de processamento (PUs) para isolar recursos, enquanto a camada padrão usa unidades de taxa de transferência (TUs). Essas camadas não exigem interação com CPU/Memória para inflar automaticamente PUs ou TUs.

Verificação de estado de funcionamento

A integridade do sistema de mensagens deve ser considerada nas verificações de integridade de um aplicativo de missão crítica. Considere os seguintes fatores:

  • O sistema de mensagens funciona como um buffer entre os produtores de mensagens e os consumidores. O selo pode ser visto como saudável se os produtores forem capazes de enviar mensagens com sucesso para o corretor e se os consumidores forem capazes de processar com sucesso as mensagens do corretor.
  • A verificação de integridade deve garantir que as mensagens possam ser enviadas para o sistema de mensagens.

Próximos passos

Implante a implementação de referência para obter uma compreensão completa dos recursos e sua configuração usados nessa arquitetura.