Jaki jest zalecany sposób usuwania dużej liczby elementów z DynamoDB?

112

Piszę prostą usługę logowania w DynamoDB.

Mam tabelę dzienników, która jest kluczowana przez hash user_id i zakres datownika (int w epoce systemu Unix).

Kiedy użytkownik serwisu zamyka swoje konto, muszę usunąć wszystkie pozycje z tabeli, niezależnie od wartości zakresu.

Jaki jest zalecany sposób wykonywania tego rodzaju operacji (pamiętaj, że mogą istnieć miliony elementów do usunięcia)?

Moje opcje, o ile widzę, to:

Odp .: Wykonaj operację skanowania, wywołując usuwanie dla każdego zwróconego elementu, dopóki nie zostaną żadne elementy

B: Wykonaj operację BatchGet, ponownie wywołując usuwanie dla każdego elementu, dopóki żaden nie zostanie

Oba te wyglądają dla mnie okropnie, ponieważ zajmą dużo czasu.

To, co chciałbym zrobić, to wywołać LogTable.DeleteItem (user_id) - bez podawania zakresu i usunąć wszystko za mnie.

Tyler
źródło

Odpowiedzi:

52

Najlepiej byłoby, gdybyśmy wywołali LogTable.DeleteItem (user_id) - bez podawania zakresu i usunęli wszystko za mnie.

Rzeczywiście zrozumiała prośba; Mogę sobie wyobrazić, że zaawansowane operacje, takie jak te, mogą być dodawane z czasem przez zespół AWS (mają historię zaczynania od ograniczonego zestawu funkcji i oceniania rozszerzeń na podstawie opinii klientów), ale oto, co należy zrobić, aby uniknąć kosztów pełny skan co najmniej:

  1. Użyj zapytania zamiast skanowania, aby pobrać wszystkie elementy user_id- działa to niezależnie od używanego połączonego klucza podstawowego hash / range, ponieważ HashKeyValue i RangeKeyCondition są oddzielnymi parametrami w tym interfejsie API, a ten pierwszy dotyczy tylko wartości atrybutu składnika skrótu złożonego klucz podstawowy. .

    • Pamiętaj, że będziesz musiał jak zwykle poradzić sobie ze stronicowaniem interfejsu API zapytań tutaj, jak zwykle, zobacz parametr ExclusiveStartKey :

      Klucz podstawowy elementu, z którego należy kontynuować wcześniejsze zapytanie. Wcześniejsze zapytanie może dostarczyć tę wartość jako LastEvaluatedKey, jeśli operacja zapytania została przerwana przed zakończeniem zapytania; ze względu na rozmiar zestawu wyników lub parametr Limit. LastEvaluatedKey można przekazać z powrotem w nowym żądaniu zapytania, aby kontynuować operację od tego momentu.

  2. Zapętlaj wszystkie zwrócone elementy i albo jak zwykle ułatwiaj DeleteItem

    • Aktualizacja : Najprawdopodobniej BatchWriteItem jest bardziej odpowiedni dla takiego przypadku użycia (szczegóły poniżej).

Aktualizacja

Jak podkreślił ivant , operacja BatchWriteItem umożliwia umieszczanie lub usuwanie kilku elementów w wielu tabelach w jednym wywołaniu interfejsu API [podkreślenie moje] :

Aby przesłać jeden element, możesz użyć interfejsu API PutItem, a aby usunąć jeden element, możesz użyć interfejsu API DeleteItem. Jeśli jednak chcesz przesłać lub usunąć duże ilości danych, na przykład przesłać duże ilości danych z Amazon Elastic MapReduce (EMR) lub przenieść dane z innej bazy danych do Amazon DynamoDB, ten interfejs API stanowi wydajną alternatywę.

Należy pamiętać, że nadal ma to pewne istotne ograniczenia, w szczególności:

  • Maksymalna liczba operacji w jednym żądaniu - można określić łącznie do 25 operacji wstawiania lub usuwania; jednak łączny rozmiar żądania nie może przekraczać 1 MB (ładunek HTTP).

  • Nie jest to niepodzielna operacja - poszczególne operacje określone w BatchWriteItem są niepodzielne; jednak BatchWriteItem jako całość jest operacją „najlepszego wysiłku”, a nie operacją atomową. Oznacza to, że w żądaniu BatchWriteItem niektóre operacje mogą się powieść, a inne mogą zakończyć się niepowodzeniem. […]

Niemniej jednak w oczywisty sposób oferuje to potencjalnie znaczące korzyści w przypadkach użycia, takich jak niniejszy.

