Exportar (0) Imprimir
Expandir Tudo

Como criar uma estratégia de particionamento escalonável para o armazenamento de tabelas do Azure

Atualizado: agosto de 2014

Autor: http://msdn.microsoft.com/pt-br/library/hh307529.aspx

Imagem referenciada

Saiba mais sobre Consulta de RBA.

Resumo Este artigo discute tópicos relacionados ao particionamento de uma Tabela do Azure e as estratégias usadas para garantir uma escalabilidade eficiente.

O Azure fornece armazenamento de dados confiável que está sempre disponível e altamente escalonável. O sistema de armazenamento subjacente do Azure é fornecido através de um conjunto de abstrações de objeto frequentemente descritas como serviços, que são compostos pelos serviços de tabela, blob e fila. Cada um desses serviços pode apoiar a maioria das suas necessidades de desenvolvimento. Quando seu aplicativo necessita armazenar dados estruturados, a tabela do Azure fornece a você a melhor opção. O serviço de Armazenamento do Azure comporta um número ilimitado de tabelas, e cada tabela pode ser dimensionada para níveis maciços. Uma tabela pode se dimensionar automaticamente para armazenar bilhões de entidades que podem representar terabytes de armazenamento físico. Para aproveitar o que as tabelas oferecem, os dados devem ser particionados usando valores de PartitionKey otimizados. Este artigo explora estratégias que permitem particionar de forma eficiente dados do armazenamento da Tabela do Azure.

As entidades de tabela representam as unidades dos dados armazenados em uma tabela e são semelhantes às linhas em uma tabela de banco de dados relacional típico. Cada entidade define um conjunto de propriedades. Cada propriedade é um par chave/valor definido pelo seu nome, valor e o tipo de dado do valor. As entidades devem definir as três propriedades de sistema a seguir como parte da coleção de propriedades:

  • PartitionKey – A propriedade PartitionKey armazena valores de cadeia de caracteres que identificam a partição à qual uma entidade pertence. Isso significa que as entidades com os mesmos valores de PartitionKey pertencem à mesma partição. As partições, abordadas posteriormente, são parte integrante da escalabilidade da tabela.

  • RowKey – A propriedade RowKey armazena valores de cadeia de caracteres que identificam univocamente entidades dentro de cada partição.

  • Timestamp – A propriedade Timestamp fornece rastreabilidade para uma entidade. Um carimbo é um valor DateTime que informa a última vez que a entidade foi modificada. Um carimbo às vezes é referido como a versão da entidade. As modificações ao carimbo são ignoradas porque o serviço de tabela mantém o valor dessa propriedade durante todas as inserções e operações de atualização.

A chave primária de qualquer tabela de banco de dados define as colunas que definem univocamente cada linha. O mesmo acontece com as tabelas do Azure. A chave primária de uma tabela do Azure são as propriedades PartitionKey e RowKey que formam um índice clusterizado único dentro da tabela. Cada propriedade PartitionKey e RowKey pode armazenar até 1 KB de valores de cadeia de caracteres. As cadeias de caracteres vazias também são permitidas, mas os valores nulos não o são. O índice clusterizado é classificado pela PartitionKey em ordem crescente, e em seguida pela RowKey também em ordem crescente. A ordem de classificação é observada em todas as respostas de consultas. Durante a operação de classificação são usadas comparações lexicais. Portanto, um valor de cadeia de caracteres "111" aparecerá antes de um valor de cadeia de caracteres "2". Em alguns casos, você pode preferir que a ordem seja numérica. Para classificar por ordem numérica e crescente, é necessário usar cadeias de caracteres de comprimento fixo e sem preenchimento. No exemplo anterior, o uso de "002" permitirá que este apareça antes de "111".

