research

Testamos 65 restaurações do DynamoDB. A 66ª? Imprevisível.

Jeff Reynar
Testamos 65 restaurações do DynamoDB. A 66ª? Imprevisível.

Se você está escrevendo um plano de recuperação que envolve o DynamoDB, precisa saber quanto tempo uma restauração vai levar, mas não existe boa documentação sobre isso. A AWS diz que “o tempo que leva para restaurar uma tabela varia de acordo com múltiplos fatores” e que “os tempos de restauração para um ponto no tempo nem sempre estão diretamente correlacionados ao tamanho da tabela”, e então se recusa a estimar. O único número que publicam vem de um artigo de suporte atualizado pela última vez em maio de 2026: uma restauração para um ponto no tempo “leva pelo menos 20 minutos, independentemente do tamanho da tabela”. Quatro parágrafos depois, o mesmo artigo diz: “Não é possível calcular com antecedência o tempo exato de restauração da tabela.”

Restauramos nossas tabelas de produção sessenta e cinco vezes para descobrir a verdade. O piso de 20 minutos está errado por um fator de cinco. A AWS recomenda excluir índices secundários para tornar uma restauração mais rápida, e fazer isso deixou a recuperação de seis a nove vezes mais lenta. A mesma tabela restaurada duas vezes pode variar por um fator de três.

Como medimos

Cada execução dispara uma restauração para um ponto no tempo com restore-table-to-point-in-time, para uma tabela nova, na mesma região e conta da origem. As dez tabelas são sob demanda (PAY_PER_REQUEST) em us-east-1, em uma única conta, restauradas entre 10 e 12 de setembro de 2026. Uma tabela provisionada pode se comportar de forma diferente e não testamos nenhuma.

O cronômetro corre da chamada da API até o momento em que a tabela e cada um dos seus índices secundários reporta ACTIVE. Isso importa, porque é a métrica mais lenta entre as duas óbvias e é a que corresponde ao momento em que a aplicação volta a funcionar por completo.

Esses tempos excluem a validação. Depois de cada execução, contamos as duas tabelas com leituras consistentes e comparamos itens amostrados, algo que ninguém em recuperação de um incidente faz antes de declarar sucesso. Todas as sessenta e cinco restaurações tiveram êxito. As diferenças que encontramos entre uma cópia e sua origem eram a tabela ativa continuando a receber gravações, não perda de dados.

A sondagem (polling) pode acrescentar até um intervalo à leitura. Os primeiros testes consultavam describe-table a cada 30 segundos; todas as execuções posteriores consultavam a cada um ou cinco segundos. Trinta segundos é relevante numa restauração de quatro minutos e é ruído numa de cinquenta minutos, então os números de 30 segundos estão marcados com asterisco na tabela abaixo, e toda tabela pequena foi reexecutada com sondagem de um segundo. Onde os dois intervalos mediram a mesma tabela, os resultados concordaram: a tabela de 834 MB deu 9,7, 8,2, 8,2, 8,2 a 30 segundos e 8,3, 8,3, 8,2, 8,5 a um segundo.

As medições

Dez tabelas, tamanhos conforme reportados por describe-table, tempos para uma restauração completa.

TamanhoItensÍndicesRestauração
12,1 MB46933,6, 3,7, 4,6* min
18,5 MB12.80093,9, 5,1*, 6,6 min
76,1 MB204.48745,1, 5,1*, 5,1 min
100,9 MB41.62114,3, 5,0, 5,6* min
165,6 MB202.73744,9, 5,6*, 6,4 min
204,3 MB241.20415,1*, 5,3, 6,0 min
691,2 MB186.13827,8 a 12,1 min, dezoito execuções
834,2 MB223.93806,7 a 20,9 min, vinte e cinco execuções
3,09 GB10.567.744251,8*, 61,7* min
16,24 GB8.689.000692,9*, 91,4 min