Steffen Opel
źródło
4
Myślę, że sensowne byłoby użycie usuwania wsadowego w drugim kroku (jest to "zamaskowane" jako operacja zapisu wsadowego )
ivant
1
@ivant - wielkie dzięki za podpowiedź, ta "zamaskowana" funkcja usuwania BatchWriteItem rzeczywiście mi wtedy umknęła; Odpowiednio zaktualizowałem odpowiedź.
Steffen Opel
do usuwania z BatchWriteItemelementami należy określić za pośrednictwemTableWriteItems
Neil
1
Link do BatchWriteItem to teraz docs.aws.amazon.com/amazondynamodb/latest/APIReference/…
Tony
4
Zdaję sobie sprawę, że to jest stare, a OP nie wspomniał o konkretnym języku SDK, ale w Pythonie jest wysoki poziom batch_writer()jako część boto3.resource.TableAPI, który „automatycznie obsługuje buforowanie i wysyłanie elementów w partiach. Ponadto piszący partie również automatycznie obsługuje wszelkie nieprzetworzone elementy i ponownie je wysyła w razie potrzeby ”tj. jest to opakowanie wokół BatchWriteItem, które zarządza irytującymi częściami. boto3.amazonaws.com/v1/documentation/api/latest/reference/…
Davos
46

Zgodnie z dokumentacją DynamoDB można po prostu usunąć całą tabelę.

Zobacz poniżej:

„Usunięcie całej tabeli jest znacznie bardziej wydajne niż usuwanie elementów pojedynczo, co zasadniczo podwaja przepustowość zapisu, ponieważ wykonujesz tyle operacji usuwania, ile operacji put”

Jeśli chcesz usunąć tylko podzbiór danych, możesz utworzyć osobne tabele dla każdego miesiąca, roku lub podobnego. W ten sposób możesz usunąć „ostatni miesiąc” i zachować resztę danych w stanie nienaruszonym.

Oto jak usunąć tabelę w Javie za pomocą AWS SDK:

DeleteTableRequest deleteTableRequest = new DeleteTableRequest()
  .withTableName(tableName);
DeleteTableResult result = client.deleteTable(deleteTableRequest);
Jonathan
źródło
8
Ta odpowiedź też mi się podoba, ale uwaga: może to spowodować utworzenie wielu tabel w twoim systemie, a my płacimy za rezerwację stołu. Dlatego po zakończeniu miesiąca (jeśli twoja tabela jest miesięcznie) musisz zmniejszyć rezerwę, dopóki ta tabela nie zostanie usunięta.
Sergio MC Figueiredo
2
zgadzam się z tą odpowiedzią, jest ona stosowana, jeśli chcesz usunąć wszystkie rekordy z tabeli, ale tutaj pytający chce usunąć wpisy bazy użytkowników, a nie całą tabelę.
Ihtsham Minhas
1
Posiadanie oddzielnej tabeli dla każdego użytkownika byłoby kosztowne, biorąc pod uwagę cenę DynamoDB. Jeden stół na miesiąc faktycznie pogorszyłby sytuację. To jest oczywiście odpowiedź na inny, bardzo specyficzny problem.
André Werlang
11
Usunięcie tabeli może również nie być atrakcyjną opcją, jeśli używasz automatycznej obsługi administracyjnej, takiej jak CloudFormation, do zarządzania tabelą jako częścią stosu. Nie znam prostego sposobu, aby CloudFormation odtworzył tabelę usuniętą ręcznie.
brabster,
2
Takie podejście zajmuje trochę czasu, aby usunąć i odtworzyć (w razie potrzeby) tabelę, przez co jest ona niedostępna przez cały czas. Pytanie jasno określa usunięcie danych użytkownika, co byłoby niepraktyczne podzielenie na oddzielne tabele dla każdego użytkownika.
André Werlang
14

Jeśli chcesz usunąć pozycje po jakimś czasie, np. Po miesiącu, wystarczy skorzystać z opcji Time To Live. To będzie nie liczyć jednostki zapisu.

W twoim przypadku dodałbym ttl, gdy logi wygasną i zostawiłem je po usunięciu użytkownika. TTL zapewni, że dzienniki zostaną ostatecznie usunięte.

Gdy w tabeli włączona jest funkcja Time To Live, zadanie w tle sprawdza atrybut TTL elementów, aby sprawdzić, czy wygasły.

DynamoDB zazwyczaj usuwa wygasłe elementy w ciągu 48 godzin od wygaśnięcia. Dokładny czas, w którym element zostanie rzeczywiście usunięty po wygaśnięciu, zależy od rodzaju obciążenia pracą i rozmiaru tabeli. Elementy, które wygasły i nie zostały usunięte, nadal będą pojawiać się w odczytach, zapytaniach i skanach. Te elementy można nadal aktualizować, a pomyślne aktualizacje w celu zmiany lub usunięcia atrybutu wygaśnięcia będą honorowane.

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