As partições representam uma coleção de entidades com os mesmos valores de PartitionKey. As partições são sempre atendidas a partir de um servidor de partições, e cada servidor de partições pode atender uma ou mais partições. Um servidor de partições possui um limite de taxa do número de entidades que ele pode atender a partir de uma partição ao longo do tempo. Especificamente, uma partição possui uma meta de escalabilidade de 500 entidades por segundo. Essa taxa de transferência pode ser maior durante o carregamento mínimo no nó do armazenamento, mas ela será limitada quando o nó do armazenamento se tornar muito solicitado ou muito ativo. Para ilustrar melhor o conceito de particionamento, a figura a seguir ilustra uma tabela que contém um pequeno subconjunto de dados para registros de eventos de corrida. Ela representa uma visualização conceitual do particionamento onde PartitionKey contém três valores diferentes que compreendem o nome e a distância do evento. Nesse exemplo, há dois servidores de partições. O Servidor A contém registros para as distâncias de meia maratona e de 10 km, enquanto o Servidor B contém apenas as distâncias da maratona completa. Os valores de RowKey são exibidos para fornecer contexto, mas não são significativos para este exemplo.

Tela referenciada

Como uma partição é sempre atendida a partir de um servidor de partições único, e dado que cada servidor de partições pode atender uma ou mais partições, a eficiência das entidades de atendimento está correlacionada com a integridade do servidor. Os servidores que encontram tráfego intenso para suas partições podem não ser capazes de manter uma alta taxa de transferência. Por exemplo, na figura acima, se houver muitas solicitações para "2011 New York City Marathon__Half", o servidor A pode se tornar excessivamente solicitado. Para aumentar a taxa de transferência do servidor, o sistema de armazenamento fornece balanceamento de carga das partições para outros servidores. O resultado é que o tráfego é distribuído através de vários outros servidores. Para obter um balanceamento de carga de tráfego ideal, você deve usar mais partições, porque isso vai permitir que o serviço Tabela do Azure distribua as partições para mais servidores de partições.

Uma transação de grupo de entidades é um conjunto de operações de armazenamento que são implementadas de forma atômica em entidades com o mesmo valor de PartitionKey. Se alguma operação de armazenamento no grupo de entidades falhar, então todas as operações de armazenamento nele são revertidas. Uma transação do grupo de entidades inclui no máximo 100 operações de armazenamento e não pode ter mais de 4 MB de tamanho. As transações do grupo de entidades fornecem à Tabela do Azure uma forma limitada da atomicidade, coerência, isolamento e semânticas de durabilidade (ACID) fornecidas pelos bancos de dados relacionais. As transações do grupo de entidades melhoram a taxa de transferência, pois elas reduzem o número de operações individuais de armazenamento que devem ser enviadas para o serviço Tabela do Azure. Elas também fornecem um benefício econômico, pois uma transação de grupo de entidades é cobrada como uma única operação de armazenamento, independentemente de quantas operações de armazenamento ela contenha. Como todas as operações de armazenamento de uma transação de grupo de entidades afetam as entidades com o mesmo valor de PartitionKey, o desejo de usar transações de grupo de entidades pode motivar a seleção do valor de PartitionKey.

Se você está usando valores de PartitionKey exclusivos para suas entidades, então cada entidade pertencerá à sua própria partição. Se os valores exclusivos que você está usando estão aumentando ou diminuindo de valor, é possível que o Azure crie partições de intervalo. As partições de intervalo agrupam entidades que possuem valores de PartitionKey exclusivos e sequenciais para melhorar o desempenho de consultas de intervalo. Sem as partições de intervalo, uma consulta de intervalo necessitará atravessar os limites das partições ou os limites dos servidores, o que pode diminuir o desempenho da consulta. Considere um aplicativo que usa a seguinte tabela com valores sequenciais crescentes da PartitionKey.

 

PartitionKey

RowKey

"0001"

-

"0002"

-

"0003"

-

"0004"

-

"0005"

-

"0006"

-

