Qual é a maneira recomendada de excluir um grande número de itens do DynamoDB?

111

Estou escrevendo um serviço de registro simples no DynamoDB.

Eu tenho uma tabela de logs que é codificada por um hash user_id e um intervalo de carimbo de data / hora (Unix epoch int).

Quando um usuário do serviço encerra sua conta, preciso deletar todos os itens da tabela, independente do valor do intervalo.

Qual é a maneira recomendada de fazer esse tipo de operação (lembre-se de que pode haver milhões de itens a serem excluídos)?

Minhas opções, tanto quanto posso ver são:

R: Execute uma operação de digitalização, chamando delete em cada item devolvido, até que nenhum item seja deixado

B: Execute uma operação BatchGet, novamente chamando delete em cada item até que nenhum seja deixado

Ambos parecem terríveis para mim, pois levarão muito tempo.

O que eu idealmente quero fazer é chamar LogTable.DeleteItem (user_id) - Sem fornecer o intervalo, e fazer com que ele exclua tudo para mim.

Tyler
fonte

Respostas:

52

O que eu idealmente quero fazer é chamar LogTable.DeleteItem (user_id) - Sem fornecer o intervalo, e fazer com que ele exclua tudo para mim.

De fato, um pedido compreensível; Posso imaginar operações avançadas como essas podem ser adicionadas ao longo do tempo pela equipe da AWS (eles têm um histórico de começar com um conjunto limitado de recursos primeiro e avaliar extensões com base no feedback do cliente), mas aqui está o que você deve fazer para evitar o custo de uma verificação completa, pelo menos:

  1. Use Query em vez de Scan para recuperar todos os itens user_id- isso funciona independentemente da chave primária de hash / intervalo combinada em uso, porque HashKeyValue e RangeKeyCondition são parâmetros separados nesta API e o primeiro visa apenas o valor de Atributo do componente hash do composto chave primária. .

    • Observe que você terá que lidar com a paginação da API de consulta aqui como de costume, consulte o parâmetro ExclusiveStartKey :

      Chave primária do item do qual continuar uma consulta anterior. Uma consulta anterior pode fornecer esse valor como LastEvaluatedKey se essa operação de consulta foi interrompida antes de concluir a consulta; devido ao tamanho do conjunto de resultados ou ao parâmetro Limite. A LastEvaluatedKey pode ser passada de volta em uma nova solicitação de consulta para continuar a operação a partir desse ponto.

  2. Faça um loop em todos os itens devolvidos e facilite o DeleteItem como de costume

    • Atualização : Provavelmente BatchWriteItem é mais apropriado para um caso de uso como este (veja detalhes abaixo).

Atualizar

Conforme destacado por ivant , a operação BatchWriteItem permite que você coloque ou exclua vários itens em várias tabelas em uma única chamada de API [ênfase minha] :

Para fazer upload de um item, você pode usar a API PutItem e para excluir um item, você pode usar a API DeleteItem. No entanto, quando você deseja fazer upload ou excluir grandes quantidades de dados, como fazer upload de grandes quantidades de dados do Amazon Elastic MapReduce (EMR) ou migrar dados de outro banco de dados para o Amazon DynamoDB, esta API oferece uma alternativa eficiente.

Observe que isso ainda tem algumas limitações relevantes, principalmente:

  • Máximo de operações em uma única solicitação - você pode especificar um total de até 25 operações de inserção ou exclusão; no entanto, o tamanho total da solicitação não pode exceder 1 MB (a carga útil HTTP).

  • Não é uma operação atômica - as operações individuais especificadas em um BatchWriteItem são atômicas; no entanto, BatchWriteItem como um todo é uma operação de "melhor esforço" e não uma operação atômica. Ou seja, em uma solicitação BatchWriteItem, algumas operações podem ser bem-sucedidas e outras podem falhar. [...]

No entanto, isso obviamente oferece um ganho potencialmente significativo para casos de uso como o que temos em mãos.

