Conceber uma estratégia de criação de partições dimensionável para o armazenamento de Tabelas do Azure
Este artigo aborda a criação de partições de uma tabela no armazenamento de Tabelas do Azure e as estratégias que pode utilizar para garantir uma escalabilidade eficiente.
O Azure fornece armazenamento na cloud altamente disponível e altamente dimensionável. O sistema de armazenamento subjacente para o Azure é fornecido através de um conjunto de serviços, incluindo o armazenamento de Blobs do Azure, o armazenamento de Tabelas do Azure, o armazenamento de Filas do Azure e Ficheiros do Azure.
O armazenamento de Tabelas do Azure foi concebido para armazenar dados estruturados. O serviço de Armazenamento do Azure suporta um número ilimitado de tabelas. Cada tabela pode ser dimensionada para níveis maciços e fornecer terabytes de armazenamento físico. Para tirar melhor partido das tabelas, tem de particionar os seus dados de forma ideal. Este artigo explora estratégias que pode utilizar para criar partições eficientes de dados para o armazenamento de Tabelas do Azure.
Entidades de tabela
As entidades de tabela representam as unidades de dados que são armazenadas numa tabela. As entidades de tabela são semelhantes às linhas numa tabela de base de dados relacional típica. Cada entidade define uma coleção de propriedades. Cada propriedade é definida como um par chave/valor pelo respetivo nome, valor e tipo de dados do valor. As entidades têm de definir as seguintes três propriedades do sistema como parte da coleção de propriedades:
PartitionKey: a propriedade PartitionKey armazena valores de cadeia que identificam a partição à qual uma entidade pertence. As partições, como discutimos mais tarde, são parte integrante da escalabilidade da tabela. As entidades que têm o mesmo valor PartitionKey são armazenadas na mesma partição.
RowKey: a propriedade RowKey armazena valores de cadeia que identificam exclusivamente entidades em cada partição. A PartitionKey e a RowKey juntos formam a chave primária para a entidade.
Carimbo de data/hora: a propriedade Carimbo de Data/Hora fornece rastreabilidade para uma entidade. Um carimbo de data/hora é um valor de data/hora que indica a última vez que a entidade foi modificada. Por vezes, um carimbo de data/hora é referido como a versão da entidade. As modificações aos carimbos de data/hora são ignoradas porque o serviço de tabelas mantém o valor desta propriedade durante todas as operações de inserção e atualização.
Chave primária da tabela
A chave primária de uma entidade do Azure consiste nas propriedades combinadas PartitionKey e RowKey . As duas propriedades formam um único índice agrupado na tabela. Os valores PartitionKey e RowKey podem ter até 1024 carateres. As cadeias vazias também são permitidas; no entanto, não são permitidos valores nulos.
O índice agrupado ordena por PartitionKey por ordem ascendente e, em seguida, por RowKey por ordem ascendente. A sequência de ordenação é observada em todas as respostas de consulta. As comparações lexical são utilizadas durante a operação de ordenação. É apresentado um valor de cadeia de "111" antes de um valor de cadeia de carateres de "2". Em alguns casos, poderá querer que a sequência de ordenação seja numérica. Para ordenar por ordem numérica e ascendente, tem de utilizar cadeias de carateres de comprimento fixo e sem almofadas. No exemplo anterior, "002" é apresentado antes de "111".
Partições de tabela
As partições representam uma coleção de entidades com os mesmos valores PartitionKey . As partições são sempre servidas a partir de um servidor de partições. Cada servidor de partições pode servir uma ou mais partições. Um servidor de partições tem um limite de taxa do número de entidades que pode servir de uma partição ao longo do tempo. Especificamente, uma partição tem um destino de escalabilidade de 2000 entidades por segundo. Este débito pode ser superior durante a carga mínima no nó de armazenamento, mas é limitado quando o nó fica quente ou ativo.
Para ilustrar melhor o conceito de criação de partições, a figura seguinte mostra uma tabela que contém um pequeno subconjunto de dados para registos de eventos de corrida a pé. A figura apresenta uma vista conceptual da criação de partições onde a PartitionKey contém três valores diferentes: o nome do evento combinado com três distâncias (maratona completa, meia maratona e 10 km). Este exemplo utiliza dois servidores de partição. O Servidor A contém registos para a meia maratona e distâncias de 10 km. O servidor B contém apenas as distâncias completas da maratona. Os valores RowKey são mostrados para fornecer contexto, mas os valores não são significativos para este exemplo.
Uma tabela com três partições
Escalabilidade
Uma vez que uma partição é sempre servida a partir de um único servidor de partição e cada servidor de partição pode servir uma ou mais partições, a eficiência de servir entidades está correlacionada com o estado de funcionamento do servidor. Os servidores que se deparam com tráfego elevado para as suas partições poderão não conseguir suportar um débito elevado. Por exemplo, na figura anterior, se forem recebidos muitos pedidos de "Marathon__Half de Nova Iorque de 2011", o servidor A poderá tornar-se demasiado frequente. Para aumentar o débito do servidor, o sistema de armazenamento balancea as partições para outros servidores. O resultado é que o tráfego é distribuído por muitos outros servidores. Para um balanceamento de carga ideal do tráfego, deve utilizar mais partições para que o armazenamento de Tabelas do Azure possa distribuir as partições por mais servidores de partição.
Transações de grupo de entidades
Uma transação de grupo de entidades é um conjunto de operações de armazenamento que são implementadas atomicamente em entidades que têm o mesmo valor PartitionKey . Se alguma operação de armazenamento no grupo de entidades falhar, todas as operações de armazenamento na entidade serão revertidas. Uma transação de grupo de entidades não consiste em mais de 100 operações de armazenamento e pode não ter mais de 4 MiB de tamanho. As transações de grupo de entidades fornecem armazenamento de Tabelas do Azure com uma forma limitada da semântica atomicidade, consistência, isolamento e durabilidade (ACID) fornecida pelas bases de dados relacionais.
As transações de grupos de entidades melhoram o débito porque reduzem o número de operações de armazenamento individuais que têm de ser submetidas para o armazenamento de Tabelas do Azure. As transações de grupos de entidades também proporcionam um benefício económico. Uma transação de grupo de entidades é faturada como uma única operação de armazenamento, independentemente do número de operações de armazenamento que contém. Uma vez que todas as operações de armazenamento numa transação de grupo de entidades afetam entidades que têm o mesmo valor PartitionKey , a necessidade de utilizar transações de grupos de entidades pode impulsionar a seleção do valor PartitionKey .
Intervalo de partições
Se utilizar valores PartitionKey exclusivos para as suas entidades, cada entidade pertence à sua própria partição. Se os valores exclusivos que utiliza aumentarem ou diminuirem o valor, é possível que o Azure crie partições de intervalo. As partições de intervalo agrupam entidades que têm valores partitionKey sequenciais e exclusivos para melhorar o desempenho das consultas de intervalo. Sem partições de intervalo, uma consulta de intervalo tem de ultrapassar os limites da partição ou os limites do servidor, o que pode diminuir o desempenho das consultas. Considere uma aplicação que utiliza a seguinte tabela, que tem um valor de sequência crescente para PartitionKey:
PartitionKey | RowKey |
---|---|
"0001" | - |
"0002" | - |
"0003" | - |
"0004" | - |
"0005" | - |
"0006" | - |
O Azure pode agrupar as três primeiras entidades numa partição de intervalo. Se aplicar uma consulta de intervalo à tabela que utiliza a PartitionKey como critérios e pede entidades de "0001" a "0003", a consulta poderá ter um desempenho eficiente porque as entidades são servidas a partir de um único servidor de partição. Não há garantias de quando e como será criada uma partição de intervalo.
A existência de partições de intervalo para a sua tabela pode afetar o desempenho das operações de inserção se inserir entidades que tenham valores PartitionKey crescentes ou decrescentes. A inserção de entidades com valores PartitionKey crescentes é denominada padrão só de acréscimo. A inserção de entidades com valores decrescentes é denominada padrão só de pré-e-end. Considere não utilizar estes tipos de padrões porque o débito geral dos seus pedidos de inserção é limitado por um único servidor de partição. Isto acontece porque, se existirem partições de intervalo, as primeiras e últimas partições (intervalo) contêm os valores PartitionKey menores e maiores, respetivamente. Por conseguinte, a inserção de uma nova entidade, que tem um valor PartitionKey sequencialmente inferior ou superior, destina-se a uma das partições finais. A figura seguinte mostra um possível conjunto de partições de intervalo que se baseiam no exemplo anterior. Se fosse inserido um conjunto de entidades "0007", "0008" e "0009", seriam atribuídas à última partição (laranja).
Um conjunto de partições de intervalo
É importante ter em atenção que não existe nenhum efeito negativo no desempenho se as operações de inserção utilizarem valores PartitionKey mais dispersos.
Analisar dados
Ao contrário de uma tabela numa base de dados relacional que pode utilizar para gerir índices, as tabelas no armazenamento de Tabelas do Azure só podem ter um índice. Um índice no armazenamento de Tabelas do Azure consiste sempre nas propriedades PartitionKey e RowKey .
Numa tabela do Azure, não tem o luxo de otimizar o desempenho da tabela ao adicionar mais índices ou ao alterar uma tabela existente depois de a implementar. Tem de analisar os dados à medida que cria a sua tabela. Os aspetos mais importantes a considerar para uma escalabilidade ideal e para a eficiência de consulta e inserção são os valores PartitionKey e RowKey . Este artigo realça como escolher a PartitionKey porque está diretamente relacionada com a forma como as tabelas são particionadas.
Dimensionamento de partições
O dimensionamento de partições refere-se ao número de entidades que uma partição contém. À medida que discutimos em Escalabilidade, ter mais partições significa que obtém um melhor balanceamento de carga. A granularidade do valor PartitionKey afeta o tamanho das partições. No nível mais grossérico, se um único valor for utilizado como PartitionKey, todas as entidades estão numa única partição muito grande. No melhor nível de granularidade, a PartitionKey pode conter valores exclusivos para cada entidade. O resultado é que existe uma partição para cada entidade. A tabela seguinte mostra as vantagens e desvantagens do intervalo de granularidades:
Granularidade partitionKey | Tamanho da partição | Vantagens | Desvantagens |
---|---|---|---|
Valor único | Pequeno número de entidades | As transações em lote são possíveis com qualquer entidade. Todas as entidades são locais e são servidas a partir do mesmo nó de armazenamento. |
|
Valor único | Grande número de entidades | As transações de grupos de entidades podem ser possíveis com qualquer entidade. Para obter mais informações sobre os limites das transações de grupos de entidades, veja Executar transações de grupos de entidades. | O dimensionamento é limitado. O débito está limitado ao desempenho de um único servidor. |
Vários valores | Várias partições Os tamanhos de partição dependem da distribuição de entidades. |
As transações em lotes são possíveis em algumas entidades. A criação de partições dinâmicas é possível. As consultas de pedido único são possíveis (sem tokens de continuação). O balanceamento de carga em mais servidores de partição é possível. |
Uma distribuição altamente desigual de entidades entre partições pode limitar o desempenho das partições maiores e mais ativas. |
Valores exclusivos | Muitas partições pequenas | A tabela é altamente dimensionável. As partições de intervalo podem melhorar o desempenho das consultas entre partições. |
As consultas que envolvem intervalos podem exigir visitas a mais do que um servidor. As transações em lote não são possíveis. Os padrões apenas de acréscimo ou de pré-fim podem afetar o débito de inserção. |
A tabela mostra como o dimensionamento é afetado pelos valores partitionKey . É uma melhor prática favorecer partições mais pequenas porque oferecem um melhor balanceamento de carga. As partições maiores podem ser adequadas em alguns cenários e não são necessariamente desfavorecidas. Por exemplo, se a sua aplicação não necessitar de escalabilidade, uma única partição grande poderá ser adequada.
Determinar consultas
As consultas obtêm dados de tabelas. Quando analisa os dados de uma tabela no armazenamento de Tabelas do Azure, é importante considerar quais as consultas que a aplicação irá utilizar. Se uma aplicação tiver várias consultas, poderá ter de priorizá-las, embora as suas decisões possam ser subjetivas. Em muitos casos, as consultas dominantes são discerníveis a partir de outras consultas. Em termos de desempenho, as consultas enquadram-se em categorias diferentes. Uma vez que uma tabela tem apenas um índice, o desempenho das consultas normalmente está relacionado com as propriedades PartitionKey e RowKey . A tabela seguinte mostra os diferentes tipos de consultas e as respetivas classificações de desempenho:
Tipo de consulta | Correspondência partitionKey | Correspondência de RowKey | Classificação de desempenho |
---|---|---|---|
Análise do intervalo de linhas | Exact | Parcial | Melhor com partições de tamanho mais pequeno. Incorreto com partições que são muito grandes. |
Análise do intervalo de partições | Parcial | Parcial | Bom, com um pequeno número de servidores de partição a serem tocados. Pior com mais servidores a serem tocados. |
Análise completa da tabela | Parcial, nenhum | Parcial, nenhum | Pior, com um subconjunto de partições a ser analisado. Pior, com todas as partições a serem analisadas. |
Nota
A tabela define as classificações de desempenho relativamente umas às outras. O número e o tamanho das partições podem, em última análise, determinar o desempenho da consulta. Por exemplo, uma análise do intervalo de partições de uma tabela que tenha muitas partições grandes pode ter um mau desempenho em comparação com uma análise de tabela completa para uma tabela que tenha algumas partições pequenas.
Os tipos de consulta listados na tabela anterior mostram uma progressão dos melhores tipos de consultas a utilizar para os piores tipos, com base nas respetivas classificações de desempenho. As consultas de pontos são os melhores tipos de consultas a utilizar porque utilizam totalmente o índice agrupado da tabela. A consulta de ponto seguinte utiliza os dados da tabela de registo de corridas a pé:
http://<account>.windows.core.net/registrations(PartitionKey=”2011 New York City Marathon__Full”,RowKey=”1234__John__M__55”)
Se a aplicação utilizar várias consultas, nem todas podem ser consultas pontuais. Em termos de desempenho, as consultas de intervalo seguem consultas de pontos. Existem dois tipos de consultas de intervalo: a análise do intervalo de linhas e a análise do intervalo de partições. A análise do intervalo de linhas especifica uma única partição. Uma vez que a operação ocorre num único servidor de partição, as análises de intervalo de linhas geralmente são mais eficientes do que as análises do intervalo de partições. No entanto, um fator chave no desempenho das análises do intervalo de linhas é a seleção de uma consulta. A seletividade de consultas dita quantas linhas têm de ser iteradas para encontrar as linhas correspondentes. As consultas mais seletivas são mais eficientes durante as análises de intervalo de linhas.
Para avaliar as prioridades das consultas, considere os requisitos de tempo de frequência e resposta para cada consulta. As consultas executadas frequentemente podem ser priorizadas mais elevadas. No entanto, uma consulta importante, mas raramente utilizada, pode ter requisitos de baixa latência que podem classificá-la mais alto na lista de prioridades.
Escolha o valor PartitionKey
O núcleo da estrutura de qualquer tabela é a escalabilidade, as consultas utilizadas para aceder à mesma e os requisitos de operação de armazenamento. Os valores PartitionKey que escolher ditam como uma tabela é particionada e o tipo de consultas que pode utilizar. As operações de armazenamento, e especialmente as inserções, também podem afetar a escolha dos valores partitionKey . Os valores PartitionKey podem variar de valores únicos a valores exclusivos. Também podem ser criados com vários valores. Pode utilizar as propriedades da entidade para formar o valor PartitionKey . Em alternativa, a aplicação pode calcular o valor. As secções seguintes abordam considerações importantes.
Transações de grupo de entidades
Os programadores devem primeiro considerar se a aplicação irá utilizar transações de grupo de entidades (atualizações em lote). As transações de grupo de entidades exigem que as entidades tenham o mesmo valor PartitionKey . Além disso, uma vez que as atualizações de lote se destinam a um grupo inteiro, as escolhas dos valores partitionKey podem ser limitadas. Por exemplo, uma aplicação bancária que mantenha transações em dinheiro tem de inserir transações em dinheiro na tabela atomicamente. As transações em dinheiro representam os lados do débito e do crédito e têm de ser líquidas para zero. Este requisito significa que o número da conta não pode ser utilizado como parte do valor PartitionKey porque cada lado da transação utiliza números de conta diferentes. Em vez disso, um ID de transação pode ser uma escolha melhor.
Partições
Os números e tamanhos de partição afetam a escalabilidade de uma tabela que está sob carga. Também são controlados pela forma granular como os valores partitionKey são granulares. Pode ser difícil determinar a PartitionKey com base no tamanho da partição, especialmente se a distribuição de valores for difícil de prever. Uma boa regra do polegar é utilizar múltiplas partições mais pequenas. Muitas partições de tabela facilitam a gestão do armazenamento de Tabelas do Azure a partir dos nós de armazenamento a partir dos qual as partições são servidas.
Escolher valores exclusivos ou mais finos para PartitionKey resulta em partições mais pequenas, mas mais. Geralmente, isto é favorável porque o sistema pode fazer o balanceamento de carga das muitas partições para distribuir a carga por várias partições. No entanto, deve considerar o efeito de ter muitas partições em consultas de intervalo de partições cruzadas. Estes tipos de consultas têm de visitar várias partições para satisfazer uma consulta. É possível que as partições sejam distribuídas por vários servidores de partição. Se uma consulta atravessar um limite do servidor, os tokens de continuação têm de ser devolvidos. Os tokens de continuação especificam os próximos valores PartitionKey ou RowKey para obter o próximo conjunto de dados da consulta. Por outras palavras, os tokens de continuação representam pelo menos mais um pedido para o serviço, o que pode degradar o desempenho geral da consulta.
A seletividade de consultas é outro fator que pode afetar o desempenho da consulta. A seletividade de consultas é uma medida do número de linhas que têm de ser iteradas para cada partição. Quanto mais seletiva for a consulta, mais eficiente será a consulta ao devolver as linhas que pretende. O desempenho geral das consultas de intervalo pode depender do número de servidores de partição que têm de ser tocados ou da seleção da consulta. Também deve evitar utilizar os padrões apenas de acréscimo ou de pré-acréscimo quando insere dados na sua tabela. Se utilizar estes padrões, apesar de criar partições pequenas e muitas, poderá limitar o débito das operações de inserção. Os padrões apenas de acréscimo e de pré-acesso são discutidos em Partições de intervalo.
Consultas
Conhecer as consultas que irá utilizar pode ajudá-lo a determinar que propriedades são importantes considerar para o valor PartitionKey . As propriedades que utiliza nas consultas são candidatas ao valor PartitionKey . A tabela seguinte fornece uma orientação geral sobre como determinar o valor PartitionKey :
Se a entidade... | Ação |
---|---|
Tem uma propriedade chave | Utilize-a como PartitionKey. |
Tem duas propriedades de chave | Utilize uma como PartitionKey e outra como RowKey. |
Tem mais de duas propriedades principais | Utilize uma chave composta de valores concatenados. |
Se existir mais do que uma consulta igualmente dominante, pode inserir as informações várias vezes com valores RowKey diferentes de que precisa. A sua aplicação irá gerir linhas secundárias (ou terciárias, etc.). Pode utilizar este tipo de padrão para satisfazer os requisitos de desempenho das suas consultas. O exemplo seguinte utiliza os dados do exemplo de registo de corrida a pé. Tem duas consultas dominantes:
- Consultar por número bib
- Consulta por idade
Para servir ambas as consultas dominantes, insira duas linhas como uma transação de grupo de entidades. A tabela seguinte mostra as propriedades PartitionKey e RowKey para este cenário. Os valores RowKey fornecem um prefixo para o bíb e a idade para que a aplicação possa distinguir entre os dois valores.
PartitionKey | RowKey |
---|---|
Marathon__Full de Nova Iorque de 2011 | BIB:01234__John__M__55 |
Marathon__Full de Nova Iorque de 2011 | IDADE:055__1234__John__M |
Neste exemplo, uma transação de grupo de entidades é possível porque os valores PartitionKey são os mesmos. A transação de grupo fornece atomicidade da operação de inserção. Embora seja possível utilizar este padrão com diferentes valores PartitionKey , recomendamos que utilize os mesmos valores para obter este benefício. Caso contrário, poderá ter de escrever lógica adicional para garantir que as transações atómicas utilizam valores partitionKey diferentes.
Operações de armazenamento
As tabelas no armazenamento de Tabelas do Azure podem encontrar carga não só a partir de consultas. Também podem encontrar carga a partir de operações de armazenamento, como inserções, atualizações e eliminações. Considere o tipo de operações de armazenamento que irá realizar na tabela e a que taxa. Se realizar estas operações com pouca frequência, poderá não ter de se preocupar com as mesmas. No entanto, para operações frequentes como executar muitas inserções num curto espaço de tempo, tem de considerar como essas operações são servidas como resultado dos valores partitionKey que escolher. Exemplos importantes são os padrões apenas de acréscimo e de pré-conclusão. Os padrões apenas de acréscimo e de pré-acesso são discutidos em Partições de intervalo.
Quando utiliza um padrão só de acréscimo ou apenas de pré-fim, utiliza valores ascendentes ou descendentes exclusivos para PartitionKey em inserções subsequentes. Se combinar este padrão com operações de inserção frequentes, a tabela não poderá servir as operações de inserção com grande escalabilidade. A escalabilidade da tabela é afetada porque o Azure não consegue fazer o balanceamento de carga dos pedidos de operação para outros servidores de partição. Nesse caso, poderá considerar a utilização de valores aleatórios, como valores GUID. Em seguida, os tamanhos de partição podem permanecer pequenos e manter o balanceamento de carga durante as operações de armazenamento.
Teste de stress da partição da tabela
Quando o valor PartitionKey é complexo ou requer comparações com outros mapeamentos partitionKey , poderá ter de testar o desempenho da tabela. O teste deve examinar o desempenho de uma partição em cargas de pico.
Para realizar um teste de stress
- Create uma tabela de teste.
- Carregue a tabela de teste com dados para que contenha entidades com o valor PartitionKey que irá direcionar.
- Utilize a aplicação para simular o pico de carga para a tabela. Direcione uma única partição com o valor PartitionKey do passo 2. Este passo é diferente para cada aplicação, mas a simulação deve incluir todas as consultas e operações de armazenamento necessárias. Poderá ter de ajustar a aplicação para que tenha como destino uma única partição.
- Examine o débito das operações GET ou PUT na tabela.
Para examinar o débito, compare os valores reais com o limite especificado de uma única partição num único servidor. As partições estão limitadas a 2000 entidades por segundo. Se o débito exceder as 2000 entidades por segundo para uma partição, o servidor poderá ser demasiado frequente numa definição de produção. Neste caso, os valores partitionKey podem ser demasiado grosséricos, para que não existam partições suficientes ou as partições sejam demasiado grandes. Poderá ter de modificar o valor PartitionKey para que as partições sejam distribuídas entre mais servidores.
Balanceamento de carga
O balanceamento de carga na camada de partição ocorre quando uma partição fica demasiado frequente. Quando uma partição está demasiado frequente, a partição, especificamente o servidor de partição, funciona para além da escalabilidade de destino. Para o armazenamento do Azure, cada partição tem um objetivo de escalabilidade de 2000 entidades por segundo. O balanceamento de carga também ocorre na camada Sistema de Ficheiros Distribuído (DFS).
O balanceamento de carga na camada DFS lida com a carga de E/S e está fora do âmbito deste artigo. O balanceamento de carga na camada de partição não ocorre imediatamente após a exceção do destino de escalabilidade. Em vez disso, o sistema aguarda alguns minutos antes de iniciar o processo de balanceamento de carga. Isto garante que uma partição se tornou verdadeiramente quente. Não é necessário criar partições com carga gerada que acione o balanceamento de carga porque o sistema executa automaticamente a tarefa.
Se uma tabela tiver sido preparada com uma determinada carga, o sistema poderá ser capaz de equilibrar as partições com base na carga real, o que resulta numa distribuição significativamente diferente das partições. Em vez de criar partições, considere escrever código que processe os erros de tempo limite e Ocupado pelo Servidor. Os erros são devolvidos quando o sistema está a fazer o balanceamento de carga. Ao processar esses erros através de uma estratégia de repetição, a sua aplicação pode lidar melhor com as cargas de pico. As estratégias de repetição são abordadas mais detalhadamente na secção seguinte.
Quando ocorre o balanceamento de carga, a partição fica offline durante alguns segundos. Durante o período offline, o sistema reatribui a partição a um servidor de partição diferente. É importante ter em atenção que os seus dados não são armazenados pelos servidores de partição. Em vez disso, os servidores de partição servem entidades da camada DFS. Uma vez que os seus dados não estão armazenados na camada de partição, mover partições para servidores diferentes é um processo rápido. Esta flexibilidade limita consideravelmente o tempo de inatividade, caso exista, que a sua aplicação possa encontrar.
Estratégia de repetição
É importante que a sua aplicação lide com falhas de operações de armazenamento para ajudar a garantir que não perde atualizações de dados. Algumas falhas não requerem uma estratégia de repetição. Por exemplo, as atualizações que devolvem um erro 401 Não autorizado não beneficiam da repetição da operação porque é provável que o estado da aplicação não se altere entre as repetições que resolvem o erro 401. No entanto, erros como Servidor Ocupado ou Tempo Limite estão relacionados com as funcionalidades de balanceamento de carga do Azure que proporcionam escalabilidade da tabela. Quando os nós de armazenamento que servem as suas entidades ficam quentes, o Azure equilibra a carga ao mover partições para outros nós. Durante este período, a partição pode estar inacessível, o que resulta em erros de Servidor Ocupado ou Tempo Limite. Eventualmente, a partição é reativada e as atualizações são retomadas.
Uma estratégia de repetição é adequada para erros de Servidor Ocupado ou Tempo Limite. Na maioria dos casos, pode excluir erros de 400 níveis e alguns erros de 500 níveis da lógica de repetição. Os erros que podem ser excluídos incluem 501 Não Implementado e 505 Versão HTTP Não Suportada. Em seguida, pode implementar uma estratégia de repetição para erros de até 500 níveis, como Servidor Ocupado (503) e Tempo Limite (504).
Pode escolher entre três estratégias de repetição comuns para a sua aplicação:
- Sem Repetição: não é efetuada nenhuma tentativa de repetição.
- Backoff Fixo: a operação é repetida N vezes com um valor de recuo constante.
- Trás Exponencial: a operação é repetida N vezes com um valor de recuo exponencial.
A estratégia Sem Repetição é uma forma simples (e evasiva) de lidar com falhas de operação. No entanto, uma estratégia Sem Repetição não é muito útil. Não impor quaisquer tentativas de repetição representa riscos óbvios, uma vez que os dados não são armazenados corretamente após operações falhadas. Uma estratégia melhor é utilizar a estratégia de Backoff Fixo. que fornece a capacidade de repetir operações com a mesma duração de backoff.
No entanto, a estratégia não está otimizada para processar tabelas altamente dimensionáveis. Se muitos threads ou processos estiverem à espera da mesma duração, podem ocorrer colisões. Uma estratégia de repetição recomendada é aquela que utiliza um recuo exponencial em que cada tentativa de repetição é maior do que a última tentativa. É semelhante ao algoritmo de prevenção de colisão utilizado em redes de computadores, como o Ethernet. O recuo exponencial utiliza um fator aleatório para fornecer uma variância adicional ao intervalo resultante. Em seguida, o valor de backoff é limitado a limites mínimos e máximos. A fórmula seguinte pode ser utilizada para calcular o próximo valor de backoff com um algoritmo exponencial:
y = Rand(0,8z, 1,2z)(2x-1
y = Min(zmin + y, zmax
Em que:
z = recuo predefinido em milissegundos
zmin = recuo mínimo predefinido em milissegundos
zmax = recuo máximo predefinido em milissegundos
x = o número de repetições
y = o valor de recuo em milissegundos
Os multiplicadores de 0,8 e 1,2 utilizados na função Rand (aleatório) produzem uma variância aleatória do recuo predefinido dentro de ±20% do valor original. O intervalo de ±20% é aceitável para a maioria das estratégias de repetição e evita novas colisões. A fórmula pode ser implementada com o seguinte código:
int retries = 1;
// Initialize variables with default values
var defaultBackoff = TimeSpan.FromSeconds(30);
var backoffMin = TimeSpan.FromSeconds(3);
var backoffMax = TimeSpan.FromSeconds(90);
var random = new Random();
double backoff = random.Next(
(int)(0.8D * defaultBackoff.TotalMilliseconds),
(int)(1.2D * defaultBackoff.TotalMilliseconds));
backoff *= (Math.Pow(2, retries) - 1);
backoff = Math.Min(
backoffMin.TotalMilliseconds + backoff,
backoffMax.TotalMilliseconds);
Resumo
Uma aplicação no armazenamento de Tabelas do Azure pode armazenar uma grande quantidade de dados porque o Armazenamento de tabelas gere e reatribui partições em muitos nós de armazenamento. Pode utilizar a criação de partições de dados para controlar a escalabilidade da tabela. Planeie com antecedência quando definir um esquema de tabela para garantir que implementa estratégias de criação de partições eficientes. Especificamente, analise os requisitos, os dados e as consultas da aplicação antes de selecionar valores PartitionKey . Cada partição pode ser reatribuída a diferentes nós de armazenamento à medida que o sistema responde ao tráfego. Utilize um teste de esforço de partição para garantir que a tabela tem os valores partitionKey corretos. Este teste ajuda-o a determinar quando as partições estão demasiado quentes e ajuda-o a fazer os ajustes de partição necessários.
Para garantir que a sua aplicação processa erros intermitentes e que os seus dados persistem, utilize uma estratégia de repetição com o backoff. A política de repetição predefinida que a Biblioteca de Cliente do Armazenamento do Azure utiliza tem um recuo exponencial que evita colisões e maximiza o débito da sua aplicação.