O Azure pode agrupar as primeiras três entidades em uma partição de intervalo. Se você aplicar a esta tabela uma consulta de intervalo que use a PartitionKey como critério e solicite entidades de "0001" a "0003", a consulta poderá apresentar um desempenho eficiente, pois as partições serão atendidas a partir de um único servidor de partições. Não há garantia 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 de suas operações de inserção se você estiver inserindo entidades com valores de PartitionKey crescentes ou decrescentes. A inserção de entidades com valores de PartitionKey crescentes é denominada padrão Somente Acréscimo, e a inserção de entidades com valores decrescentes é denominada padrão Somente Precedência. Você deve considerar não usar tais padrões, porque a taxa de transferência geral de suas solicitações de inserção serão limitadas por um único servidor de partições. Isso ocorre porque se existirem partições de intervalo, então a primeira e última partições (de intervalo) irão conter os valores de PartitionKey menor e maior, respectivamente. Portanto, a inserção de uma nova entidade, com um valor de PartitionKey sequencialmente menor ou maior, irá visar uma das partições extremas. A figura seguinte mostra um possível conjunto de partições de intervalo no exemplo anterior. Se fosse inserido um conjunto de entidades "0007", "0008" e "0009", eles iriam ser atribuídos à última partição (laranja).

Tela referenciada

É importante observar que não há efeitos negativos no desempenho se as operações de inserção estiverem usando valores de PartitionKey mais dispersos.

Diferentemente de uma tabela de um banco de dados relacional, que permite gerenciar índices, as tabelas do Azure só podem ter um índice, que é sempre composto pelas propriedades PartitionKey e RowKey. Você não possui o luxo de ajustar o desempenho de sua tabela adicionando mais índices ou alterando um índice existente após você o ter distribuído. Portanto, você deve analisar os dados conforme projeta sua tabela. Os aspectos mais importantes a considerar para se obter uma escalabilidade ideal e eficiência na consulta e inserção são os valores de PartitionKey e RowKey. Este artigo põe mais ênfase em como escolher a PartitionKey, porque ela está diretamente relacionada com a forma em que as tabelas são particionadas.

O dimensionamento da partição refere-se ao número de entidades que uma partição contém. Conforme mencionado na seção "Escalabilidade", mais partições significam um melhor balanceamento de carga. A granularidade do valor de PartitionKey afeta o tamanho das partições. No nível mais simples, se for usado um valor único como PartitionKey, todas as entidades estarão em uma partição única e muito grande. Como alternativa, no melhor nível de granularidade, a PartitionKey pode conter valores únicos para cada entidade. O resultado é que há uma partição para cada entidade. A tabela seguinte mostra as vantagens e desvantagens do intervalo de granularidades.

 

Granularidade da PartitionKey

Tamanho da partição

Vantagens

Desvantagens

Valor único

Pequeno número de entidades

As transações em lotes são possívies com qualquer entidade

Todas as entidades são locais e são atendidas a partir do mesmo nó de armazenamento

 

Valor único

Grande número de entidades

As Transações de Grupo de Entidades podem ser possíveis com qualquer entidade. Consulte http://msdn.microsoft.com/en-us/library/dd894038.aspxpara obter mais informações sobre os limites das transações de grupo de entidades

O escalonamento é limitado.

A taxa de transferência é limitada ao desempenho de um único servidor.

Vários valores

Há várias partições

Os tamanhos das partições dependem da distribuição das entidades

As transações em lotes são possíveis em algumas entidades

O particionamento dinâmico é possível

As consultas de solicitação única são possíveis (não há tokens de continuação)

O balanceamento de carga através de mais servidores de partições é possível

Uma distribuição altamente irregular de entidades através das partições pode limitar o desempenho das partições maiores e mais ativas

Valores únicos

Há muitas partições pequenas.

A tabela é altamente escalonável

As partições de intervalo podem melhorar o desempenho de consultas de intervalo entre partições

