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 principais:
Characteristics | Considerações |
---|---|
Desempenho | Quanta computação é necessária? |
Latência | Que impacto terá a distância entre o usuário e o armazenamento de dados na latência? Qual é o nível desejado de consistência com a compensação de latência? |
Capacidade de resposta | É necessário que o armazenamento de dados esteja sempre disponível? |
Escalabilidade | O que é o esquema de particionamento? |
Durabilidade | Espera-se que os dados perdurem por muito tempo? 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 criptografados? O armazenamento de dados pode ser acessado pela rede pública? |
Nesta arquitetura, existem dois armazenamentos de dados:
Backup de banco de dados
Armazenamentos relacionados à carga de trabalho. É recomendável que todos os estados sejam armazenados globalmente em um banco de dados separado dos carimbos regionais. Crie redundância implantando o banco de dados entre as regiões. Para cargas de trabalho de missão crítica, a sincronização de dados entre as 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 monitoração de estado no carimbo regional é o agente de mensagens, que armazena solicitações por um curto período. O agente atende à necessidade de buffering e mensagens confiáveis. As solicitações processadas são persistentes no banco de dados global.
Para obter outras considerações sobre dados, consulte Orientação de missão crítica em Well-architected Framework: considerações sobre plataforma de dados.
Backup de banco de dados
Essa arquitetura usa o Azure Cosmos DB for NoSQL. Esta opção é escolhida porque fornece a maioria dos recursos necessários neste design:
Gravação multirregional
A gravação em várias regiões é habilitada com réplicas implantadas em todas as regiões nas quais um carimbo é implantado. Cada carimbo pode gravar 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 do aplicativo distribuídos geograficamente. A implementação de referência do Azure Mission-Critical usa a tecnologia multimestre para fornecer o máximo de 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.
Gerenciamento 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, vence 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 alto número de partições é adicionar um filtro de igualdade com o itemID identificado. Uma revisão detalhada das recomendações de otimização de consulta 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 suporta backups online e restauração de dados sob demanda.
Observação
A maioria das cargas de trabalho não é puramente OLTP. Há uma demanda cada vez maior por relatórios em tempo real, como a execução de relatórios no sistema operacional. Isso também é chamado de HTAP (Processamento Transacional e Analítico Híbrido). O Azure Cosmos DB dá suporte a esse recurso por meio do Azure Synapse Link para o Azure Cosmos DB.
Modelo de dados para a carga de trabalho
O modelo de dados deve ser projetado de forma que os recursos oferecidos pelos bancos de dados relacionais tradicionais não sejam necessários. Por exemplo, chaves estrangeiras, esquema estrito de linha/coluna, exibições e outros.
A carga de trabalho tem estas características de acesso a dados:
- Padrão de leitura:
- Leituras de ponto - Buscar um único registro. O ID do item e a chave de partição são usados diretamente para otimização máxima (1 RU por solicitação).
- Leituras de lista - Obtendo itens de catálogo para exibição em uma lista.
FeedIterator
com limite no número de resultados é usado.
- Padrão de gravação:
- 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 dimensionar para lidar com a demanda de tráfego na ordem de milhões de usuários.
- Tamanho pequeno da carga útil ou do conjunto de dados - geralmente na ordem de KB.
- Baixo tempo de resposta (em ordem de milissegundos).
- Baixa latência (em ordem de milissegundos).
Configuração
O Azure Cosmos DB está configurado da seguinte maneira:
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 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.
Observação
O nível de consistência de Sessão oferece uma compensação razoável para latência, disponibilidade e garantias de 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 com vários mestres.
A chave de partição é definida como
/id
para todas as coleções. Essa decisão é baseada no padrão de uso, que é principalmente "gravar novos documentos com GUID como 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 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. Essa política indexa apenas as propriedades usadas em predicados de consulta. Por exemplo, o aplicativo não usa o campo de texto de comentário como um filtro em consultas. Ele foi excluído da política de indexação personalizada.
Aqui está um exemplo da implementação que mostra as configurações de diretiva 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 com o Azure Cosmos DB nesta arquitetura, consulte Considerações sobre a plataforma de aplicativos 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 o acoplamento solto e atuam como um buffer que isola o sistema contra picos inesperados de demanda.
- O Barramento de Serviço do Azure é recomendado para cargas de trabalho baseadas em mensagens ao manipular 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 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. Essas informações podem ser usadas para calcular o pico de MB/segundo necessário por carimbo.
- O impacto de um failover deve ser considerado ao calcular o MB/segundo de pico necessário por carimbo.
- Para o Barramento de Serviço do Azure, as 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 Barramento de Serviço.
- A taxa de transferência do Barramento de Serviço com os recursos necessários deve ser calculada por meio de testes como MB/segundo por Unidade do Sistema de Mensagens (MU). Para saber mais sobre esse tópico, confira asCamadas do sistema de mensagens do Barramento de Serviço Premium e Standard.
- 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.
Toda mensagem deve ser processada
A camada premium do Barramento de Serviço do Azure é a solução recomendada para mensagens de alto valor para as quais o processamento deve ser garantido. A seguir estão detalhes sobre esse requisito ao usar o Barramento de Serviço do Azure premium:
Para garantir que as mensagens sejam transferidas e aceitas corretamente pelo agente, os produtores de mensagens devem usar um dos clientes de API do Barramento de Serviço com suporte. As APIs com suporte só retornarão com êxito de uma operação de envio se a mensagem tiver sido persistente na fila/tópico.
Para garantir que as mensagens no barramento sejam processadas, você deve usar o modo de recebimento PeekLock. Esse modo habilita pelo menos uma vez o processamento. O seguinte descreve o processo:
- O consumidor da mensagem 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 agente e a mensagem será removida da fila.
- Se uma confirmação não for recebida pelo agente no período de tempo alocado, ou o manipulador abandonar explicitamente a mensagem, o bloqueio exclusivo será liberado. A mensagem fica disponível para que outros consumidores processem 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 ativadas, a fila de mensagens mortas deve ser monitorada e os 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 tornados idempotentes.
Processamento de mensagens idempotentes
No RFC 7231, o Protocolo de Transferência de Hipertexto afirma: "Um 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 de uma única solicitação."
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 inclua operações de banco de dados, especificamente a inserção de novos registros com identificadores gerados pelo banco de dados. Novas mensagens podem ser emitidas para o agente, 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 as seguintes situações de exemplo:
- 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 agente e solicitar que a transação de 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 outro código que pode estar sendo executado ao mesmo tempo. Isso pode fazer com que os destinatários das mensagens escapadas processem as entradas de banco de dados erradas, 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 guarda 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 resulta novamente num estado geral 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 para o lado, no mesmo armazenamento transacional que os dados corporativos. 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 consistentemente 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 embrulhadas em algum tipo de biblioteca. Todo o processamento de código e envio de mensagens transacionalmente significativas deve fazer uso dessa biblioteca, em vez de interagir diretamente com o agente de mensagens.
- As bibliotecas que implementam essa funcionalidade no .NET incluem NServiceBus e MassTransit.
Alta disponibilidade e recuperação de desastre
O agente de mensagens deve estar disponível para que os produtores enviem mensagens e os consumidores as recebam. A seguir estão detalhes sobre esse requisito:
- Para garantir a maior disponibilidade com o Service Bus, use a camada premium, que tem suporte para zonas de disponibilidade em regiões de suporte. Com as zonas de disponibilidade, as mensagens e os metadados são replicados em três data centers diferentes na mesma região.
- Use SDKs do Barramento de Serviço ou dos Hubs de Eventos com suporte para repetir automaticamente falhas de leitura ou gravação.
- Considere padrões de replicação ativa-ativa ou ativa-passiva para se isolar contra desastres regionais.
Observação
A recuperação de desastres geográficos do Barramento de Serviço do Azure replica metadados apenas entre regiões. Esse recurso não replica mensagens.
Monitoramento
O sistema de mensagens atua como um buffer entre produtores de mensagens e 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 Barramento de Serviço quanto os Hubs de Eventos oferecem suporte ao monitoramento de solicitações limitadas. Você deve alertar sobre este indicador.
- Profundidade da fila - Uma profundidade de fila que está aumentando pode indicar que os processadores de mensagens não estão funcionando ou 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 Barramento de Serviço, 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 requerem intervenção manual. Os alertas devem ser definidos na fila de mensagens mortas.
- O Barramento de Serviço 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 - A CPU e a memória devem ser monitoradas para garantir que o sistema de mensagens tenha recursos suficientes para processar a carga atual. Tanto o Barramento de Serviço premium quanto o Hubs de Eventos premium expõem o uso da CPU e da memória.
- As unidades do sistema de mensagens (MUs) são usadas no Barramento de Serviços para isolar recursos como CPU e memória de um namespace. CPU e memória subindo acima de um limite pode indicar que não há MUs suficientes configurados, enquanto cair abaixo de outros limites pode indicar que há muitos MUs configurados. Esses indicadores podem ser usados para dimensionar automaticamente as MUs.
- A camada premium dos Hubs de Eventos usa unidades de processamento (PUs) para isolar recursos, enquanto a camada standard usa unidades de produtividade (TUs). Essas camadas não exigem interação com CPU/Memória para inflar automaticamente PUs ou TUs.
Verificação de integridade
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 atua como um buffer entre produtores de mensagens e consumidores. O carimbo pode ser visto como íntegro se os produtores forem capazes de enviar mensagens com sucesso para o agente e se os consumidores forem capazes de processar com sucesso as mensagens do agente.
- A verificação de integridade deve garantir que as mensagens possam ser enviadas para o sistema de mensagens.
Próximas etapas
Implante a implementação de referência para obter uma compreensão completa dos recursos e sua configuração usados nessa arquitetura.