Lukas Liesis
źródło
dodanie TTL jest „aktualizacją” (operacją zapisu). Nie jestem pewien, czy przyniesie to jakikolwiek zysk za wykonanie „aktualizacji” zamiast „usunięcia”.
Tomer
możesz mieć te dane wstawione z oryginalnym zapisem i zaktualizowane za pomocą dowolnej innej akcji aktualizacji. Oczywiście nie jest to opcja, jeśli masz dużo danych, a następnie chcesz je usunąć. Ale jest to poprawna opcja w przypadkach, w których możesz mieć ttl dla danych, które wstawiasz lub aktualizujesz.
Lukas Liesis
1
Zgadzam się, jeśli jest już skonfigurowane TTL i czyszczenie może poczekać do 48 godzin, to zdecydowanie optymalna opcja. Przepraszam, jeśli nie byłam jasna.
Tomer,
4

Odpowiedź na to pytanie zależy od liczby pozycji i ich wielkości oraz budżetu. Zależy od tego, że mamy 3 przypadki:

1- Liczba pozycji i rozmiar pozycji w tabeli nie są zbyt duże. następnie, jak powiedział Steffen Opel, możesz użyć zapytania zamiast skanowania, aby pobrać wszystkie elementy dla user_id, a następnie przejrzeć wszystkie zwrócone elementy i albo ułatwić, DeleteItemalboBatchWriteItem. Pamiętaj jednak, że możesz tutaj spalić dużą przepustowość. Na przykład rozważmy sytuację, w której trzeba usunąć 1000 pozycji z tabeli DynamoDB. Załóżmy, że każdy element ma rozmiar 1 KB, co daje około 1 MB danych. To zadanie usuwania zbiorczego będzie wymagało łącznie 2000 jednostek pojemności zapisu do wykonywania zapytań i usuwania. Aby wykonać to ładowanie danych w ciągu 10 sekund (co w niektórych aplikacjach nie jest nawet uważane za tak szybkie), należałoby ustawić udostępnioną przepustowość zapisu tabeli na 200 jednostek pojemności zapisu. Jak widać, można go użyć w ten sposób, jeśli jest to dla mniejszej liczby przedmiotów lub przedmiotów o małych rozmiarach.

2- Mamy w tabeli wiele pozycji lub bardzo duże pozycje i możemy je przechowywać według czasu w różnych tabelach. Wtedy, jak powiedział Jonathan, możesz po prostu usunąć tabelę. to jest o wiele lepsze, ale nie sądzę, aby pasowało do twojego przypadku. Ponieważ chcesz usunąć wszystkie dane użytkowników bez względu na czas tworzenia logów, w tym przypadku nie możesz usunąć konkretnej tabeli. jeśli chcesz mieć osobną tabelę dla każdego użytkownika, myślę, że jeśli liczba użytkowników jest duża, jest to tak drogie i nie jest praktyczne w twoim przypadku.

3- Jeśli masz dużo danych i nie możesz podzielić swoich gorących i zimnych danych na różne tabele i musisz często usuwać na dużą skalę, to niestety DynamoDB wcale nie jest dla Ciebie dobrą opcją. Może stać się droższy lub bardzo powolny (w zależności od budżetu). W takich przypadkach radzę poszukać innej bazy danych.

Iman Sedighi
źródło
0

Moje podejście do usuwania wszystkich wierszy z tabeli i DynamoDb polega po prostu na wyciągnięciu wszystkich wierszy z tabeli za pomocą DynamoDbs ScanAsync, a następnie przesłaniu listy wyników do DynamoDbs AddDeleteItems. Poniższy kod w C # u mnie działa dobrze.

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

Uwaga: Usunięcie tabeli, a następnie ponowne utworzenie jej z konsoli internetowej może spowodować problemy, jeśli do tworzenia tabeli używasz YAML / CloudFront.

Mohammad
źródło
0

Nie mamy możliwości obcinania tablic dynamo. musimy porzucić tabelę i ponownie stworzyć. Opłaty za DynamoDB są oparte na ReadCapacityUnits i WriteCapacityUnits. Jeśli usuniemy wszystkie elementy za pomocą funkcji BatchWriteItem, użyje ona WriteCapacityUnits, więc lepiej usunąć określone rekordy lub usunąć tabelę i zacząć od nowa.

Shraavan Hebbar
źródło