Steffen Opel
fonte
4
Acho que faria sentido usar a exclusão de lote para a segunda etapa (é "mascarado" como uma operação de gravação em lote )
ivant
1
@ivant - muito obrigado pela dica, essa funcionalidade de exclusão "mascarada" de BatchWriteItem de fato me escapou naquela época; Eu atualizei a resposta de acordo.
Steffen Opel
para exclusão com BatchWriteItemitens precisam ser especificados viaTableWriteItems
Neil
1
O link para BatchWriteItem agora é docs.aws.amazon.com/amazondynamodb/latest/APIReference/…
Tony
3
Sei que isso é antigo e o OP não mencionou um SDK de linguagem específico, mas em Python há um alto nível batch_writer()como parte da boto3.resource.TableAPI que "tratará automaticamente o armazenamento em buffer e o envio de itens em lotes. Além disso, o criador de lotes irá também manipula automaticamente quaisquer itens não processados ​​e os reenvia conforme necessário ", ou seja, é um invólucro em torno do BatchWriteItem que gerencia as partes irritantes. boto3.amazonaws.com/v1/documentation/api/latest/reference/…
Davos
46

De acordo com a documentação do DynamoDB, você pode simplesmente deletar a tabela inteira.

Ver abaixo:

"Excluir uma tabela inteira é significativamente mais eficiente do que remover itens um por um, o que essencialmente duplica a capacidade de gravação, pois você faz tantas operações de exclusão quanto de colocação"

Se você deseja excluir apenas um subconjunto de seus dados, você pode fazer tabelas separadas para cada mês, ano ou similar. Desta forma, você pode remover o "mês passado" e manter o resto de seus dados intactos.

É assim que você exclui uma tabela em Java usando o SDK da AWS:

DeleteTableRequest deleteTableRequest = new DeleteTableRequest()
  .withTableName(tableName);
DeleteTableResult result = client.deleteTable(deleteTableRequest);
Jonathan
fonte
8
Eu também gosto dessa resposta, mas cuidado: isso pode criar muitas tabelas em seu sistema e pagamos por provisão de tabela. Portanto, você precisa reduzir o provisionamento após o final do mês (se sua tabela for por mês) enquanto esta tabela não é excluída.
Sergio MC Figueiredo
2
concordo com esta resposta, ela se aplica se você precisar excluir todos os registros da tabela, mas aqui o questionador deseja excluir as entradas da base de usuários e não a tabela inteira.
Ihtsham Minhas
1
Ter uma mesa separada para cada usuário seria caro devido ao preço do DynamoDB. Uma mesa por mês pioraria as coisas. Esta é claramente uma resposta para um problema diferente e muito específico.
André Werlang
11
Excluir a tabela também pode não ser uma opção atraente se você usar o provisionamento automatizado, como CloudFormation, para gerenciar sua tabela como parte de uma pilha. Não estou ciente de uma maneira simples de fazer o CloudFormation recriar uma tabela que você excluiu manualmente.
brabster
2
Essa abordagem leva um pouco de tempo para excluir e recriar (quando necessário) a tabela, tornando-a indisponível o tempo todo. A questão afirma claramente a remoção de dados do usuário, o que seria impraticável dividir em tabelas separadas por usuário.
André Werlang
13

Se você deseja excluir itens após algum tempo, por exemplo, após um mês, basta usar a opção Time To Live. Ele vai não contar unidades de gravação.

No seu caso, eu adicionaria ttl quando os logs expiram e os deixaria depois que um usuário fosse excluído. O TTL garantiria que os logs fossem removidos eventualmente.

Quando Time To Live está habilitado em uma tabela, um trabalho em segundo plano verifica o atributo TTL dos itens para ver se eles expiraram.

O DynamoDB normalmente exclui itens expirados em até 48 horas após a expiração. A duração exata na qual um item é realmente excluído após a expiração é específica para a natureza da carga de trabalho e o tamanho da tabela. Os itens que expiraram e não foram excluídos ainda aparecerão nas leituras, consultas e varreduras. Esses itens ainda podem ser atualizados e as atualizações bem-sucedidas para alterar ou remover o atributo de expiração serão respeitadas.

https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/howitworks-ttl.html