As consultas que envolvem intervalos podem exigir visitas a mais de um servidor.

As transações em lotes não são possíveis.

Os padrões Somente Acréscimo ou Somente Precedência podem afetar a taxa de transferência de inserção

Esta tabela mostra como o dimensionamento é afetado pelos valores de PartitionKey. É uma prática recomendada favorecer partições menores, porque elas oferecem um melhor balanceamento de carga. As partições maiores podem ser apropriadas em determinadas situações, e não são necessariamente desvantajosas. Por exemplo, se seu aplicativo não exigir escalabilidade, uma única partição grande pode ser apropriada.

As consultas recuperam dados de tabelas. Quando você analiza os dados de uma tabela do Azure, é importante considerar quais consultas o aplicativo irá usar. Se um aplicativo tiver várias consultas, pode ser necessário priorizá-las, embora suas decisões possam ser subjetivas. Em muitos casos, as consultas dominantes são discerníveis das outras consultas. Em termos de desempenho, as consultas se encaixam em diferentes categorias. Como uma tabela possui 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 suas classificações de desempenho.

 

Tipo de consulta

Correspondência PartitionKey

Correspondência RowKey

Classificação de desempenho

Point

Exato

Exato

Excelente

Exame de intervalo de linhas

Exato

Parcial

Melhor com partições de tamanho menor

Ruim com partições muito grandes

Exame de intervalo de partições

Parcial

Parcial

Bom com um número pequeno de servidores de partições envolvidos

Pior com mais servidores envolvidos

Verificação de tabela completa

Parcial, nenhum

Parcial, nenhum

Pior com um subconjunto de partições sendo examinado

Pior com todas as partições sendo examinadas

noteObservação
A tabela define classificações de desempenho relativas umas às outras. O número e o tamanho das partições pode determinar o desempenho da consulta. Por exemplo, um exame de intervalo de partições para uma tabela com partições numerosas e grandes pode apresentar um baixo desempenho comparado com um exame de tabela completo com partições pequenas e pouco numerosas.

Os tipos de consulta listados nesta tabela mostram uma progressão dos melhores tipos de consultas para usar aos piores tipos, com base nas respectivas classificações de desempenho. As consultas de faixas são os melhores tipos de consultas, porque usam totalmente o índice clusterizado da tabela. A seguinte consulta de faixa usa os dados da tabela de registros da corrida.

http://<account>.windows.core.net/registrations(PartitionKey=”2011 New York City Marathon__Full”,RowKey=”1234__John__M__55”)

Se o aplicativo usar várias consultas, elas não podem ser todas consultas de faixas. Em termos de desempenho, as consultas de intervalo seguem as consultas de faixa. Existem dois tipos de consultas de intervalo: o exame de intervalo de linhas e o exame de intervalo de partições. O exame de intervalo de linhas especifica uma única partição. Como a operação ocorre em um único servidor de partições, os exames de intervalo de linhas são geralmente mais eficientes do que os exames de intervalo de partições. No entanto, um fator chave no desempenho do exame de intervalo de linhas é o grau de seletividade de uma consulta. A seletividade da consulta determina quantas linhas devem ser iteradas para encontrar linhas correspondentes. As consultas mais seletivas são mais eficientes durante os exames de intervalo de linhas.

Para avaliar as prioridades de suas consultas, você deve considerar a frequência e os requisitos de tempo de resposta para cada consulta. As consultas que são executadas com frequência podem ter uma prioridade mais alta. No entanto, uma consulta importante mas raramente usada pode ter requisitos baixos de latência e pode portanto ter uma classificação mais alta na lista de prioridades.

