Wie wird empfohlen, eine große Anzahl von Elementen aus DynamoDB zu löschen?

110

Ich schreibe einen einfachen Protokollierungsdienst in DynamoDB.

Ich habe eine Protokolltabelle, die von einem user_id-Hash und einem Zeitstempelbereich (Unix epoch int) verschlüsselt wird.

Wenn ein Benutzer des Dienstes sein Konto kündigt, muss ich alle Elemente in der Tabelle löschen, unabhängig vom Bereichswert.

Was ist die empfohlene Methode für diese Art von Operation (wenn Sie bedenken, dass möglicherweise Millionen von Elementen gelöscht werden müssen)?

Soweit ich sehen kann, sind meine Optionen:

A: Führen Sie einen Scanvorgang durch und rufen Sie bei jedem zurückgegebenen Artikel die Option "Löschen" auf, bis keine Artikel mehr übrig sind

B: Führen Sie eine BatchGet-Operation aus und rufen Sie erneut delete für jedes Element auf, bis keine mehr übrig sind

Beide sehen für mich schrecklich aus, da sie lange dauern werden.

Im Idealfall möchte ich LogTable.DeleteItem (user_id) aufrufen - ohne den Bereich anzugeben und alles für mich löschen zu lassen.

Tyler
quelle

Antworten:

52

Im Idealfall möchte ich LogTable.DeleteItem (user_id) aufrufen - ohne den Bereich anzugeben und alles für mich löschen zu lassen.

Eine verständliche Bitte; Ich kann mir vorstellen, dass solche fortgeschrittenen Vorgänge vom AWS-Team im Laufe der Zeit hinzugefügt werden (sie haben in der Vergangenheit zunächst mit einem begrenzten Funktionsumfang begonnen und Erweiterungen basierend auf Kundenfeedback bewertet), aber hier ist, was Sie tun sollten, um die Kosten für zu vermeiden mindestens ein vollständiger Scan:

  1. Verwenden Sie " Abfrage" anstelle von " Scannen" , um alle Elemente abzurufen. user_idDies funktioniert unabhängig vom verwendeten kombinierten Hash / Range-Primärschlüssel, da HashKeyValue und RangeKeyCondition separate Parameter in dieser API sind und erstere nur auf den Attributwert der Hash-Komponente des Verbundwerkstoffs abzielen Primärschlüssel. .

    • Bitte beachten Sie, dass Sie sich hier wie gewohnt mit dem Paging der Abfrage-API befassen müssen. Weitere Informationen finden Sie im Parameter ExclusiveStartKey :

      Primärschlüssel des Elements, von dem aus eine frühere Abfrage fortgesetzt werden soll. Eine frühere Abfrage kann diesen Wert als LastEvalencedKey bereitstellen, wenn dieser Abfragevorgang vor Abschluss der Abfrage unterbrochen wurde. entweder aufgrund der Größe der Ergebnismenge oder des Parameters Limit. Der LastEvalencedKey kann in einer neuen Abfrageanforderung zurückgegeben werden, um den Vorgang von diesem Punkt an fortzusetzen.

  2. Durchlaufen Sie alle zurückgegebenen Artikel und erleichtern Sie DeleteItem wie gewohnt

    • Update : Höchstwahrscheinlich ist BatchWriteItem für einen Anwendungsfall wie diesen besser geeignet (Details siehe unten).

Aktualisieren

Wie von ivant hervorgehoben , können Sie mit der BatchWriteItem- Operation mehrere Elemente in mehreren Tabellen in einem einzigen API-Aufruf ablegen oder löschen [Schwerpunkt Mine] :

Um ein Element hochzuladen, können Sie die PutItem-API verwenden und um ein Element zu löschen, können Sie die DeleteItem-API verwenden. Wenn Sie jedoch große Datenmengen hochladen oder löschen möchten, z. B. große Datenmengen von Amazon Elastic MapReduce (EMR) hochladen oder Daten aus einer anderen Datenbank in Amazon DynamoDB migrieren möchten, bietet diese API eine effiziente Alternative.

Bitte beachten Sie, dass dies noch einige relevante Einschränkungen aufweist, insbesondere:

  • Maximale Operationen in einer einzelnen Anforderung - Sie können insgesamt bis zu 25 Put- oder Löschoperationen angeben. Die Gesamtanforderungsgröße darf jedoch 1 MB (die HTTP-Nutzdaten) nicht überschreiten.

  • Keine atomare Operation - Einzelne Operationen, die in einem BatchWriteItem angegeben sind, sind atomar. BatchWriteItem als Ganzes ist jedoch eine "Best-Effort" -Operation und keine atomare Operation. Das heißt, in einer BatchWriteItem-Anforderung sind einige Vorgänge möglicherweise erfolgreich und andere schlagen möglicherweise fehl. [...]

Dies bietet jedoch offensichtlich einen potenziell signifikanten Gewinn für Anwendungsfälle wie den vorliegenden.