Lukas Liesis
fonte
adicionar TTL é uma "atualização" (operação de gravação). Não tenho certeza se há algum ganho em fazer uma "atualização" em vez de uma "exclusão".
Tomer
você pode ter esses dados inseridos com a gravação original e atualizados com qualquer outra ação de atualização. Obviamente, não é uma opção se você tiver muitos dados e quiser excluí-los. Mas esta é uma opção válida para os casos em que você pode ter ttl para os dados que você inserir ou atualizar.
Lukas Liesis
1
Eu concordo, se já houver TTL configurado e a limpeza pode esperar até 48 horas, essa é definitivamente a opção ideal. Minhas desculpas se não fui claro.
Tomer
4

A resposta a esta pergunta depende do número de itens e seu tamanho e seu orçamento. Depende disso, temos os seguintes 3 casos:

1- O número de itens e o tamanho dos itens na tabela não são muito. então, como Steffen Opel disse, você pode usar Query em vez de Scan para recuperar todos os itens para user_id e, em seguida, fazer um loop em todos os itens devolvidos e facilitar DeleteItemouBatchWriteItem. Mas tenha em mente que você pode queimar muita capacidade de processamento aqui. Por exemplo, considere uma situação em que você precisa excluir 1000 itens de uma tabela do DynamoDB. Suponha que cada item tenha 1 KB de tamanho, resultando em cerca de 1 MB de dados. Essa tarefa de exclusão em massa exigirá um total de 2.000 unidades de capacidade de gravação para consulta e exclusão. Para executar esse carregamento de dados em 10 segundos (o que nem mesmo é considerado tão rápido em alguns aplicativos), você precisaria definir a taxa de transferência de gravação provisionada da tabela para 200 unidades de capacidade de gravação. Como você pode ver, é possível usar desta forma se for para menos número de itens ou itens de tamanho pequeno.

2- Temos muitos itens ou itens muito grandes na mesa e podemos armazená-los de acordo com o tempo em diferentes tabelas. Então, como Jonathan Said, você pode simplesmente deletar a tabela. isso é muito melhor, mas não acho que corresponda ao seu caso. Como você deseja deletar todos os dados dos usuários não importa qual seja o momento de criação dos logs, então neste caso você não pode deletar uma determinada tabela. se você quiser ter uma mesa separada para cada usuário, então eu acho que se o número de usuários for alto, é muito caro e não é prático para o seu caso.

3- Se você tem muitos dados e não consegue dividir seus dados quentes e frios em tabelas diferentes e precisa deletar em grande escala com frequência, infelizmente o DynamoDB não é uma boa opção para você. Pode ficar mais caro ou muito lento (depende do seu orçamento). Nestes casos, recomendo encontrar outro banco de dados para seus dados.

Iman Sedighi
fonte
0

Minha abordagem para excluir todas as linhas de uma tabela i DynamoDb é apenas puxar todas as linhas da tabela, usando DynamoDbs ScanAsync e, em seguida, alimentar a lista de resultados para DynamoDbs AddDeleteItems. O código abaixo em C # funciona bem para mim.

        public async Task DeleteAllReadModelEntitiesInTable()
    {
        List<ReadModelEntity> readModels;

        var conditions = new List<ScanCondition>();
        readModels = await _context.ScanAsync<ReadModelEntity>(conditions).GetRemainingAsync();

        var batchWork = _context.CreateBatchWrite<ReadModelEntity>();
        batchWork.AddDeleteItems(readModels);
        await batchWork.ExecuteAsync();
    }

Nota: Excluir a tabela e, em seguida, recriá-la novamente do console da web pode causar problemas se usar YAML / CloudFront para criar a tabela.

Maomé
fonte
0

Não temos a opção de truncar tabelas de dínamo. temos que largar a mesa e criar novamente. As cobranças do DynamoDB são baseadas em ReadCapacityUnits e WriteCapacityUnits. Se excluirmos todos os itens usando a função BatchWriteItem, ele usará WriteCapacityUnits. Portanto, é melhor excluir registros específicos ou excluir a tabela e começar novamente.

Shraavan Hebbar
fonte