O núcleo de qualquer concepção de tabela está baseado em sua escalabilidade, nas consultas usadas para acessá-la e nos requisitos de operações de armazenamento. Os valores da PartitionKey que você escolher determinarão como a tabela será particionada e os tipos de consulta que podem ser usados. As operações de armazenamento, em particular as inserções, também podem afetar sua escolha dos valores da PartitionKey. Os valores da PartitionKey podem variar de valores únicos a valores exclusivos, e também podem ser compostos de vários valores. As propriedades das entidades podem ser compostas para formar o valor da PartitionKey. Além disso, o aplicativo pode calcular o valor.

Os desenvolvedores devem primeiro considerar se o aplicativo utilizará transações de grupo de entidades (atualizações em lotes). As transações de grupo de entidades exigem que as entidades tenham o mesmo valor da PartitionKey. Além disso, como as atualizações em lotes são para todo o grupo, as escolhas para os valores da PartitionKey podem ser limitadas. Por exemplo, um aplicativo bancário que mantém transações monetárias deve inseri-las na tabela atomicamente. Isso é porque as transações monetárias representam tanto o lado do débito quanto o do crédito, e devem se compensar para dar zero. Esse requisito significa que o número da conta não pode ser usado como parte da PartitionKey, porque cada lado da transação usa números de conta diferentes. Em vez disso, uma ID de transação pode ser uma escolha mais natural.

Os números e tamanhos das partições afetam a escalabilidade de uma tabela que está sob carga, e são controlados pelo grau de granularidade dos valores da PartitionKey. Pode ser um desafio determinar a PartitionKey com base no tamanho da partição, especialmente se a distribuição dos valores for difícil de prever. Uma boa regra prática é usar várias partições menores. Muitas partições de tabela facilitam o serviço Tabela do Azure para gerenciar os nós de armazenamento a partir de onde as partições são atendidas.

Escolher valores únicos ou mais precisos para a PartitionKey resultará em partições menores e mais numerosas. Normalmente, isso é favorável porque o sistema pode balancear a carga das numerosas partições para distribuir a carga através de numerosas partições. No entanto, você deve levar em consideração o efeito de ter várias partições em consultas de intervalo entre partições. Esse tipo de consulta deve visitar várias partições para satisfazer a consulta. É possível que as partições estejam distribuídas através de muitos servidores de partições. Se uma consulta cruzar um limite de servidor, deverão ser retornados tokens de continuação. Os tokens de continuação especificam os próximos valores de PartitionKey ou de RowKey que irão recuperar o próximo conjunto de dados para a consulta. Em outras palavras, os tokens de continuação representam pelo menos mais uma solicitação ao serviço, o que pode degradar o desempenho geral da consulta. A seletividade da consulta é outro fator que pode afetar o desempenho da consulta. A seletividade da consulta é uma medida de quantas linhas devem ser iteradas para cada partição. Quanto mais seletiva for uma consulta, mais eficiente ela será ao retornar as linhas desejadas. O desempenho geral das consultas de intervalo pode depender do número de servidores de partições que devem ser tocados ou de quão seletiva a consulta é. Você também deve evitar usar os padrões somente acréscimo ou somente precedência ao inserir dados em sua tabela. O uso de tais padrões, apesar de criar partições numerosas e pequenas, pode limitar a taxa de transferência de suas operações de inserção. Os padrões somente acréscimo e somente precedência são discutidos na seção "Partições de intervalo".

Saber as consultas que serão usadas permitirá determinar quais propriedades é importante levar em consideração para a PartitionKey. As propriedades que são usadas nas consultas são candidatas para a PartitionKey. A tabela seguinte fornece uma orientação geral de como determinar a PartitionKey.

 

Se a entidade...

Ação

tem uma propriedade chave

Use-a como a PartitionKey

tem duas propriedades chave

Use uma como a PartitionKey e a outra como a RowKey

tem mas de duas propriedades chave

Use uma chave composta de valores concatenados