Steffen Opel
quelle
4
Ich denke, es wäre sinnvoll, Batch-Löschung für den zweiten Schritt zu verwenden (es ist als Batch-Schreibvorgang "maskiert" )
ivant
1
@ivant - vielen Dank für den Hinweis, diese "maskierte" Löschfunktion von BatchWriteItem ist mir damals tatsächlich entgangen; Ich habe die Antwort entsprechend aktualisiert.
Steffen Opel
Zum Löschen mit BatchWriteItemElementen muss überTableWriteItems
Neil
1
Der Link zu BatchWriteItem lautet jetzt docs.aws.amazon.com/amazondynamodb/latest/APIReference/…
Tony
3
Mir ist klar, dass dies alt ist und das OP kein bestimmtes Sprach-SDK erwähnt hat, aber in Python gibt es eine hohe Ebene batch_writer()als Teil der boto3.resource.TableAPI, die "das Puffern und Senden von Elementen in Stapeln automatisch übernimmt. Außerdem wird der Stapelschreiber dies tun." Behandeln Sie auch unverarbeitete Elemente automatisch und senden Sie sie nach Bedarf erneut. "Das heißt, es ist ein Wrapper um BatchWriteItem, der die lästigen Teile verwaltet. boto3.amazonaws.com/v1/documentation/api/latest/reference/…
Davos
45

Gemäß der DynamoDB-Dokumentation können Sie einfach die vollständige Tabelle löschen.

Siehe unten:

"Das Löschen einer gesamten Tabelle ist wesentlich effizienter als das Entfernen von Elementen nacheinander. Dadurch wird der Schreibdurchsatz im Wesentlichen verdoppelt, da Sie so viele Löschvorgänge wie Put-Vorgänge ausführen."

Wenn Sie nur eine Teilmenge Ihrer Daten löschen möchten, können Sie für jeden Monat, jedes Jahr oder ähnliches separate Tabellen erstellen. Auf diese Weise können Sie "letzten Monat" entfernen und den Rest Ihrer Daten intakt halten.

So löschen Sie eine Tabelle in Java mit dem AWS SDK:

DeleteTableRequest deleteTableRequest = new DeleteTableRequest()
  .withTableName(tableName);
DeleteTableResult result = client.deleteTable(deleteTableRequest);
Jonathan
quelle
8
Ich mag diese Antwort auch, aber Vorsicht: Dies könnte viele Tabellen in Ihrem System erstellen und wir zahlen pro Tabellenbereitstellung. Daher müssen Sie die Bereitstellung nach Monatsende reduzieren (wenn Ihre Tabelle pro Monat ist), während diese Tabelle nicht gelöscht wird.
Sergio MC Figueiredo
2
Stimmen Sie dieser Antwort zu. Sie wird angewendet, wenn Sie alle Datensätze aus der Tabelle löschen müssen. Hier möchte der Fragesteller jedoch die Benutzerbasiseinträge löschen, nicht die gesamte Tabelle.
Ihtsham Minhas
1
Eine separate Tabellentabelle für jeden Benutzer wäre angesichts der DynamoDB-Preise teuer. Ein Tisch pro Monat würde die Sache tatsächlich noch schlimmer machen. Dies ist eindeutig eine Antwort auf ein anderes, sehr spezifisches Problem.
André Werlang
11
Das Löschen der Tabelle ist möglicherweise auch keine attraktive Option, wenn Sie eine automatisierte Bereitstellung wie CloudFormation verwenden, um Ihre Tabelle als Teil eines Stapels zu verwalten. Mir ist keine einfache Möglichkeit bekannt, mit CloudFormation eine Tabelle neu zu erstellen, die Sie manuell gelöscht haben.
Brabster
2
Dieser Ansatz benötigt einige Zeit, um die Tabelle zu löschen und (bei Bedarf) neu zu erstellen, sodass sie während der gesamten Zeit nicht verfügbar ist. In der Frage wird eindeutig angegeben, dass Benutzerdaten entfernt werden, was eine unpraktische Aufteilung in separate Benutzertabellen wäre.
André Werlang
13

Wenn Sie Elemente nach einiger Zeit löschen möchten, z. B. nach einem Monat, verwenden Sie einfach die Option Time To Live. Schreibeinheiten werden nicht gezählt.

In Ihrem Fall würde ich ttl hinzufügen, wenn Protokolle ablaufen, und diese belassen, nachdem ein Benutzer gelöscht wurde. TTL würde sicherstellen, dass Protokolle schließlich entfernt werden.

Wenn Time To Live für eine Tabelle aktiviert ist, überprüft ein Hintergrundjob das TTL-Attribut von Elementen, um festzustellen, ob sie abgelaufen sind.

DynamoDB löscht abgelaufene Elemente normalerweise innerhalb von 48 Stunden nach Ablauf. Die genaue Dauer, innerhalb derer ein Element nach Ablauf tatsächlich gelöscht wird, hängt von der Art der Arbeitslast und der Größe der Tabelle ab. Elemente, die abgelaufen sind und nicht gelöscht wurden, werden weiterhin in Lesevorgängen, Abfragen und Scans angezeigt. Diese Elemente können weiterhin aktualisiert werden, und erfolgreiche Aktualisierungen zum Ändern oder Entfernen des Ablaufattributs werden berücksichtigt.

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