* Sondado a cada 30 segundos, então a leitura pode estar até 30 segundos acima do real. Nas restaurações longas marcadas, isso é menos de 1% do total. As faixas de 691 MB e 834 MB também incluem o lote de 30 segundos, uma execução e quatro respectivamente; os extremos de ambas as linhas vêm de sondagem mais fina.

O piso de 20 minutos não existe

A restauração completa mais rápida levou 3 minutos e 36 segundos, medidos com sondagem de um segundo. Seis das dez tabelas terminaram em menos de sete minutos, índices incluídos. Seja qual for a origem do número de 20 minutos, não é um piso confiável para planejamento, e se suas tabelas forem pequenas você está reservando de quatro a cinco vezes mais tempo do que precisa.

A orientação publicada erra nas duas direções. O guia de PITR da Dynobase, que aparece entre os primeiros resultados de busca sobre o assunto, diz que “independentemente do tamanho da tabela, a restauração leva apenas alguns segundos”. Nossa restauração mais rápida foi 3 minutos e 36 segundos, e a mais lenta foi 92,9 minutos, e o tamanho da tabela é uma das duas variáveis que efetivamente preveem o tempo.

Restaurar os dados primeiro e os índices depois é mais lento

A orientação da AWS é que “as restaurações podem ser mais rápidas e mais econômicas se você excluir alguns ou todos os índices da criação na tabela restaurada”, e o artigo de suporte apresenta isso como uma sequência: excluir os índices, adicioná-los depois que a restauração terminar.

Testamos as duas condições em uma tabela, 12 MB com três índices secundários globais, ambos os lados com sondagem de 30 segundos, um viés compartilhado pelos dois lados e pequeno diante da diferença que eles mostram.

Tabela ACTIVETotalmente recuperada
Restauração completa4,6 min4,6 min, índices incluídos
GSIs excluídos2,6 min28,5 min

A tabela voltou 44% mais rápido e ficou totalmente operacional cerca de seis vezes depois, porque o DynamoDB cria os índices excluídos um de cada vez, posteriormente. Se sua aplicação faz leituras por um índice secundário, uma tabela sem ele não é uma tabela recuperada.

A objeção óbvia é que uma tabela maior se comportaria de forma diferente, porque a restauração dos dados passaria a dominar e os índices deixariam de importar. Então repetimos o teste em uma tabela de 3,09 GB com 10,6 milhões de itens e dois índices.

Tabela ACTIVETotalmente recuperada
Restauração completa56,8 min56,8 min, índices incluídos
GSIs excluídos46,4 min431,5 min, ou 7,2 horas

Piora com o tamanho, não melhora. A penalidade cresceu de 6,2x para 7,6x, e a vantagem inicial encolheu de 43% para 18%. Os índices foram construídos um após o outro nas duas vezes: 209 e 188 minutos na primeira execução, 198 e 175 na segunda.

Cada número dessa tabela é a média de duas execuções. As restaurações completas levaram 51,8 e 61,7 minutos, as restaurações com índices excluídos, 443,3 e 419,7. Pegue a restauração completa mais rápida e a com índices excluídos mais lenta, o que um único par de execuções poderia muito bem ter entregado, e o mesmo experimento passa a mostrar 8,6x.

O que ainda não testamos: excluir alguns índices em vez de todos, e índices locais ou vetoriais.

Uma parte não depende da nossa medição de forma alguma. RestoreTableToPointInTime aceita tanto LocalSecondaryIndexOverride quanto uma versão global, então você pode excluir índices secundários locais na restauração da mesma forma. UpdateTable não tem um parâmetro equivalente: ele aceita GlobalSecondaryIndexUpdates e VectorIndexUpdates, e nada para LSIs, porque um índice secundário local só pode existir a partir do momento em que a tabela é criada. Então “você pode adicionar índices depois que a restauração terminar” vale para índices globais e não vale para os locais. Excluir um LSI na restauração e a única forma de recuperá-lo é restaurar de novo.

Quatro ao mesmo tempo deixaram o pior caso 12% mais lento, e existe um teto de 50

