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.
Divida um armazenamento de dados em um conjunto de partições horizontais ou fragmentos. Essa abordagem pode melhorar a escalabilidade quando você armazena e acessa grandes volumes de dados.
Contexto e problema
Um armazenamento de dados em um único servidor tem as seguintes limitações:
Espaço de armazenamento: Um armazenamento de dados para um aplicativo de nuvem em grande escala pode conter um grande volume de dados que cresce ao longo do tempo. Um servidor fornece uma quantidade finita de armazenamento em disco e você pode substituir discos existentes por discos maiores ou adicionar mais discos à medida que os volumes de dados aumentam. O sistema eventualmente atinge um limite em que você não pode aumentar a capacidade de armazenamento em um único servidor.
Recursos de computação: Um aplicativo de nuvem deve dar suporte a um grande número de usuários simultâneos que executam consultas no armazenamento de dados. Um único servidor pode não fornecer poder de computação suficiente para essa carga, o que resulta em tempos de resposta estendidos e tempos limite. Você pode adicionar processadores de memória ou atualização, mas o sistema atinge um limite em que você não pode aumentar ainda mais os recursos de computação.
Largura de banda de rede: A taxa na qual um único servidor pode receber solicitações e enviar respostas limita o desempenho do armazenamento de dados. O volume de tráfego de rede pode exceder a capacidade da conexão de rede, o que resulta em solicitações com falha.
Geografia: Requisitos legais, de conformidade ou de desempenho podem exigir que você armazene dados do usuário na mesma região geográfica que os usuários. Se os usuários se estenderem por países/regiões, talvez você não consiga armazenar todos os dados do aplicativo em um único armazenamento de dados.
Para adiar essas limitações temporariamente, você pode dimensionar verticalmente adicionando capacidade de disco, capacidade de processamento, memória e conexões de rede. Um aplicativo de nuvem que deve dar suporte a um grande número de usuários e grandes volumes de dados precisa ser dimensionado horizontalmente.
Solução
Divida o repositório de dados em partições horizontais ou fragmentos. Cada fragmento tem o mesmo esquema, mas contém seu próprio subconjunto distinto dos dados. Cada fragmento é um armazenamento de dados completo que pode conter dados para muitas entidades de diferentes tipos. Uma partição opera em um servidor que funciona como um nó de armazenamento.
Esse padrão tem os seguintes benefícios:
Você pode escalar horizontalmente o sistema adicionando mais fragmentos em nós de armazenamento extras.
Um sistema pode usar hardware pré-construído em vez de computadores especializados e caros para cada nó de armazenamento.
Você pode reduzir a contenção e melhorar o desempenho equilibrando a carga de trabalho entre fragmentos.
Na nuvem, os fragmentos podem residir fisicamente perto dos usuários que acessam os dados.
Quando você divide um armazenamento de dados em fragmentos, decida quais dados colocar em cada fragmento. Cada fragmento normalmente contém itens agrupados por um ou mais atributos de dados. Esses atributos formam a chave de fragmento, às vezes chamada de chave de partição.
A fragmentação física organiza os dados. Quando um aplicativo armazena e recupera dados, a lógica de fragmentação direciona-os para o fragmento apropriado. Você pode implementar essa lógica no código de acesso a dados do aplicativo ou no sistema de armazenamento de dados se ele der suporte transparente à fragmentação.
A abstração do local físico dos dados na lógica de fragmentação fornece controle sobre quais fragmentos contêm quais dados. Você também pode migrar dados entre fragmentos sem modificar a lógica de negócios do aplicativo quando precisar redistribuir dados, como quando os fragmentos ficam desequilibrados. A compensação é a sobrecarga extra de acesso a dados para determinar a localização de cada item de dados durante a recuperação.
Seleção de chave de fragmento
A chave de fragmento é a decisão de design mais crítica em um sistema fragmentado. Para alterar uma chave de fragmento depois de escolhê-la, você normalmente deve migrar todos os dados para um novo layout de fragmento, que é uma operação cara e arriscada em um sistema em uso. Tome essa decisão com cuidado antes de escrever qualquer código.
Uma chave de fragmento eficaz é imutável, tem alta cardinalidade, distribui dados e carrega uniformemente e se alinha aos padrões de consulta dominantes para que a maioria das solicitações seja resolvida em relação a um único fragmento. Evite aumentar valores monotonicamente (números inteiros de preenchimento automático e carimbos de data/hora sequenciais), atributos de baixa cardinalidade (boolianos e pequenos conjuntos de enumerações) e atributos voláteis que mudam com frequência. Esses atributos levam a hotspots ou movimentação dispendiosa de dados entre fragmentos.
Se nenhum atributo atender a esses critérios, defina uma chave de fragmento composta combinando dois ou mais atributos. Se as consultas precisarem recuperar dados por atributos que não fazem parte da chave de fragmento, use um padrão como o padrão tabela de índice para fornecer pesquisas secundárias.
Para obter mais informações sobre como escolher chaves de partição nos serviços do Azure, consulte as diretrizes de particionamento de dados e estratégias de particionamento de dados.
Estratégias de fragmentação
Use uma das estratégias a seguir ao selecionar a chave de fragmento e decidir como distribuir dados entre fragmentos. Você não precisa de uma correspondência um-para-um entre fragmentos e os servidores que os hospedam. Um único servidor pode hospedar vários fragmentos.
Estratégia de fragmentação de consulta
Na estratégia de pesquisa, também chamada de estratégia baseada em diretório, a lógica de fragmentação implementa um mapa que roteia uma solicitação de dados para o fragmento que contém esses dados usando a chave de fragmento. Em um aplicativo multilocatário, você pode armazenar todos os dados de um locatário juntos em um fragmento usando a ID do locatário como a chave de fragmento. Vários locatários podem compartilhar o mesmo fragmento, mas os dados de um único locatário não se espalham por vários fragmentos. O diagrama a seguir mostra a fragmentação de dados de inquilinos com base em IDs de inquilino.
O mapeamento entre valores de chave de fragmento e armazenamento físico pode ser direto, em que cada valor de chave de fragmento é mapeado para uma partição física. Uma técnica mais flexível é o particionamento virtual, onde valores de chave de fragmento são mapeados para fragmentos virtuais, e então o sistema mapeia esses fragmentos virtuais para um número menor de partições físicas. Um aplicativo localiza dados usando um valor de chave de fragmento que se refere a um fragmento virtual e o sistema mapeia transparentemente fragmentos virtuais para partições físicas. O mapeamento entre um fragmento virtual e uma partição física pode ser alterado sem a necessidade de modificações de código do aplicativo.
Estratégia de particionamento baseada em intervalo
A estratégia baseada em faixas agrupa itens relacionados no mesmo fragmento e os ordena por chave sequencial do fragmento. Essa estratégia dá suporte a aplicativos que recuperam frequentemente conjuntos de itens usando consultas de intervalo. As consultas de intervalo retornam um conjunto de itens de dados para uma chave de fragmento que se enquadra em um determinado intervalo.
Por exemplo, se um aplicativo precisar encontrar regularmente todos os pedidos feitos em um determinado mês, você poderá recuperar os dados mais rapidamente se armazenar todos os pedidos por um mês na ordem de data e hora no mesmo fragmento. Se você armazenar cada pedido em um fragmento diferente, o aplicativo precisará buscá-los individualmente executando um grande número de consultas pontuais. O diagrama a seguir mostra conjuntos sequenciais, ou intervalos, de dados armazenados em fragmentos.
Neste exemplo, a chave de partição é uma chave composta que contém o mês do pedido como o elemento mais significativo, seguido pelo dia e hora do pedido. Os novos pedidos são naturalmente classificados à medida que são criados e adicionados a um fragmento.
Alguns armazenamentos de dados dão suporte a chaves shard de duas partes. Uma chave de partição identifica o fragmento e uma chave de linha identifica exclusivamente um item dentro do fragmento. O fragmento normalmente armazena dados em ordem de chave de linha. Para itens que precisam de consultas de intervalo e devem ser agrupados, você pode usar uma chave de fragmento que tenha o mesmo valor para a chave de partição, mas um valor exclusivo para a chave de linha.
Estratégia de fragmentação baseada em hash
A estratégia baseada em hash reduz a chance de hotspots, que são fragmentos que recebem uma quantidade desproporcional de carga. Essa estratégia distribui dados entre fragmentos para equilibrar o tamanho de cada fragmento e a carga média que cada fragmento encontra. A lógica de fragmentação calcula o fragmento para armazenar um item com base em um hash de um ou mais atributos dos dados. A função de hash escolhida deve distribuir dados uniformemente entre os fragmentos. O diagrama a seguir mostra a fragmentação de dados do locatário com base em um hash de IDs de locatários.
Para entender a vantagem da estratégia de hash em relação a outras estratégias de fragmentação, considere como um aplicativo multilocatário que registra novos locatários sequencialmente pode atribuir os locatários a fragmentos no armazenamento de dados. Quando você utiliza a estratégia de intervalo, os dados dos inquilinos de 1 a n são armazenados no fragmento A, os dados dos inquilinos de n+1 a m são armazenados no fragmento B, e os intervalos de inquilinos subsequentes são mapeados para fragmentos sucessivos. Se os locatários registrados mais recentemente também forem os mais ativos, a maior parte da atividade de dados ocorrerá em alguns fragmentos, o que pode causar hotspots. Por outro lado, a estratégia de hash aloca usuários para fragmentos com base no hash do ID do usuário. O hash geralmente distribui locatários sequenciais entre diferentes fragmentos, o que equilibra a carga. O diagrama anterior mostra essa abordagem para locatários 55 e 56.
Estratégia de fragmentação geográfica
A estratégia geográfica atribui dados a fragmentos com base na origem geográfica ou na região de consumo pretendida desses dados. Em muitas cargas de trabalho, os usuários e os dados gerados estão concentrados em regiões específicas. Os requisitos regulatórios, como as leis de residência de dados, podem exigir que os dados específicos permaneçam dentro de uma jurisdição específica. Mesmo sem drivers regulatórios, colocar dados próximos aos usuários que os acessam com mais frequência reduz a latência de rede para leituras e gravações.
Nessa estratégia, você deriva a chave de fragmento de um atributo geográfico, como o país/região do usuário, a região do datacenter de origem ou um identificador de locatário regional. Você hospeda ou fixa cada fragmento à infraestrutura dentro desse limite geográfico.
Por exemplo, um aplicativo que atende clientes na América do Norte, Europa e Asia-Pacific pode manter três grupos de fragmentos, um grupo em cada região correspondente do Azure. Um aplicativo europeu que atende somente usuários europeus roteia uma solicitação para o fragmento da Europa. Essa abordagem reduz a latência e atende aos requisitos de residência de dados.
A fragmentação geográfica apresenta o risco de distribuição de dados irregulares. Se a maioria dos usuários residir em uma região, o fragmento dessa região carregará uma parte desproporcional da carga e do armazenamento. Você pode combinar a fragmentação geográfica com outra estratégia, como hash ou pesquisa, em cada região para distribuir a carga uniformemente entre vários fragmentos dentro do mesmo limite geográfico.
Vantagens e considerações para cada estratégia
As quatro estratégias de fragmentação têm as seguintes vantagens e considerações:
A estratégia de consulta fornece mais controle sobre a configuração de shards. Os fragmentos virtuais reduzem o impacto do rebalanceamento porque você pode adicionar novas partições físicas para equilibrar a carga de trabalho. Você pode modificar o mapeamento entre um fragmento virtual e suas partições físicas sem afetar o código do aplicativo. Procurar a localização dos fragmentos gera sobrecarga.
A estratégia de intervalo é fácil de implementar e funciona bem com consultas de intervalo. As consultas de intervalo podem recuperar vários itens de dados do mesmo fragmento em uma única operação. O gerenciamento de dados é mais simples. Por exemplo, você pode agendar atualizações por fuso horário com base em padrões de carga locais quando os usuários na mesma região compartilham um fragmento. No entanto, essa estratégia não equilibra a carga uniformemente entre fragmentos. O rebalanceamento é difícil e pode não resolver a carga desigual quando a maioria das atividades se concentra em chaves de repartição adjacentes.
A estratégia de hash oferece uma chance melhor de uma distribuição uniforme de dados e carga. Você pode rotear solicitações diretamente usando a função de hash sem manter um mapa. Calcular o hash adiciona alguma sobrecarga. O rebalanceamento é difícil sem hash consistente.
A estratégia geográfica atende aos requisitos de residência e soberania de dados que outras estratégias não abordam inerentemente. Ele reduz a latência de leitura e gravação quando os usuários acessam dados em sua região. No entanto, a fragmentação geográfica pode criar dados significativos e desequilíbrio de carga quando as populações de usuários não são distribuídas uniformemente entre regiões. Consultas que abrangem regiões, como relatórios globais, devem recuperar dados de todos os fragmentos geográficos e incorrer em maior latência. Combine a fragmentação geográfica com outra estratégia em cada região quando você precisar de conformidade e até mesmo distribuição de carga.
A maioria dos sistemas de fragmentação implementa uma dessas abordagens, mas você também deve considerar os requisitos de negócios do aplicativo e seus padrões de uso de dados. Por exemplo, em um aplicativo multilocatário:
Você pode fragmentar dados com base na carga de trabalho. Segregar dados para locatários altamente voláteis em fragmentos separados para melhorar a velocidade de acesso a dados para outros locatários.
Você pode fragmentar dados com base no local do locatário. Para o backup e manutenção, mantenha os dados do locatário em uma região geográfica específica offline durante os horários fora de pico dessa região, enquanto os dados do locatário em outras regiões permanecem online durante o horário comercial.
Atribua aos clientes de alto valor seus próprios fragmentos dedicados e levemente carregados. Locatários de menor valor podem compartilhar fragmentos mais densamente empacotados.
Armazene dados para locatários que precisam de isolamento e privacidade de dados fortes em servidores separados.
Operações de dimensionamento e movimentação de dados para cada estratégia
Cada estratégia de fragmentação fornece diferentes funcionalidades e níveis de complexidade para gerenciar a escala interna, a escala externa, a movimentação de dados e a manutenção do estado.
A estratégia de pesquisa permite operações de dimensionamento e movimentação de dados no nível do usuário, online ou offline. Para mover dados:
Suspenda algumas ou todas as atividades do usuário, normalmente durante períodos fora do pico.
Mova os dados para a nova partição virtual ou fragmento físico.
Atualize os mapeamentos.
Invalide ou atualize os caches que contêm esses dados.
Retomar a atividade do usuário.
Geralmente, você pode gerenciar essa operação centralmente. A estratégia de pesquisa requer que o estado seja altamente armazenável em cache e compatível com réplicas.
A estratégia de intervalo limita operações de dimensionamento e movimentação de dados porque você deve dividir e mesclar dados entre fragmentos, normalmente, enquanto parte ou todo o armazenamento de dados está offline. Ao mover dados para rebalancear fragmentos, talvez você não elimine a carga irregular se a maioria das atividades se concentrar em chaves de fragmento adjacentes ou identificadores de dados dentro do mesmo intervalo. A estratégia de intervalo também pode exigir estado para mapear intervalos para partições físicas.
A estratégia de hash complica operações de dimensionamento e movimentação de dados. As chaves de partição são hashes das chaves de fragmento ou identificadores de dados. Com uma função de hash padrão, como
hash(key) mod Nadicionar ou remover um fragmento reatribui a maioria das chaves e dispara a migração de dados em grande escala. O hash consistente reduz esse impacto organizando o espaço de hash para que apenas uma pequena fração de chaves se mova quando a contagem de fragmentos for alterada. A estratégia de hash não requer a manutenção de um estado de mapeamento separado.A estratégia geográfica vincula diretamente operações de dimensionamento ao provisionamento de infraestrutura regional. Adicionar capacidade em uma região não alivia a carga em outra região. Os requisitos regulatórios que obrigam a fragmentação geográfica também podem restringir a movimentação de dados entre limites geográficos. Em cada região, o dimensionamento usa a estratégia secundária que distribui dados entre os fragmentos dessa região.
Problemas e considerações
Considere os seguintes pontos ao decidir como implementar esse padrão:
Use "sharding" de forma complementar a outras formas de particionamento, como particionamento vertical e particionamento funcional. Por exemplo, um único fragmento pode conter entidades particionadas verticalmente e você pode implementar uma partição funcional como vários fragmentos. Para obter mais informações, consulte o particionamento de dados horizontal, vertical e funcional.
Mantenha os fragmentos equilibrados para que todos eles possam lidar com um volume de E/S (entrada/saída) semelhante. A distorção de dados se acumula ao longo do tempo quando os registros são inseridos e excluídos, o que leva a pontos críticos. Planeje reequilibrar periodicamente.
O rebalanceamento move dados entre fragmentos e geralmente causa tempo de inatividade ou taxa de transferência reduzida. Para reequilibrar com menos frequência, use partições virtuais. Mapeie muitas partições lógicas para menos fragmentos físicos. Quando um fragmento está sobrecarregado, redistribua suas partições virtuais para novos fragmentos físicos sem refazer o hash de todo o dataset. O Azure Cosmos DB usa essa abordagem para desacoplar o esquema de partição da infraestrutura física.
Prefira muitos fragmentos pequenos em vez de alguns grandes. Fragmentos menores migram mais rapidamente, equilibram a carga mais uniformemente e fornecem mais flexibilidade para redistribuição de dados.
Utilize dados estáveis como chave de fragmentação. Se a chave de fragmento for alterada, talvez seja necessário mover o item de dados correspondente entre fragmentos, o que aumenta a sobrecarga da operação de atualização. Evite basear a chave de partição em informações potencialmente voláteis. Escolha atributos que são invariáveis ou naturalmente formam uma chave.
Certifique-se de que as chaves de partição sejam únicas. Por exemplo, evite usar campos de incremento automático como chave de fragmentação. Em alguns sistemas, campos autoincrementados não podem ser coordenados entre fragmentos, o que pode resultar em itens em fragmentos diferentes com a mesma chave de fragmento.
Observação
Valores autoincrementados em outros campos que não são chaves de fragmento também podem causar problemas. Por exemplo, se você usar campos autoincrementados para gerar IDs exclusivas, dois itens diferentes em fragmentos diferentes poderão receber a mesma ID.
Fragmente os dados para dar suporte às consultas executadas com mais frequência. Talvez você não consiga criar uma chave de fragmento que corresponda aos requisitos de cada consulta em relação aos dados. Se necessário, crie tabelas de índice secundárias para dar suporte a consultas que recuperam dados por atributos que não fazem parte da chave de fragmento. Para obter mais informações, consulte padrão de tabela de índice.
Projete sua chave de fragmento e o modelo de dados para manter a maioria das operações no escopo de um único fragmento. As consultas que acessam apenas um único fragmento são mais eficientes do que as consultas que recuperam dados de vários fragmentos. Desnormalize seus dados para manter entidades relacionadas que geralmente são consultadas juntas, como clientes e seus pedidos, no mesmo fragmento para reduzir o número de leituras separadas.
Consultas entre fragmentos adicionam latência, consumo de recursos e complexidade. Quando um aplicativo precisa recuperar dados de vários fragmentos, use consultas paralelas "fan-out" executadas simultaneamente em cada fragmento para agregar os resultados. Mesmo com o paralelismo, o fragmento mais lento determina a latência geral.
Gorjeta
Se uma entidade em um fragmento fizer referência a uma entidade em outro fragmento, inclua a chave de fragmento para a segunda entidade como parte do esquema da primeira entidade. Essa abordagem pode melhorar o desempenho de consultas que fazem referência a dados relacionados entre fragmentos.
Reconsidere sua chave de partição ou se a fragmentação atende às suas necessidades caso sua carga de trabalho exija uma forte integridade transacional através dos limites de partições. Transações entre fragmentos apresentam desafios. Protocolos de coordenação distribuída, como confirmação em duas fases, adicionam latência, introduzem modos de falha e reduzem a taxa de transferência. A maioria dos sistemas fragmentados evita transações distribuídas e adota a consistência eventual. Nesse modelo, cada fragmento é atualizado de forma independente e o aplicativo lida com inconsistências temporárias.
Verifique se os recursos disponíveis para cada nó de armazenamento de fragmentos podem lidar com os requisitos de escalabilidade em termos de tamanho e taxa de transferência de dados. Para obter mais informações, consulte Estratégias de particionamento de dados.
Considere a possibilidade de replicar dados de referência para todos os fragmentos. Se uma consulta em um fragmento também fizer referência a dados estáticos ou lentos, adicione esses dados ao fragmento. Em seguida, o aplicativo pode buscar todos os dados para a consulta sem fazer uma viagem de ida e volta para um armazenamento de dados separado.
Observação
Se os dados de referência mantidos em vários fragmentos forem alterados, o sistema deverá sincronizar essas alterações em todos os fragmentos. Algum grau de inconsistência pode ocorrer enquanto essa sincronização é executada. Crie seus aplicativos para tolerar essa inconsistência.
Sistemas fragmentados multiplicam a carga operacional. Planeje estas preocupações:
Monitoramento: Você deve agregar métricas e logs em todos os fragmentos para obter uma visão completa da integridade do sistema.
Backup e restauração: Você deve fazer backup de cada fragmento de forma independente e projetar procedimentos de restauração para manter a consistência entre fragmentos. Uma restauração pontual de um fragmento pode criar inconsistências com outros fragmentos.
Alterações de esquema: Você deve coordenar as alterações de DDL (Linguagem de Definição de Dados) em cada fragmento.
Você pode implementar essas tarefas usando scripts ou outras soluções de automação.
Você pode geolocar fragmentos para colocar seus dados perto das instâncias de aplicativo que o usam. Essa abordagem pode melhorar o desempenho, mas requer um planejamento extra para operações que devem acessar vários fragmentos em locais diferentes.
Quando usar esse padrão
Gorjeta
Antes de criar uma camada de fragmentação personalizada, determine quais responsabilidades de fragmentação sua plataforma de dados já manipula. Alguns serviços gerenciam completamente a fragmentação. Por exemplo, o Azure Cosmos DB distribui dados entre partições físicas, manipula divisões e roteia consultas sem envolvimento do aplicativo. Outros serviços gerenciam a fragmentação parcialmente. Por exemplo, o Banco de Dados SQL do Azure fornece ferramentas de banco de dados elástico para gerenciamento de mapa de fragmentos e roteamento dependente de dados, mas você projeta a chave de fragmento e gerencia operações de divisão. Use o padrão de fragmentação ao criar e operar a lógica de fragmentação você mesmo.
Use esse padrão quando:
O volume total de dados excede a capacidade de armazenamento de uma única instância de banco de dados e nenhuma opção de dimensionamento vertical resolve o déficit.
A taxa de transferência de transação ou simultaneidade de consulta excede o que uma única instância pode sustentar e as réplicas de leitura por si só não resolvem o gargalo porque a carga de gravação também é alta.
Observação
A fragmentação melhora o desempenho e a escalabilidade de um sistema e também pode melhorar a disponibilidade. Uma falha em uma partição não necessariamente impede que um aplicativo acesse dados em outras partições. E um operador pode executar a manutenção ou recuperação de uma partição sem tornar todos os dados indisponíveis. Para obter mais informações, consulte As diretrizes de particionamento de dados.
Os requisitos regulatórios ou de conformidade determinam que subconjuntos de dados específicos residem em jurisdições geográficas específicas e nenhuma implantação de região única pode atender a todos os requisitos.
Locatários distintos ou segmentos de clientes exigem isolamento de dados físicos por motivos de segurança, desempenho ou contratual.
Em cenários como esses, o padrão de fragmentação às vezes é aplicado além dos armazenamentos de dados tradicionais. Por exemplo, um sistema de gerenciamento de zona DNS pode ser fragmentado por equipe, ambiente ou região para reduzir o raio de explosão de alterações de DNS e estabelecer limites de propriedade claros. Nesse contexto, a principal motivação é a segmentação operacional em vez da escalabilidade. Para obter mais informações, consulte Particionamento de zonas DNS privadas.
A fragmentação introduz complexidade substancial e permanente em sua arquitetura de dados. Essa complexidade afeta o desenvolvimento, operações, testes, design de consulta e recuperação de falhas para o tempo de vida do sistema.
O padrão pode não ser adequado nestes casos:
O volume de dados e a taxa de transferência se encaixam em uma única instância de banco de dados, mesmo com o crescimento projetado. O dimensionamento vertical preserva a simplicidade da consulta e a integridade transacional.
O gargalo é o volume de leitura, não a capacidade de armazenamento ou volume de gravação. Réplicas de leitura e camadas de cache podem aliviar o tráfego de leitura sem a complexidade das consultas entre fragmentos que a fragmentação apresenta.
O mecanismo de banco de dados dá suporte ao particionamento em nível de tabela que atende às suas necessidades de desempenho. O particionamento em uma única instância não requer vários servidores ou lógica de roteamento.
Seus padrões de consulta dominantes exigem junções entre entidades, transações de várias entidades ou agregações de conjunto de dados completos. A fragmentação torna essas operações caras, e a sobrecarga de consultas de disseminação e coordenação distribuída pode superar os benefícios de escalabilidade.
Design de carga de trabalho
Avalie como usar o padrão sharding no design de uma carga de trabalho para abordar as metas e os princípios abordados nos pilares do Azure Well-Architected Framework. A tabela a seguir fornece diretrizes sobre como esse padrão dá suporte às metas de cada pilar.
| Pilar | Como esse padrão apoia os objetivos do pilar |
|---|---|
| As decisões de design de confiabilidade ajudam sua carga de trabalho a se tornar resiliente ao mau funcionamento e garantir que ela se recupere para um estado totalmente funcional após a ocorrência de uma falha. | Os dados e o processamento são isolados no fragmento, portanto, um defeito em um fragmento permanece isolado nesse fragmento. - Particionamento de dados - RE:07 Autopreservação |
| A Otimização de Custos concentra-se na manutenção e na melhoria do retorno sobre o investimento da carga de trabalho. | Um sistema que implementa fragmentos geralmente se beneficia do uso de várias instâncias de recursos de computação ou armazenamento mais baratos, em vez de um único recurso mais caro. Em muitos casos, essa configuração pode economizar dinheiro. - CO:07 Custos de componentes |
| A Eficiência de Desempenho ajuda sua carga de trabalho a atender com eficiência às demandas por meio de otimizações no dimensionamento, nos dados e no código. | Quando você usa a fragmentação em sua estratégia de dimensionamento, os dados e o processamento são isolados para cada fragmento, portanto, as solicitações só competem por recursos dentro do fragmento atribuído. Você também pode usar a fragmentação para otimizar com base na geografia. - PE:05 Dimensionamento e particionamento - PE:08 Performance de Dados |
Se esse padrão introduzir compensações dentro de um pilar, considere-as em relação aos objetivos dos outros pilares.
Exemplo
Considere um site que apresenta uma coleção expansiva de informações sobre livros publicados em todo o mundo. O número de livros possíveis catalogados nessa carga de trabalho e os padrões típicos de consulta e uso excedem o que um banco de dados relacional pode manipular. O arquiteto de sistemas decide fragmentar os dados em várias instâncias de banco de dados usando o ISBN estático dos livros como a chave de partição. Especificamente, o arquiteto usa o dígito de verificação (0 a 10) do ISBN, que fornece 11 fragmentos lógicos possíveis com distribuição de dados bastante equilibrada.
Para começar, o arquiteto coloca os 11 fragmentos lógicos em três bancos de dados de fragmentos físicos. Nessa abordagem de partição virtual, muitas partições lógicas são mapeadas para menos nós físicos. O arquiteto usa a abordagem de lookup para particionamento e armazena o mapeamento de chaves para servidores em um banco de dados de mapa de fragmentos.
O Serviço de Aplicativos do Azure é etiquetado como "Site de Catálogo de Livros". Ele se conecta a várias instâncias do Banco de Dados SQL e a uma instância do Azure AI Search. Um dos bancos de dados é rotulado como o banco de dados ShardMap. Ele inclui uma tabela de exemplo que espelha uma parte da tabela de mapeamento, que é listada posteriormente neste artigo. A tabela inclui três instâncias de bancos de dados fragmentados: bookdbshard0, bookdbshard1 e bookdbshard2. Os outros bancos de dados incluem listagens de exemplo idênticas de tabelas sob eles. As tabelas incluem Livros, LibraryOfCongressCatalog e um indicador de mais tabelas disponíveis. A Pesquisa de IA é usada para navegação facetada e pesquisa de site. A identidade gerenciada está associada ao Serviço de Aplicativo.
Mapa de fragmentos de pesquisa
O banco de dados de mapas de fragmentos contém a tabela e os dados de mapeamento de fragmentos a seguir.
SELECT ShardKey, DatabaseServer
FROM BookDataShardMap
| ShardKey | DatabaseServer |
|----------|----------------|
| 0 | bookdbshard0 |
| 1 | bookdbshard0 |
| 2 | bookdbshard0 |
| 3 | bookdbshard1 |
| 4 | bookdbshard1 |
| 5 | bookdbshard1 |
| 6 | bookdbshard2 |
| 7 | bookdbshard2 |
| 8 | bookdbshard2 |
| 9 | bookdbshard0 |
| 10 | bookdbshard1 |
Código do site de exemplo: acesso a único fragmento
O site não está ciente de quantos bancos de dados de fragmentos físicos existem (três nesse caso) ou a lógica que mapeia uma chave de fragmento para uma instância de banco de dados. Ele só sabe que o dígito de verificação do ISBN de um livro é a chave de fragmento. O site tem acesso somente leitura ao banco de dados de mapas de fragmentos e acesso de leitura-gravação a todos os bancos de dados de fragmentos. Neste exemplo, o site usa a identidade gerenciada pelo sistema de seu host do Serviço de Aplicativo do Azure para autorização, o que mantém os segredos fora das cadeias de conexão.
O website é configurado com as seguintes cadeias de conexão, seja em um arquivo appsettings.json, conforme mostrado neste exemplo, ou por meio de configurações do aplicativo no Serviço de Aplicativo.
{
...
"ConnectionStrings": {
"ShardMapDb": "Data Source=tcp:<database-server-name>.database.windows.net,1433;Initial Catalog=ShardMap;Authentication=Active Directory Default;App=Book Site v1.5a",
"BookDbFragment": "Data Source=tcp:SHARD.database.windows.net,1433;Initial Catalog=Books;Authentication=Active Directory Default;App=Book Site v1.5a"
},
...
}
O código a seguir mostra como o site executa uma consulta de atualização no pool de fragmentos de banco de dados da carga de trabalho.
...
// All data for this book is stored in a shard based on the book's ISBN check digit,
// which is converted to an integer 0 - 10 (special value 'X' becomes 10).
int isbnCheckDigit = book.Isbn.CheckDigitAsInt;
// Establish a pooled connection to the database shard for this specific book.
using (SqlConnection sqlConn = await shardedDatabaseConnections.OpenShardConnectionForKeyAsync(key: isbnCheckDigit, cancellationToken))
{
// Update the book's Library of Congress catalog information.
SqlCommand cmd = sqlConn.CreateCommand();
cmd.CommandText = @"UPDATE LibraryOfCongressCatalog
SET ControlNumber = @lccn,
...
Classification = @lcc
WHERE BookID = @bookId";
cmd.Parameters.AddWithValue("@lccn", book.LibraryOfCongress.Lccn);
...
cmd.Parameters.AddWithValue("@lcc", book.LibraryOfCongress.Lcc);
cmd.Parameters.AddWithValue("@bookId", book.Id);
await cmd.ExecuteNonQueryAsync(cancellationToken);
}
...
No código de exemplo anterior, se book.Isbn fosse 978-8-1130-1024-6, então isbnCheckDigit deveria ser 6. A OpenShardConnectionForKeyAsync(6) chamada normalmente é implementada usando uma abordagem de cache-aside. Se as informações de fragmento armazenadas em cache para a chave do fragmento 6 não estiverem disponíveis, o método consultará o banco de dados do mapa de fragmentos identificado pela ShardMapDb cadeia de conexão. O método recupera o valor bookdbshard2 de cache do aplicativo ou do banco de dados shard e o substitui por SHARD na cadeia de conexão BookDbFragment. Em seguida, o método estabelece ou restabelece uma conexão em pool com bookdbshard2.database.windows.net, abre-a e retorna-a ao código de chamada. Em seguida, o código atualiza o registro existente nessa instância de banco de dados.
Código do site de exemplo: acesso a vários fragmentos
No caso raro, quando o site requer uma consulta direta entre fragmentos, o aplicativo executa uma consulta de fan-out paralela em todos os fragmentos.
...
// Retrieve all shard keys.
var shardKeys = shardedDatabaseConnections.GetAllShardKeys();
// Run the query in a fan-out style against each shard in the shard list.
Parallel.ForEachAsync(shardKeys, async (shardKey, cancellationToken) =>
{
using (SqlConnection sqlConn = await shardedDatabaseConnections.OpenShardConnectionForKeyAsync(key: shardKey, cancellationToken))
{
SqlCommand cmd = sqlConn.CreateCommand();
cmd.CommandText = @"SELECT ...
FROM ...
WHERE ...";
SqlDataReader reader = await cmd.ExecuteReaderAsync(cancellationToken);
while (await reader.ReadAsync(cancellationToken))
{
// Collect the results into a thread-safe data structure.
}
reader.Close();
}
});
...
Como alternativa às consultas entre fragmentos, essa carga de trabalho pode usar um índice mantido externamente no Azure AI Search para pesquisa de site ou navegação facetada.
Adicionar instâncias de fragmentação
A equipe de carga de trabalho sabe que, se o catálogo de dados ou seu uso simultâneo aumentar significativamente, eles poderão exigir mais de três instâncias de banco de dados. A equipe de gerenciamento de carga de trabalho não espera adicionar servidores de banco de dados dinamicamente e aceita o tempo de inatividade do workload quando um novo fragmento entra online. Para colocar uma nova instância de fragmento online, eles devem mover dados de fragmentos existentes para o novo fragmento e atualizar a tabela de mapa de fragmentos. Com essa abordagem bastante estática, o workload pode armazenar em cache com confiança o mapeamento de banco de dados de chave de shard no código do site.
A lógica da chave de fragmento neste exemplo tem um limite superior de 11 fragmentos físicos. Se a equipe de carga de trabalho determinar por meio da estimativa de carga que eles no futuro exigirão mais de 11 instâncias de banco de dados, eles devem fazer uma alteração invasiva na lógica da shard key. Essa alteração envolve um planejamento cuidadoso de modificações de código e migração de dados para a nova lógica de chave.
Funcionalidade do SDK
Em vez de escrever código personalizado para gerenciamento de fragmentos e roteamento de consulta para instâncias do Banco de Dados SQL, avalie a biblioteca de clientes do banco de dados elástico. Essa biblioteca oferece suporte ao gerenciamento de mapas de fragmentos, roteamento de consultas dependentes de dados e consultas entre fragmentos em C# e Java.
Próxima etapa
- Níveis de consistência no Azure Cosmos DB: a distribuição de dados entre fragmentos introduz compensações de consistência. Este artigo descreve o espectro de modelos de consistência, de forte a eventual, e seus efeitos sobre disponibilidade e latência.
Recursos relacionados
- Particionamento de dados horizontal, vertical e funcional: este artigo descreve outras estratégias para particionar dados na nuvem para melhorar a escalabilidade, reduzir a contenção e otimizar o desempenho.
- Padrão de tabela de índice: às vezes, você não pode suportar todas as consultas apenas pelo design da chave de fragmento. Um aplicativo pode usar o Padrão Tabela de Índice para recuperar dados de um armazenamento de dados grande especificando uma chave diferente da chave de partição.
- Padrão de exibição materializada: para manter o desempenho de algumas operações de consulta, você pode criar exibições materializadas que agregam e resumem dados, especialmente se você distribuir esses dados entre fragmentos.