Lukas Liesis
quelle
Das Hinzufügen von TTL ist ein "Update" (Schreibvorgang). Ich bin mir nicht sicher, ob es einen Gewinn gibt, ein "Update" anstelle eines "Löschens" durchzuführen.
Tomer
Sie können diese Daten mit dem ursprünglichen Schreibvorgang einfügen und mit jeder anderen Aktualisierungsaktion aktualisieren lassen. Natürlich ist dies keine Option, wenn Sie eine Reihe von Daten haben und diese dann löschen möchten. Dies ist jedoch eine gültige Option für Fälle, in denen Sie ttl für die Daten haben können, die Sie einfügen oder aktualisieren.
Lukas Liesis
1
Ich stimme zu, wenn bereits TTL konfiguriert ist und die Bereinigung bis zu 48 Stunden warten kann, ist dies definitiv die optimale Option. Ich entschuldige mich, wenn ich unklar war.
Tomer
4

Die Antwort auf diese Frage hängt von der Anzahl der Artikel und ihrer Größe sowie Ihrem Budget ab. Hängt davon ab, dass wir folgende 3 Fälle haben:

1- Die Anzahl der Elemente und die Größe der Elemente in der Tabelle sind nicht sehr hoch. dann können Sie, wie Steffen Opel sagte, Abfrage anstelle von Scannen verwenden, um alle Elemente für user_id abzurufen und dann alle zurückgegebenen Elemente zu durchlaufen und entweder DeleteItemoder zu erleichternBatchWriteItem. Beachten Sie jedoch, dass hier möglicherweise viel Durchsatzkapazität verbraucht wird. Stellen Sie sich beispielsweise eine Situation vor, in der Sie 1000 Elemente aus einer DynamoDB-Tabelle löschen müssen. Angenommen, jedes Element hat eine Größe von 1 KB, was zu etwa 1 MB Daten führt. Für diese Massenlöschaufgabe sind insgesamt 2000 Schreibkapazitätseinheiten zum Abfragen und Löschen erforderlich. Um dieses Laden der Daten innerhalb von 10 Sekunden durchzuführen (was in einigen Anwendungen nicht einmal als schnell angesehen wird), müssten Sie den bereitgestellten Schreibdurchsatz der Tabelle auf 200 Schreibkapazitätseinheiten festlegen. Wie Sie sehen können, ist es machbar, diese Methode zu verwenden, wenn es sich um eine geringere Anzahl von Artikeln oder kleine Artikel handelt.

2- Wir haben viele oder sehr große Gegenstände in der Tabelle und können sie je nach Zeit in verschiedenen Tabellen speichern. Dann können Sie, wie Jonathan sagte, einfach die Tabelle löschen. Das ist viel besser, aber ich denke nicht, dass es mit Ihrem Fall übereinstimmt. Da Sie alle Benutzerdaten unabhängig vom Zeitpunkt der Erstellung der Protokolle löschen möchten, können Sie in diesem Fall eine bestimmte Tabelle nicht löschen. Wenn Sie eine separate Tabelle für jeden Benutzer haben möchten, dann ist es wahrscheinlich so teuer und für Ihren Fall nicht praktikabel, wenn die Anzahl der Benutzer hoch ist.

3- Wenn Sie viele Daten haben und Ihre heißen und kalten Daten nicht in verschiedene Tabellen aufteilen können und häufig umfangreiche Löschvorgänge durchführen müssen, ist DynamoDB leider überhaupt keine gute Option für Sie. Es kann teurer oder sehr langsam werden (abhängig von Ihrem Budget). In diesen Fällen empfehle ich, eine andere Datenbank für Ihre Daten zu suchen.

Iman Sedighi
quelle
0

Mein Ansatz zum Löschen aller Zeilen aus einer Tabelle in DynamoDb besteht darin, alle Zeilen mit DynamoDbs ScanAsync aus der Tabelle zu ziehen und die Ergebnisliste dann DynamoDbs AddDeleteItems zuzuführen. Der folgende Code in C # funktioniert gut für mich.

        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();
    }

Hinweis: Das Löschen der Tabelle und das anschließende erneute Erstellen über die Webkonsole kann zu Problemen führen, wenn Sie YAML / CloudFront zum Erstellen der Tabelle verwenden.

Mohammad
quelle
0

Wir haben keine Möglichkeit, Dynamotabellen abzuschneiden. Wir müssen die Tabelle löschen und erneut erstellen. DynamoDB-Gebühren basieren auf ReadCapacityUnits und WriteCapacityUnits. Wenn wir alle Elemente mit der BatchWriteItem-Funktion löschen, wird WriteCapacityUnits verwendet. Um bestimmte Datensätze zu löschen oder die Tabelle zu löschen und erneut zu starten.

Shraavan Hebbar
quelle