Você tem sorte se sua recuperação exigir restaurar apenas uma tabela. Executamos quatro restaurações simultaneamente. Comparadas com as mesmas tabelas rodando isoladas, elas terminaram 12%, 9%, 9% e 1% mais lentas. O caminho dos dados não serializa.

Isso foi medido com quatro. Não diz nada sobre quarenta, e existe um teto documentado de quantas você pode executar no total. Da referência da API:

Qualquer número de usuários pode executar até 50 restaurações simultâneas (de qualquer tipo) em uma determinada conta.

Dois outros limites são descritos na mesma página. Até 500 operações simultâneas de tabela por conta, contando restaurações entre elas, e até 250 solicitações simultâneas ao criar tabelas com um ou mais índices secundários, o que é o caso de toda restauração de uma tabela indexada. A AWS acrescenta que, quando as especificações de tabela ou índice são complexas, “o DynamoDB pode reduzir temporariamente o número de operações simultâneas”.

Se você tiver mais de 50 tabelas para trazer de volta, elas precisam ser restauradas em ondas. Seu piso não é a tabela mais lenta. É a tabela mais lenta da primeira onda somada à mais lenta da próxima, e assim por diante. Comece pelas tabelas maiores, para que uma restauração longa rode enquanto as curtas passam pelas vagas restantes. Calcule quantas ondas você precisa antes de anotar um tempo de recuperação, e não presuma que os 9% se mantêm em cinquenta, porque não medimos isso.

A mesma tabela restaurada duas vezes pode variar em 3x

Restauramos uma tabela de 834 MB vinte e cinco vezes. Vinte e três dessas execuções ficaram entre 6,7 e 9,3 minutos. Uma ficou em 9,7. Uma ficou em 20,9.

Uma tabela de 691 MB, dezoito execuções, tem o mesmo problema em escala menor: catorze execuções dentro de 7,8 a 8,9 minutos, depois 9,7, 9,8, 11,9 e 12,1.

Não é um fenômeno de tabelas grandes. Uma tabela de 18 MB foi restaurada em 3,9 minutos numa noite e em 6,6 minutos dois dias depois, ambas com sondagem de um segundo, uma diferença de 1,7x numa tabela que cabe na memória.

A dispersão sobrevive mesmo mantendo o protocolo fixo. Vinte dessas execuções foram feitas como uma série controlada: dez por tabela, alternadas, cada uma restaurando para um ponto exatamente 24 horas antes, uma atrás da outra ao longo de três horas. Dezenove das vinte ficaram entre 8,0 e 9,3 minutos. Uma levou 12,05.

Também não é um período lento que dá para simplesmente esperar passar. Aquela execução de 12,05 começou às 12h52. A outra tabela foi restaurada às 12h44 em 8,28 minutos e de novo às 13h04 em 8,01.

Isso não é uma curva de sino com uma cauda. É um agrupamento apertado mais uma execução ocasional que fica fora dele. Planejar com uma média e uma margem pressupõe a primeira forma. A execução lenta não é a média mais 20%, é duas vezes e meia a mediana, e chega sem aviso.

O número de índices não explica nada disso. A tabela com zero índices produziu o outlier de 3x, e a tabela com seis índices foi a coisa mais estável que medimos.

Nada mais que registramos explica isso também: nem o tamanho, nem a quantidade de itens, nem a hora do dia, nem o quão distante no passado ficava o ponto de restauração. O candidato óbvio é a carga na frota subjacente, que uma conta de cliente não consegue enxergar.

Ir mais longe no passado não deixa a restauração mais lenta

A recuperação para um ponto no tempo cobre 35 dias, e a intuição é que buscar mais longe no passado poderia levar mais tempo. Restauramos a mesma tabela de 834 MB para três pontos dentro dessa janela, e repetimos toda a sequência uma hora depois.

Ponto de restauraçãoPrimeira passagemSegunda passagem
1 hora atrás8,68 min20,94 min
7 dias atrás8,51 min7,83 min
34 dias atrás7,11 min6,74 min