Se houver mais de uma consulta igualmente dominante, você pode inserir as informações várias vezes com os diferentes valores de RowKey que você precisar. As linhas secundárias (ou terciárias, etc.) serão gerenciadas pelo seu aplicativo. Esse padrão permitirá satisfazer os requisitos de desempenho de suas consultas. O exemplo seguinte usa os dados do exemplo de registro da corrida. Ele tem duas consultas dominantes. São elas:

  • Consulta por número chave

  • Consulta por idade

Para atender 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 a situação em questão. Os valores de RowKey fornecem um prefixo para chave e idade para permitir que o aplicativo distinga os dois valores.

 

PartitionKey

RowKey

2011 New York City Marathon__Full

CHAVE:01234__John__M__55

2011 New York City Marathon__Full

IDADE:055__1234__John__M

Neste exemplo, uma transação de grupo de entidades é possível porque os valores da PartitionKey são iguais. A transação de grupo fornece atomicidade à operação de inserção. Embora seja possível usar esse padrão com valores diferentes da PartitionKey, recomenda-se usar os mesmos valores para obter esse benefício. Caso contrário, pode ser necessário escrever lógica extra para garantir transações atômicas com diferentes valores da PartitionKey.

As tabelas do Azure podem encontrar carga não apenas de consultas, mas também de operações de armazenamento como inserções, atualizações e exclusões. É necessário considerar que tipo de operações de armazenamento você realizará na tabela e a qual taxa. Se você realiza essas operações raramente, então provavelmente não precisará se preocupar com elas. No entanto, para operações muito frequentes tais como realizar várias inserções em um curto período, será necessário considerar como essas operações são atendidas como resultado dos valores da PartitionKey que você escolheu. Um exemplo importante são os padrões somente acréscimo ou somente precedência. Esses padrões foram discutidos na sessão anterior "Partições de intervalo". O uso dos padrões somente acréscimo ou somente precedência significa que você está usando valores unívocos crescentes ou decrescentes para a PartitionKey em inserções subsequentes. Se você combinar esse padrão com operações de inserção frequentes, sua tabela não poderá atender as operações de inserção com boa escalabilidade. A escalabilidade de sua tabela é afetada porque o Azure não poderá balancear a carga das solicitações de operações para outros servidores de partições. Portanto, nesse caso, pode ser conveniente usar valores aleatórios, como os valores GUID. Isso permitirá que os tamanhos das suas partições permaneçam pequenos, mantendo o balanceamento de carga durante as operações de armazenamento.

Quando o valor da PartitionKey é complexo ou exige comparações com outros mapeamentos da PartitionKey, pode ser necessário testar o desempenho da tabela. O teste deve examinar o desempenho da partição sob cargas de pico.

Para realizar um teste de estresse

  1. Crie uma tabela de teste.

  2. Carregue a tabela de teste com dados para que ela contenha entidades com a PartitionKey que você estará visando.

  3. Use o aplicativo para simular cargas de pico para a tabela e vise uma determinada partição usando a PartitionKey da etapa 2. Essa etapa é diferente para cada aplicativo, mas a simulação deve incluir todas as consultas e operações de armazenamento necessárias. O aplicativo pode precisar ser ajustado para que vise uma única partição.

  4. Examine a taxa de transferência das operações GET ou PUT na tabela.

Para examinar a taxa de transferência, compare os valores reais com o limite especificado de uma única partição em um único servidor. As partições são limitadas a 500 entidades por segundo. Se a taxa de transferência exceder 500 entidades por segundo para uma partição, o servidor poderá ficar excessivamente solicitado em uma configuração de produção. Nesse caso, os valores da PartitionKey podem ser de alta granularidade, não havendo então partições suficientes ou sendo as partições excessivamente grandes. Pode ser necessário modificar o valor da PartitionKey para que as partições possam ser distribuídas entre mais servidores.