Nas duas vezes, o ponto de restauração mais antigo foi o mais rápido. Ir um mês para trás não deixa a restauração mais lenta, então você pode planejar a recuperação sem se preocupar com onde na janela o incidente ocorreu.

A leitura inversa é tentadora e não podemos sustentá-la. Nas duas passagens, o ponto de restauração mais recente veio primeiro, então idade e posição no lote são a mesma variável aqui, e nunca invertemos a ordem para separá-las. O 20,94 também é a execução mais lenta entre as vinte e cinco daquela tabela, o que faz dele o outlier da seção anterior, não uma medição de outra coisa.

Um terceiro problema é específico dessa tabela. É uma tabela de log, então ela cresce, e um ponto de restauração mais antigo reconstrói uma cópia menor dela. Isso empurraria exatamente na direção que observamos. Também não conseguimos isolar esse efeito, porque DescribeTable reporta zero bytes e zero itens numa tabela recém-restaurada, então o tamanho da cópia em si nunca fica registrado. As duas passagens concordarem na ordenação é sugestivo, mas sugestivo não é prova.

Um modelo prevê a tabela. Não consegue prever a restauração.

Observe as duas maiores tabelas. Uma tem 3,09 GB com 10,6 milhões de itens e restaura em 51,8 e 61,7 minutos. A outra tem 16,24 GB com 8,7 milhões de itens e leva 92,9 e 91,4. Mais itens, menos tempo.

A vazão nas três maiores varia de 51 a 182 MB por minuto, e de 27.000 a 204.000 itens por minuto. Nenhum número isolado que você consiga ler do describe-table te dá uma taxa utilizável.

Dois deles juntos dão, e melhor do que esperávamos. Ajustando minutos em função de tamanho da tabela e quantidade de itens nas dez tabelas originais:

minutos ≈ 4.6 + 0.0033 × MB + 4.0 × milhões de itens

Um ajuste com dez pontos e três parâmetros vale muito pouco por si só, e o que vem a seguir não é uma validação dele. As duas tabelas estavam no ajuste, com duas execuções cada. Restaurá-las mais 43 vezes testa algo mais restrito do que generalização: se duas execuções eram suficientes para encontrar a mediana que esses dois pontos representavam.

O modelo dizMediana das execuçõesErro
834 MB, 223.938 itens, 25 execuções8,25 min8,29 min2 segundos
691 MB, 186.138 itens, 18 execuções7,63 min8,73 min1,1 min

O modelo acertou a mediana de vinte e cinco restaurações com margem de dois segundos, e errou por 2,5x na restauração que efetivamente obtivemos. Essa mesma tabela produziu uma execução de 20,94 minutos contra uma previsão de 8,25.

Esse é todo o problema de planejar uma recuperação com base em uma fórmula. Prever a média de uma distribuição é uma tarefa diferente de prever a amostra que você está prestes a extrair, e uma recuperação extrai exatamente uma.

A AWS realmente explica o mecanismo, e a explicação usa um número que você não consegue ver. O artigo de suporte deles diz que “se o DynamoDB distribuir os dados da sua tabela de forma uniforme, o tempo de restauração é proporcional à maior partição individual em quantidade de itens.” Note a condicional: a regra que eles dão é enunciada para tabelas sem distorção (skew), e distorção é exatamente o caso sobre o qual eles pedem para você se preocupar. Não existe API que reporte quantas partições físicas uma tabela tem ou quais itens vivem em qual partição. Então a única orientação publicada é expressa em uma grandeza que nenhum cliente consegue observar, o que ajuda a explicar por que ninguém publica medições.

Você pode contar suas chaves de partição e ver se alguma concentra muito mais itens do que as outras, o que já vale a pena saber por si só, já que é a linguagem em que a própria orientação da AWS sobre distorção é escrita. Ainda assim isso não te dá o número deles. Quais chaves compartilham uma partição física, e quantas partições existem no total, é opaco, então contar chaves te fala sobre chaves quentes, não sobre carga de partição. A conhecida regra de dedo de 10 GB por partição tem a mesma lacuna: ela te dá um limite inferior de quantas partições existem, nunca a quantidade de itens da maior delas.