O balanceamento de carga na camada da partição ocorre quando uma partição fica excessivamente solicitada, o que significa que a partição, especificamente o servidor da partição, está operando além da meta de escalabilidade. Para armazenamento do Azure, cada partição possui uma meta de escalabilidade de 500 entidades por segundo. O balanceamento de carga também ocorre na camada Sistema de Arquivos Distribuídos ou DFS. O balanceamento de carga na camada DFS lida com carga de E/S e está fora do escopo deste artigo. O balanceamento de carga na camada da partição não ocorre imediatamente após exceder-se a meta de escalabilidade. Em vez disso, o sistema aguarda alguns minutos antes de iniciar o processo de balanceamento de carga. Isso garante que a partição tenha se tornado realmente muito solicitada. Não é necessário preparar as partições com carregamento gerado que aciona o balanceamento de carga, porque o sistema irá realizar automaticamente essa tarefa. Se uma tabela tiver sido preparada com uma determinada carga, é possível que o sistema balanceie as partições com base na carga real, o que resulta em uma distribuição muito diferente das partições. Em vez de preparar partições, você deve cogitar escrever um código que lide com os erros Tempo limite e Servidor ocupado. Tais erros são retornados quando o sistema está realizando o balanceamento de carga. Ao lidar com esses erros usando uma estratégia de repetição, seu aplicativo pode lidar melhor com os picos de carga. As estratégias de repetição são discutidas mais detalhadamente na seção seguinte. Quando ocorre o balanceamento de carga, a partição fica offline por alguns segundos. Durante o período offline, o sistema reatribui a partição para um servidor de partições diferente. É importante observar que seus dados não são armazenados pelos servidores de partições. Em vez disso, os servidores de partições atendem entidades a partr da camada DFS. Como seus dados não são armazenados na camada de partição, mover as partições para diferentes servidores é um processo rápido. Isso limita muito o período de inatividade, se houver, que seu aplicativo possa encontrar.

É importante que seu aplicativo lide com as falhas nas operações de armazenamento, para garantir que você não perca nenhuma atualização de dados. Algumas falhas não exigem uma estratégia de repetição. Por exemplo, as atualizações que retornam um erro "401 Não Autorizado" não se beneficiarão com a repetição da operação, porque é provável que o estado do aplicativo não se altere entre as repetições que tentarão resolver o erro 401. No entanto, certos erros, como Servidor ocupado ou Tempo limite, estão relacionados aos recursos de balanceamento de carga do Azure que fornecem a escalabilidade das tabelas. Quando os nós do armazenamento que atendem as suas entidades se tornarem muito solicitados, o Azure balanceará a carga deslocando partições para outros nós. Durante esse tempo, a partição pode estar inacessível, o que resulta nos erros Servidor ocupado ou Tempo limite. Mais cedo ou mais tarde, a partição será reabilitada e as atualizações podem retomar. Uma estratégia de repetição é apropriada para erros de ocupado e tempo limite. Na maioria dos casos, você pode excluir erros de nível 400 e alguns erros de nível 500 da lógica de repetição, como "501 Não implementado" ou "505 Versão sem suporte" e implementar uma estratégia de repetição para alguns erros de nível 500, como "Servidor ocupado (503)" e "Tempo limite (504)".

Há três estratégias de repetição comuns que você pode usar para seu aplicativo. Segue uma lista dessas estratégias de repetição e suas descrições:

  • Sem Repetição - Não é feita nenhuma tentativa de repetição

  • Retirada Fixa - A operação é repetida N vezes com um valor de retirada constante

  • Retirada Exponencial - A operação é repetida N vezes com um valor de retirada exponencial

A estratégia Sem Repetição é uma forma simples (e evasiva) de lidar com falhas de operações. No entanto, ela não é muito útil. Não impor nenhuma tentativa de repetição coloca riscos óbvios de que dados não sejam armazenados corretamente após operações que apresentarem falha. Portanto, uma estratégia melhor é usar a Retirada Fixa, que fornece a capacidade de repetir operações com a mesma duração da retirada. No entanto, essa estratégia não é otimizada para lidar com tabelas altamente escalonáveis, porque se muitos threads ou processos estiverem aguardando pela mesma duração, podem ocorrer colisões. A estratégia de repetição recomendada é a que usa uma retirada exponencial onde cada tentativa de repetição é maior que a última tentativa. É semelhante ao algoritmo de impedimento de colisão (CA) usado em redes de computador, como Ethernet. A retirada exponencial usa um fator aleatório para fornecer uma variação adicional ao intervalo resultante. O valor da retirada é então restrito aos limites mínimo e máximo. A fórmula seguinte pode ser usada para calcular o próximo valor de retirada usando um algoritmo exponencial:

y = Rand(0.8z, 1.2z)(2x-1

y = Min(zmin + y, zmax

Onde:

z= retirada padrão em milissegundos

zmin = retirada padrão mínima em milissegundos

zmax = retirada padrão máxima em milissegundos

x= número de repetições

y= valor da retirada em milissegundos

Os multiplicadores 0.8 e 1.2 usados na função Rand (aleatória) produzem uma variação aleatória da retirada padrão dentro de ±20% do valor original. O intervalo de ±20% é aceitável para a maioria das estratégias de repetição e impede colisões adicionais. A fórmula pode ser implementada usando 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);


Se você está desenvolvendo seu aplicativo usando a Biblioteca Gerenciada do Azure, é possível aproveitar as políticas de repetição incluídas na Biblioteca de Clientes de Armazenamento. O mecanismo de repetição na biblioteca também permite ampliar a funcionalidade com suas políticas de repetição personalizadas. A classe RetryPolicies no namespace Microsoft.WindowsAzure.StorageClient fornece métodos estáticos que retornam um objeto RetryPolicy. O objeto RetryPolicy é usado em conjunto com o método SaveChangesWithRetries na classe TableServiceContext. A política padrão que um objeto TableServiceContext usa é uma instância de uma classe RetryExponential construída usando os valores RetryPolicies.DefaultClientRetryCount e RetryPolicies.DefaultClientBackoff. O código a seguir mostra como construir uma classe TableServiceContext com um RetryPolicy diferente.

class MyTableServiceContext : TableServiceContext
{
    public MyTableServiceContext(string baseAddress, CloudStorageAccount account)
        : base(baseAddress, account)
    {
        int retryCount = 5; // Default is 3
        var backoff = TimeSpan.FromSeconds(45); // Default is 30 seconds

        RetryPolicy = RetryPolicies.RetryExponential(retryCount, backoff);
    }
    ...
}

O Armazenamento de Tabelas do Azure permite que os aplicativos armazenem um valor enorme de dados porque ele gerencia e reatribui partições através de muitos nós de armazenamento. Você pode usar o particionamento de dados para controlar a escalabilidade da tabela. Planeje antecipadamente ao definir o esquema de uma tabela para garantir o uso de estratégias de particionamento eficientes. Especificamente, analise os requisitos, dados e consultas do aplicativo antes de selecionar valores da PartitionKey. Cada partição pode ser reatribuída a diferentes nós de armazenamento conforme o sistema responde ao tráfego. Use um teste de estresse da partição para garantir que a tabela tenha os valores corretos da PartitionKey. Esse teste permitirá que você reconheça quando as partições estão excessivamente solicitadas e como fazer os ajustes de partição necessários. Para garantir que seu aplicativo lide com erros intermitentes e que seus dados persistam, deve ser usada uma estratégia de repetição com retirada. A política de repetição padrão que a Biblioteca de Clientes de Armazenamento do Azure usa é uma com retirada exponencial que evita colisões e maximiza a taxa de transferência do seu aplicativo.

A Microsoft está realizando uma pesquisa online para saber sua opinião sobre o site do MSDN. Se você optar por participar, a pesquisa online lhe será apresentada quando você sair do site do MSDN.

Deseja participar?
Mostrar:
© 2014 Microsoft