Uma coisa que parece alarmante e não é

Toda tabela restaurada voltou com menos linhas do que a tabela ativa. Na tabela de 16 GB, a diferença foi de 26.176 itens.

Isso não é perda de dados. São as gravações que a tabela ativa recebeu entre o ponto de restauração e o momento em que fizemos a contagem, e é a confirmação de que o carimbo de tempo foi respeitado. Uma cópia restaurada que batesse exatamente com a tabela ativa significaria que o ponto de restauração foi ignorado.

O que colocar no runbook

Meça suas próprias tabelas. Nada aqui se transfere diretamente, porque os números dependem de como seus dados estão distribuídos entre partições, algo que você não consegue inspecionar, e as taxas variam por um fator de três entre nossas próprias tabelas.

Cronometre até todos os índices ficarem ACTIVE, não até a tabela ficar ACTIVE. Isso acontece junto numa restauração completa, então o número é o mesmo, e continua correto se isso um dia mudar.

Não planeje com base em um multiplicador. Dobrar o tempo modelado cobre nove das nossas dez tabelas e erra justamente a que importa: a execução de 20,9 minutos foi 2,54x o valor modelado de 8,25. Cobrir esse caso exige 2,6x, e não podemos garantir que 2,6x seja suficiente, porque vimos três outliers nas quarenta e três execuções dessas duas tabelas, e uma série mais longa pode muito bem encontrar um caso pior. Acompanhe a pior execução observada em vez de uma média mais margem.

Não exclua índices para ganhar velocidade. Nunca vimos isso reduzir o tempo total de restauração, em nenhuma das duas tabelas em que testamos, apesar do que a AWS diz.

Espere que a tabela restaurada seja menor do que a origem, e verifique se a diferença corresponde ao seu volume de gravações desde o ponto de restauração, em vez de tratá-la como corrupção.

Simule, e simule de novo quando a tabela mudar

Cada número acima veio de restaurar tabelas reais e cronometrá-las, o único método que produziu algo confiável. Ele também está disponível para você, exige uma restauração, e responde à pergunta para seus dados, não para os nossos.

A própria AWS já orienta a fazer isso, no mesmo artigo de onde vem o número de 20 minutos: “Documente regularmente seu tempo médio de conclusão de restauração”, e então calcule o que esses tempos representam para o seu RTO. Faça isso, mas acompanhe uma estatística diferente. A média é o único número que um outlier quase não move.

Simule suas tabelas grandes com regularidade. As pequenas terminam em minutos e as margens de erro não importam. As grandes são onde uma estimativa de recuperação é crítica, e onde estar 2,5x errado muda o que você diz às pessoas durante um incidente. Rode cada uma delas mais de uma vez, porque uma única simulação te dá uma amostra de uma distribuição cuja característica interessante é justamente a cauda.

Simule de novo quando uma tabela crescer. Os dois termos que ajustam nossos dados escalam com o tamanho da tabela, então uma tabela que dobrou de tamanho desde a última simulação tem uma resposta diferente, e a simulação é o único lugar onde essa resposta existe.

Simule de novo quando alguém adicionar um índice. O número de índices não mudou nossos tempos de restauração, mas isso não é motivo para pular esse passo. Adicionar um índice secundário global muda o que “recuperado” significa, porque a aplicação só está totalmente operacional quando todo índice reporta ACTIVE, e muda o quanto a estratégia de exclusão te prejudicaria caso você planejasse usá-la. Testamos até nove índices em dez tabelas de uma única conta, o que não é suficiente para garantir nada sobre as suas.

Simule a recuperação, não a tabela. Cronometre toda a sequência que você de fato executaria, incluindo as tabelas que esperam atrás do teto de 50 restaurações, e anote a execução mais lenta que você já viu, em vez daquela que você gostaria de citar.