Programmieren von Amazon DynamoDB mit Python und Boto3 - Amazon DynamoDB

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

Programmieren von Amazon DynamoDB mit Python und Boto3

Dieser Leitfaden bietet eine Einführung für Programmierer, die Amazon DynamoDB mit Python verwenden möchten. Erfahren Sie mehr über die Abstraktionsebenen, das Konfigurationsmanagement, den Umgang mit Fehlern, die Steuerung von Wiederholungsrichtlinien, die Verwaltung von Keepalive und mehr.

Informationen zu Boto

Sie können von Python aus auf DynamoDB zugreifen, indem Sie das offizielle AWS-SDK für Python verwenden, das allgemein als Boto3 bezeichnet wird. Der Name Boto (ausgesprochen boh-toh) stammt von einem Süßwasserdelfin, der im Amazon heimisch ist. Die Boto3-Bibliothek ist die dritte Hauptversion der Bibliothek, die erstmals 2015 veröffentlicht wurde. Die Boto3-Bibliothek ist ziemlich groß, da sie alle AWS-Services unterstützt, nicht nur DynamoDB. Dieser Leitfaden zielt nur auf die Teile von Boto3 ab, die für DynamoDB relevant sind.

Boto wird von AWS als Open-Source-Projekt verwaltet und veröffentlicht, das auf GitHub gehostet wird. Es ist in zwei Pakete aufgeteilt: Botocore und Boto3.

  • Botocore bietet die Low-Level-Funktionalität. In Botocore finden Sie die Klassen Client, Session, Credentials, Config und Exception.

  • Boto3 baut auf Botocore auf. Es bietet eine übergeordnete, pythonischere Oberfläche. Insbesondere macht es eine DynamoDB-Tabelle als Ressource verfügbar und bietet eine einfachere, elegantere Oberfläche als die serviceorientierte Client-Schnittstelle auf niedrigerer Ebene.

Da diese Projekte auf GitHub gehostet werden, können Sie den Quellcode einsehen, offene Probleme verfolgen oder Ihre eigenen Probleme einreichen.

Verwenden der Boto-Dokumentation

Beginnen Sie mit der Boto-Dokumentation anhand der folgenden Ressourcen:

  • Beginnen Sie mit dem Quickstart-Abschnitt, der einen soliden Ausgangspunkt für die Paketinstallation bietet. Dort finden Sie Anleitungen zur Installation von Boto3, falls dies noch nicht geschehen ist (Boto3 ist häufig automatisch als Teil von AWS-Services wie AWS Lambda verfügbar).

  • Konzentrieren Sie sich danach auf den DynamoDB-Leitfaden der Dokumentation. Darin erfahren Sie, wie Sie die grundlegenden DynamoDB-Aktivitäten ausführen: eine Tabelle erstellen und löschen, Elemente bearbeiten, Batch-Operationen ausführen, eine Abfrage ausführen und einen Scan durchführen. Für die Beispiele wird die Schnittstelle Ressourcen verwendet. Wenn Sie boto3.resource('dynamodb') sehen, bedeutet das, dass Sie die übergeordnete Schnittstelle Ressourcen verwenden.

  • Nach dem Leitfaden können Sie sich die DynamoDB-Referenz nochmals ansehen. Diese Startseite bietet eine vollständige Liste der Klassen und Methoden, die Ihnen zur Verfügung stehen. Ganz oben sehen Sie die DynamoDB.Client-Klasse. Diese bietet Low-Level-Zugriff auf alle Operationen auf der Steuerungsebene und der Datenebene. Schauen Sie sich ganz unten die DynamoDB.ServiceResource-Klasse an. Dies ist die Pythonic-Schnittstelle auf höherer Ebene. Damit können Sie eine Tabelle erstellen, tabellenübergreifende Batch-Operationen ausführen oder eine DynamoDB.ServiceResource.Table-Instance für tabellenspezifische Aktionen abrufen.

Grundlegendes zu den Abstraktionsebenen für Clients und Ressourcen

Die beiden Schnittstellen, mit denen Sie arbeiten werden, sind die Client- und die Ressourcen-Schnittstelle.

  • Die Low-Level-Client-Schnittstelle bietet eine Eins-zu-Eins-Zuordnung zur zugrunde liegenden Service-API. Jede von DynamoDB angebotene API ist über den Client verfügbar. Das bedeutet, dass die Client-Schnittstelle vollständige Funktionalität bieten kann, aber häufig ausführlicher und komplexer in der Anwendung ist.

  • Die High-Level-Ressourcen-Schnittstelle bietet keine 1-zu-1-Zuordnung der zugrunde liegenden Service-API. Sie bietet jedoch Methoden, die Ihnen den Zugriff auf den Service erleichtern, z. B batch_writer.

Hier ein Beispiel für das Einfügen eines Elements über die Client-Schnittstelle. Beachten Sie, dass alle Werte als Map übergeben werden, wobei der Schlüssel ihren Typ ('S' für Zeichenfolge, 'N' für Zahl) und ihren Wert als Zeichenfolge angibt. Dies wird als DynamoDB-JSON-Format bezeichnet.

import boto3 dynamodb = boto3.client('dynamodb') dynamodb.put_item( TableName='YourTableName', Item={ 'pk': {'S': 'id#1'}, 'sk': {'S': 'cart#123'}, 'name': {'S': 'SomeName'}, 'inventory': {'N': '500'}, # ... more attributes ... } )

Hier ist dieselbe PutItem-Operation, jedoch unter Verwendung der Ressourcenschnittstelle. Die Datentypisierung ist implizit:

import boto3 dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('YourTableName') table.put_item( Item={ 'pk': 'id#1', 'sk': 'cart#123', 'name': 'SomeName', 'inventory': 500, # ... more attributes ... } )

Bei Bedarf können Sie mithilfe der in boto3 bereitgestellten Klassen TypeSerializer und TypeDeserializer von dem normalen JSON- zum DynamoDB-JSON-Format konvertieren:

def dynamo_to_python(dynamo_object: dict) -> dict: deserializer = TypeDeserializer() return { k: deserializer.deserialize(v) for k, v in dynamo_object.items() } def python_to_dynamo(python_object: dict) -> dict: serializer = TypeSerializer() return { k: serializer.serialize(v) for k, v in python_object.items() }

So führen Sie eine Abfrage mithilfe der Client-Schnittstelle durch. Sie drückt die Abfrage als ein JSON-Konstrukt aus. Es wird eine KeyConditionExpression-Zeichenfolge verwendet, die eine Variablenersetzung erfordert, um mögliche Schlüsselwortkonflikte zu behandeln:

import boto3 client = boto3.client('dynamodb') # Construct the query response = client.query( TableName='YourTableName', KeyConditionExpression='pk = :pk_val AND begins_with(sk, :sk_val)', FilterExpression='#name = :name_val', ExpressionAttributeValues={ ':pk_val': {'S': 'id#1'}, ':sk_val': {'S': 'cart#'}, ':name_val': {'S': 'SomeName'}, }, ExpressionAttributeNames={ '#name': 'name', } )

Dieselbe Abfrageoperation, die die Ressourcenschnittstelle verwendet, kann verkürzt und vereinfacht werden:

import boto3 from boto3.dynamodb.conditions import Key, Attr dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('YourTableName') response = table.query( KeyConditionExpression=Key('pk').eq('id#1') & Key('sk').begins_with('cart#'), FilterExpression=Attr('name').eq('SomeName') )

Stellen Sie sich als letztes Beispiel vor, Sie möchten die ungefähre Größe einer Tabelle ermitteln (dabei handelt es sich um Metadaten, die in der Tabelle gespeichert sind und etwa alle 6 Stunden aktualisiert werden). Mit der Client-Schnittstelle führen Sie eine describe_table()-Operation aus und ziehen die Antwort aus der zurückgegebenen JSON-Struktur:

import boto3 dynamodb = boto3.client('dynamodb') response = dynamodb.describe_table(TableName='YourTableName') size = response['Table']['TableSizeBytes']

Mit der Ressourcenschnittstelle führt die Tabelle die Beschreibungsoperation implizit aus und präsentiert die Daten direkt als Attribut:

import boto3 dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('YourTableName') size = table.table_size_bytes
Anmerkung

Beachten Sie bei der Entscheidung, ob Sie mit der Client- oder der Ressourcenschnittstelle entwickeln möchten, dass der Ressourcenschnittstelle gemäß der Ressourcendokumentation keine neuen Funktionen hinzugefügt werden: „Das AWS-Python-SDK-Team beabsichtigt nicht, der Ressourcenschnittstelle in boto3 neue Funktionen hinzuzufügen. Vorhandene Schnittstellen werden während des Lebenszyklus von boto3 weiterhin funktionieren. Kunden können über die Client-Oberfläche auf neuere Service-Features zugreifen.“

Verwenden der Tabellenressource batch_writer

Ein Vorteil, der nur mit der High-Level-Tabellenressource verfügbar ist, ist der batch_writer. DynamoDB unterstützt Batch-Schreibvorgänge und ermöglicht bis zu 25 Put- oder Löschvorgänge in einer Netzwerkanfrage. Eine solche Batchverarbeitung verbessert die Effizienz, da Netzwerk-Roundtrips minimiert werden.

Mit der Low-Level-Client-Bibliothek verwenden Sie die client.batch_write_item()-Operation, um Batches auszuführen. Sie müssen Ihre Arbeit manuell in Batches von 25 aufteilen. Nach jedem Vorgang müssen Sie außerdem eine Liste der unverarbeiteten Elemente anfordern (einige Schreibvorgänge können erfolgreich sein, während andere fehlschlagen könnten). Anschließend müssen Sie diese unverarbeiteten Elemente erneut an eine spätere batch_write_item()-Operation übergeben. Es gibt eine beträchtliche Menge an Boilerplate-Code.

Die Methode Table.batch_writer erstellt einen Kontextmanager zum Schreiben von Objekten in einem Batch. Dieser stellt eine Schnittstelle bereit, bei der es so aussieht, als würden Sie Elemente einzeln schreiben, aber intern werden die Elemente gepuffert und in Batches gesendet. Außerdem verarbeitet er auch implizite Wiederholungen unverarbeiteter Elemente.

dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('YourTableName') movies = # long list of movies in {'pk': 'val', 'sk': 'val', etc} format with table.batch_writer() as writer: for movie in movies: writer.put_item(Item=movie)

Zusätzliche Codebeispiele zur Client- und Ressourcenebene

Sie können auch auf die folgenden Beispiel-Repositorys verweisen, die die Nutzung verschiedener Funktionen sowohl mit dem Client als auch mit der Ressourcenebene untersuchen:

Verständnis der Interaktion von Client- und Resource-Objekten mit Sitzungen und Threads

Das Resource-Objekt ist nicht Thread-sicher und sollte nicht über Threads oder Prozesse hinweg gemeinsam genutzt werden. Weitere Informationen finden Sie im Leitfaden zur Resource.

Das Client-Objekt hingegen ist im Allgemeinen Thread-sicher. Ausgenommen sind bestimmte fortgeschrittene Features. Weitere Informationen finden Sie im Leitfaden zu Clients.

Das Sitzungsobjekt ist nicht Thread-sicher. Daher sollten Sie in einer Multi-Threading-Umgebung für jeden neuen Client oder jedes neue Ressourcenobjekt zunächst eine neue Sitzung erstellen und daraus dann den jeweiligen Client oder das Ressourcenobjekt ableiten. Weitere Informationen finden Sie im Leitfaden zu Sitzungen.

Wenn Sie boto3.resource() aufrufen, verwenden Sie implizit die Standardsitzung. Das ist praktisch für das Schreiben von Single-Threaded-Code. Für Multi-Threaded-Code sollten Sie hingegen für jeden Thread eine eigene Session erstellen und daraus die jeweilige Resource abrufen:

# Explicitly create a new Session for this thread session = boto3.Session() dynamodb = session.resource('dynamodb')

Anpassen des Config-Objekts

Beim Erstellen eines Client- oder Resource-Objekts können Sie optionale benannte Parameter übergeben, um das Verhalten zu steuern. Der Parameter config schaltet dabei eine Vielzahl von Funktionen frei. Es handelt sich um eine Instance von botocore.client.Config, und die Referenzdokumentation zu Config zeigt alle verfügbaren Optionen zur Steuerung. Die Anleitung zur Konfiguration bietet einen guten Überblick.

Anmerkung

Sie können viele dieser Verhaltenseinstellungen auf Sitzungsebene, in der AWS-Konfigurationsdatei oder als Umgebungsvariablen ändern.

Config für Timeouts

Eine Anwendung einer benutzerdefinierten Konfiguration besteht darin, das Netzwerkverhalten anzupassen:

  • connect_timeout (float oder int) – Die Zeit in Sekunden, bis eine Timeout-Ausnahme beim Versuch eines Verbindungsaufbaus ausgelöst wird. Standardmäßig ist ein Zeitraum von 60 Sekunden festgelegt.

  • read_timeout (float oder int) – Die Zeit in Sekunden, bis beim Versuch einer Verbindungslesung eine Timeout-Ausnahme ausgelöst wird. Standardmäßig ist ein Zeitraum von 60 Sekunden festgelegt.

Timeouts von 60 Sekunden sind für DynamoDB zu hoch. Das bedeutet, dass eine vorübergehende Netzwerkstörung eine Verzögerung von einer Minute verursacht, bevor der Client einen erneuten Versuch unternehmen kann. Der folgende Code verkürzt die Timeouts auf eine Sekunde:

import boto3 from botocore.config import Config my_config = Config( connect_timeout = 1.0, read_timeout = 1.0 ) dynamodb = boto3.resource('dynamodb', config=my_config)

Weitere Informationen zu Timeouts finden Sie unter Optimierung der HTTP-Anfrageeinstellungen des AWS-Java SDK für latenzsensitive DynamoDB-Anwendungen. Beachten Sie, dass das Java-SDK mehr Timeout-Konfigurationsmöglichkeiten bietet als das Python-SDK.

Config für Keepalive

Wenn Sie Botocore 1.27.84 oder höher verwenden, können Sie auch TCP Keepalive steuern:

  • tcp_keepalive (bool) – Aktiviert die Socket-Option TCP-Keepalive beim Erstellen neuer Verbindungen, wenn diese auf True gesetzt wurde (Standard ist False). Dies ist nur ab Botocore 1.27.84 verfügbar.

Wenn Sie TCP Keepalive auf True setzen, können Sie die durchschnittlichen Latenzen reduzieren. Hier ein Beispielcode, der TCP Keepalive bedingt auf true setzt, wenn Sie die richtige Botocore-Version haben:

import botocore import boto3 from botocore.config import Config from distutils.version import LooseVersion required_version = "1.27.84" current_version = botocore.__version__ my_config = Config( connect_timeout = 0.5, read_timeout = 0.5 ) if LooseVersion(current_version) > LooseVersion(required_version): my_config = my_config.merge(Config(tcp_keepalive = True)) dynamodb = boto3.resource('dynamodb', config=my_config)
Anmerkung

TCP Keepalive unterscheidet sich von HTTP Keepalive. Bei TCP Keepalive werden kleine Pakete vom zugrunde liegenden Betriebssystem über die Socket-Verbindung gesendet, um die Verbindung aufrechtzuerhalten und etwaige Unterbrechungen sofort zu erkennen. Mit HTTP Keepalive wird die auf dem zugrunde liegenden Socket aufgebaute Webverbindung wiederverwendet. HTTP Keepalive ist bei boto3 immer aktiviert.

Es gibt jedoch eine Begrenzung, wie lange eine inaktive Verbindung aufrechterhalten werden kann. Erwägen Sie, regelmäßige Anfragen zu senden (z. B. jede Minute), wenn Sie eine Leerlaufverbindung haben, aber möchten, dass die nächste Anfrage eine bereits bestehende Verbindung nutzt.

Config für Wiederholungsversuche

Die Konfiguration akzeptiert auch ein Wörterbuch namens Wiederholungen, in dem Sie Ihr gewünschtes Wiederholungsverhalten angeben können. Wiederholungen finden innerhalb des SDK statt, wenn das SDK einen Fehler empfängt und der Fehler vorübergehend ist. Wenn ein Fehler intern wiederholt wird (und der Wiederholungsversuch schließlich erfolgreich ist), wird aus Sicht des aufrufenden Codes kein Fehler sichtbar, sondern nur eine leicht erhöhte Latenz. Hier sind die Werte, die Sie angeben können:

  • max_attempts – Eine Ganzzahl, die die maximale Anzahl von Wiederholungsversuchen angibt, die bei einer einzelnen Anfrage durchgeführt werden. Wenn Sie diesen Wert beispielsweise auf 2 setzen, wird die Anfrage nach der ersten Anfrage höchstens zweimal wiederholt. Wenn Sie diesen Wert auf 0 setzen, werden nach der ersten Anfrage keine weiteren Wiederholungsversuche durchgeführt.

  • total_max_attempts – Eine Ganzzahl, die die maximale Gesamtzahl der Versuche angibt, die bei einer einzelnen Anfrage unternommen werden. Dies schließt die erste Anfrage ein, sodass ein Wert von 1 bedeutet, dass keine weiteren Anfragen versucht werden. Wenn sowohl total_max_attempts als auch max_attempts angegeben sind, hat total_max_attempts Vorrang. total_max_attempts und nicht max_attempts wird bevorzugt, da er mit der Umgebungsvariable AWS_MAX_ATTEMPTS und dem Konfigurationswert max_attempts in der Konfigurationsdatei übereinstimmt.

  • mode – Eine Zeichenfolge, die den Typ des Wiederholungsmodus darstellt, den Botocore verwenden soll. Gültige Werte sind:

    • legacy – Der Standardmodus. Wartet 50 ms beim ersten Wiederholungsversuch und verwendet dann ein exponentielles Backoff mit dem Basisfaktor 2. Für DynamoDB sind es insgesamt maximal 10 Versuche (sofern nicht wie oben gezeigt überschrieben wurde).

      Anmerkung

      Bei exponentiellem Backoff wird fast 13 Sekunden mit dem letzten Versuch gewartet.

    • standard – Wird als „Standard“ bezeichnet, weil es konsistenter mit anderen AWS-SDKs ist. Beim ersten Wiederholungsversuch wird eine zufällige Zeitspanne zwischen 0 ms und 1 000 ms abgewartet. Sollte ein weiterer Versuch erforderlich sein, wird erneut ein zufälliger Zeitraum zwischen 0 ms und 1 000 ms gewählt und mit 2 multipliziert. Sollten weitere Wiederholungsversuche erforderlich sein, erfolgt dieselbe zufällige Auswahl, multipliziert mit 4 usw. Jede Wartezeit ist auf 20 Sekunden begrenzt. Dieser Modus führt mehr Wiederholungen für mehr erkannte Fehlerbedingungen aus als der legacy-Modus. Für DynamoDB sind es insgesamt maximal 3 Versuche (sofern nicht wie oben gezeigt überschrieben wurde).

    • adaptive - Ein experimenteller Wiederholungsmodus, der alle Funktionalitäten des Standardmodus beinhaltet, aber eine automatische clientseitige Drosselung hinzufügt. Mit adaptiver Ratenbegrenzung können SDKs die Geschwindigkeit verringern, mit der Anfragen gesendet werden, um der Kapazität der AWS-Services besser gerecht zu werden. Dies ist ein vorläufiger Modus, dessen Verhalten sich ändern kann.

Eine erweiterte Definition dieser Wiederholungsmodi finden Sie in der Anleitung zu Wiederholungsversuchen sowie im Thema Wiederholungsverhalten in der SDK-Referenz.

Hier ein Beispiel, das explizit die legacy-Wiederholungsrichtlinie mit insgesamt maximal 3 Anfragen (2 Wiederholungen) verwendet:

import boto3 from botocore.config import Config my_config = Config( connect_timeout = 1.0, read_timeout = 1.0, retries = { 'mode': 'legacy', 'total_max_attempts': 3 } ) dynamodb = boto3.resource('dynamodb', config=my_config)

Da es sich bei DynamoDB um ein System mit hoher Verfügbarkeit und geringer Latenz handelt, sollten Sie bei der Geschwindigkeit von Wiederholungsversuchen möglicherweise etwas aggressiver vorgehen, als es die integrierten Wiederholungsrichtlinien zulassen. Sie können Ihre eigene Wiederholungsrichtlinie implementieren, indem Sie die maximale Anzahl der Versuche auf 0 setzen, die Ausnahmen selbst abfangen und es gegebenenfalls in Ihrem eigenen Code erneut versuchen, anstatt sich bei impliziten Wiederholungsversuchen auf boto3 zu verlassen.

Wenn Sie Ihre eigene Wiederholungsrichtlinie verwalten, sollten Sie zwischen Drosselungen und Fehlern unterscheiden:

  • Eine Drosselung (gekennzeichnet durch ProvisionedThroughputExceededException oder ThrottlingException) weist auf einen fehlerfreien Service hin, der Sie darüber informiert, dass Sie Ihre Lese- oder Schreibkapazität in einer DynamoDB-Tabelle oder Partition überschritten haben. Mit jeder Millisekunde, die vergeht, wird etwas mehr Lese- oder Schreibkapazität zur Verfügung gestellt, sodass Sie schnell (z. B. alle 50 ms) erneut versuchen können, auf die neu freigegebene Kapazität zuzugreifen. Bei Drosselungen ist kein exponentieller Backoff erforderlich, da Drosselungen für DynamoDB leichtgewichtig sind und keine Gebühren pro Anfrage anfallen. Exponentielles Backoff weist längere Wartezeiten jenen Client-Threads zu, die bereits am längsten gewartet haben, wodurch sich die statistischen Kennzahlen p50 und p99 weiter nach außen verschieben.

  • Ein Fehler (unter anderem durch InternalServerError oder ServiceUnavailable gekennzeichnet) weist auf ein vorübergehendes Problem mit dem Service hin. Dies kann für die gesamte Tabelle oder möglicherweise nur für die Partition gelten, aus der Sie lesen oder in die Sie schreiben. Bei Fehlern sollten Sie längere Pausen zwischen den Wiederholungsversuchen einlegen (etwa 250 ms oder 500 ms) und Jitter verwenden, um die Wiederholungen zeitlich zu staffeln.

Config für maximale Poolverbindungen

Abschließend ermöglicht die Konfiguration die Steuerung der Größe des Verbindungs-Pools:

  • max_pool_connections (int) – Die maximale Anzahl von Verbindungen, die in einem Verbindungspool beibehalten werden sollen. Wenn kein Wert festgelegt ist, wird der Standardwert 10 verwendet.

Diese Option steuert die maximale Anzahl von HTTP-Verbindungen, die zur Wiederverwendung gepoolt werden sollen. Für jede Sitzung wird ein anderer Pool verwaltet. Wenn Sie erwarten, dass mehr als 10 Threads gleichzeitig auf Clients oder Ressourcen zugreifen, die aus derselben Sitzung erstellt wurden, sollten Sie diesen Wert erhöhen, damit Threads nicht auf andere Threads warten müssen, die gerade eine gepoolte Verbindung verwenden.

import boto3 from botocore.config import Config my_config = Config( max_pool_connections = 20 ) # Setup a single session holding up to 20 pooled connections session = boto3.Session(my_config) # Create up to 20 resources against that session for handing to threads # Notice the single-threaded access to the Session and each Resource resource1 = session.resource('dynamodb') resource2 = session.resource('dynamodb') # etc

Fehlerbehandlung

Nicht alle AWS-Serviceausnahmen sind in Boto3 statisch definiert. Der Grund dafür ist, dass Fehler und Ausnahmen von AWS-Services stark variieren und Änderungen unterliegen. Boto3 verpackt alle Service-Ausnahmen als ClientError und stellt die Details als strukturiertes JSON bereit. Ein Fehlerantwort könnte beispielsweise wie folgt aufgebaut sein:

{ 'Error': { 'Code': 'SomeServiceException', 'Message': 'Details/context around the exception or error' }, 'ResponseMetadata': { 'RequestId': '1234567890ABCDEF', 'HostId': 'host ID data will appear here as a hash', 'HTTPStatusCode': 400, 'HTTPHeaders': {'header metadata key/values will appear here'}, 'RetryAttempts': 0 } }

Der folgende Code fängt alle ClientError-Ausnahmen ab und prüft den Zeichenfolgenwert des Code innerhalb des Error, um zu bestimmen, welche Aktion ausgeführt werden soll:

import botocore import boto3 dynamodb = boto3.client('dynamodb') try: response = dynamodb.put_item(...) except botocore.exceptions.ClientError as err: print('Error Code: {}'.format(err.response['Error']['Code'])) print('Error Message: {}'.format(err.response['Error']['Message'])) print('Http Code: {}'.format(err.response['ResponseMetadata']['HTTPStatusCode'])) print('Request ID: {}'.format(err.response['ResponseMetadata']['RequestId'])) if err.response['Error']['Code'] in ('ProvisionedThroughputExceededException', 'ThrottlingException'): print("Received a throttle") elif err.response['Error']['Code'] == 'InternalServerError': print("Received a server error") else: raise err

Einige (aber nicht alle) Ausnahmecodes wurden als Top-Level-Klassen materialisiert. Sie können diese direkt behandeln. Wenn Sie die Client-Schnittstelle verwenden, werden diese Ausnahmen dynamisch in Ihrem Client-Objekt bereitgestellt, und Sie fangen sie über Ihre Client-Instance ab:

except ddb_client.exceptions.ProvisionedThroughputExceededException:

Wenn Sie die Ressourcenschnittstelle verwenden, müssen Sie .meta.client nutzen, um vom Ressourcenobjekt zum zugrunde liegenden Client zu gelangen und auf die Ausnahmen zuzugreifen:

except ddb_resource.meta.client.exceptions.ProvisionedThroughputExceededException:

Um die Liste der materialisierten Ausnahmetypen zu überprüfen, können Sie die Liste dynamisch generieren:

ddb = boto3.client("dynamodb") print([e for e in dir(ddb.exceptions) if e.endswith('Exception') or e.endswith('Error')])

Wenn Sie eine Schreiboperation mit einem Bedingungsausdruck ausführen, können Sie vorgeben, dass der Wert des Elements in der Fehlerantwort zurückgegeben wird, falls der Ausdruck fehlschlägt.

try: response = table.put_item( Item=item, ConditionExpression='attribute_not_exists(pk)', ReturnValuesOnConditionCheckFailure='ALL_OLD' ) except table.meta.client.exceptions.ConditionalCheckFailedException as e: print('Item already exists:', e.response['Item'])

Weitere Informationen zur Fehlerbehandlung und zu Ausnahmen finden Sie unter:

Protokollierung

Die Boto3-Bibliothek integriert sich mit dem in Python eingebauten Protokollierungsmodul, um Vorgänge während einer Sitzung zu protokollieren. Sie können das Protokollierungsmodul konfigurieren, um die Protokollierungsebenen zu steuern:

import logging logging.basicConfig(level=logging.INFO)

Dadurch wird der Root-Logger so konfiguriert, dass er INFO und Nachrichten höherer Ebenen protokolliert. Protokollierungsnachrichten, die weniger schwerwiegend sind als Level 4, werden ignoriert. Zu den Protokollierungsebenen gehören DEBUG, INFO, WARNING, ERROR und CRITICAL. Der Standardwert ist WARNING.

Die Logger in boto3 sind hierarchisch aufgebaut. Die Bibliothek verwendet verschiedene Logger, die jeweils unterschiedlichen Teilen der Bibliothek entsprechen. Sie können das Verhalten der einzelnen Logger separat steuern:

  • boto3: Der Hauptlogger für das boto3-Modul.

  • botocore: Der Hauptlogger für das Botocore-Paket.

  • botocore.auth: Wird zum Protokollieren der AWS-Signaturerstellung für Anfragen verwendet.

  • botocore.credentials: Wird zum Protokollieren des Abrufs und der Aktualisierung von Anmeldeinformationen verwendet.

  • botocore.endpoint: Wird verwendet, um die Erstellung von Anfragen zu protokollieren, bevor sie über das Netzwerk gesendet werden.

  • botocore.hooks: Wird zum Protokollieren von Ereignissen verwendet, die in der Bibliothek ausgelöst wurden.

  • botocore.loaders: Wird zum Protokollieren verwendet, wenn Teile von AWS-Servicemodellen geladen werden.

  • botocore.parsers: Wird zum Protokollieren von AWS-Serviceantworten verwendet, bevor sie geparst werden.

  • botocore.retryhandler: Wird zum Protokollieren der Verarbeitung von erneuten Versuchen von AWS-Serviceanfragen verwendet (Legacy-Modus).

  • botocore.retries.standard: Wird zum Protokollieren der Verarbeitung von erneuten Versuchen von AWS-Serviceanfragen verwendet (Standard- oder adaptiver Modus).

  • botocore.utils: Wird zum Protokollieren verschiedener Aktivitäten in der Bibliothek verwendet.

  • botocore.waiter: Wird verwendet, um die Funktionalität von Waitern zu protokollieren, die einen AWS-Service abfragen, bis ein bestimmter Status erreicht ist.

Andere Bibliotheken protokollieren ebenfalls. Intern verwendet boto3 die URLlib3 eines Drittanbieters für die HTTP-Verbindungsverarbeitung. Wenn Ihnen Latenz wichtig ist, können Sie sich die Protokolle ansehen, um sicherzustellen, dass Ihr Pool gut ausgelastet ist, indem Sie nachsehen, wann urllib3 eine neue Verbindung aufbaut oder eine inaktive Verbindung schließt.

  • urllib3.connectionpool: Wird für die Protokollierung von Ereignissen bei der Verwaltung des Verbindungspools verwendet.

Der folgende Codeausschnitt setzt die allgemeine Protokollierung auf INFO, während für Endpunkt- und Verbindungspoolaktivitäten die DEBUG-Protokollierung aktiviert wird:

import logging logging.getLogger('boto3').setLevel(logging.INFO) logging.getLogger('botocore').setLevel(logging.INFO) logging.getLogger('botocore.endpoint').setLevel(logging.DEBUG) logging.getLogger('urllib3.connectionpool').setLevel(logging.DEBUG)

Ereignis-Hooks

Botocore gibt während verschiedener Phasen seiner Ausführung Ereignisse aus. Sie können Handler für diese Ereignisse registrieren, sodass Ihr Handler immer dann aufgerufen wird, wenn ein Ereignis ausgelöst wird. Auf diese Weise können Sie das Verhalten von Botocore erweitern, ohne die internen Funktionen ändern zu müssen.

Angenommen, Sie möchten jedes Mal nachverfolgen, wenn in Ihrer Anwendung eine PutItem-Operation auf einer beliebigen DynamoDB-Tabelle ausgeführt wird. Dann könnten Sie sich auf das Ereignis 'provide-client-params.dynamodb.PutItem' registrieren, um jeden Aufruf von PutItem innerhalb der zugehörigen Sitzung zu erfassen und zu protokollieren. Hier ein Beispiel:

import boto3 import botocore import logging def log_put_params(params, **kwargs): if 'TableName' in params and 'Item' in params: logging.info(f"PutItem on table {params['TableName']}: {params['Item']}") logging.basicConfig(level=logging.INFO) session = boto3.Session() event_system = session.events # Register our interest in hooking in when the parameters are provided to PutItem event_system.register('provide-client-params.dynamodb.PutItem', log_put_params) # Now, every time you use this session to put an item in DynamoDB, # it will log the table name and item data. dynamodb = session.resource('dynamodb') table = dynamodb.Table('YourTableName') table.put_item( Item={ 'pk': '123', 'sk': 'cart#123', 'item_data': 'YourItemData', # ... more attributes ... } )

Innerhalb des Handlers können Sie die Parameter sogar programmatisch verändern, um das Verhalten anzupassen:

params['TableName'] = "NewTableName"

Weitere Informationen zu Ereignissen finden Sie in der Botocore-Dokumentation zu Ereignissen und in der boto3-Dokumentation zu Ereignissen.

Paginierung und der Paginator

Manche Anfragen wie Query und Scan begrenzen die Datenmenge, die mit einer einzelnen Anfrage zurückgegeben wird, und erfordern wiederholte Anfragen, um nachfolgende Seiten abzurufen.

Mit dem limit-Parameter können Sie die maximale Anzahl von Elementen steuern, die pro Seite gelesen werden sollen. Beispielsweise können Sie limit verwenden, um nur die letzten 10 Elemente abzurufen. Beachten Sie, dass der Grenzwert angibt, wie viel aus der Tabelle gelesen werden sollte, bevor eine Filterung angewendet wird. Es gibt keine Möglichkeit, genau 10  nach dem Filtern anzugeben. Sie können nur die Anzahl der vorgefilterten Filter kontrollieren und clientseitig überprüfen, ob Sie tatsächlich 10 abgerufen haben. Unabhängig vom Grenzwert hat jede Antwort immer eine maximale Größe von 1 MB.

Wenn die Antwort ein LastEvaluatedKey enthält, bedeutet dies, dass die Antwort beendet wurde, weil sie eine Anzahl- oder Größenbeschränkung erreicht hat. Dieser Schlüssel ist der letzte Schlüssel, der für diese Antwort ausgewertet wird. Sie können diesen LastEvaluatedKey abrufen und an einen Folgeaufruf als ExclusiveStartKey weitergeben, um den nächsten Abschnitt von diesem Startpunkt aus zu lesen. Wenn kein LastEvaluatedKey zurückgegeben wird, bedeutet das, dass keine weiteren Elemente zu der Abfrage oder dem Scan passen.

Hier ein einfaches Beispiel (unter Verwendung der Ressourcenschnittstelle, jedoch hat die Client-Schnittstelle das gleiche Muster), bei dem maximal 100 Elemente pro Seite gelesen werden und eine Schleife ausgeführt wird, bis alle Elemente gelesen sind.

import boto3 dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('YourTableName') query_params = { 'KeyConditionExpression': Key('pk').eq('123') & Key('sk').gt(1000), 'Limit': 100 } while True: response = table.query(**query_params) # Process the items however you like for item in response['Items']: print(item) # No LastEvaluatedKey means no more items to retrieve if 'LastEvaluatedKey' not in response: break # If there are possibly more items, update the start key for the next page query_params['ExclusiveStartKey'] = response['LastEvaluatedKey']

Der Einfachheit halber kann boto3 dies mit Paginatoren für Sie erledigen. Das funktioniert jedoch nur mit der Client-Schnittstelle. Hier ist der Code, der für die Verwendung von Paginatoren neu geschrieben wurde:

import boto3 dynamodb = boto3.client('dynamodb') paginator = dynamodb.get_paginator('query') query_params = { 'TableName': 'YourTableName', 'KeyConditionExpression': 'pk = :pk_val AND sk > :sk_val', 'ExpressionAttributeValues': { ':pk_val': {'S': '123'}, ':sk_val': {'N': '1000'}, }, 'Limit': 100 } page_iterator = paginator.paginate(**query_params) for page in page_iterator: # Process the items however you like for item in page['Items']: print(item)

Weitere Informationen finden Sie im Leitfaden zu Paginatoren und in der API-Referenz für DynamoDB.Paginator.Query.

Anmerkung

Paginatoren haben auch ihre eigenen Konfigurationseinstellungen: MaxItems, StartingToken und PageSize. Für die Paginierung mit DynamoDB sollten Sie diese Einstellungen ignorieren.

Waiter

Waiter bieten die Möglichkeit, auf den Abschluss eines Vorgangs zu warten, bevor der nächste Schritt ausgeführt wird. Derzeit unterstützen sie nur das Warten auf die Erstellung oder Löschung einer Tabelle. Im Hintergrund prüft der Waiter alle 20 Sekunden, bis zu 25 Mal, ob der gewünschte Zustand erreicht wurde. Zwar könnten Sie diese Prüfung selbst implementieren, aber die Verwendung eines Waiters ist eine elegante Lösung beim Schreiben von Automatisierungsskripten.

Hier ist ein Beispielcode, der zeigt, wie Sie darauf warten können, dass eine bestimmte Tabelle erstellt wurde:

# Create a table, wait until it exists, and print its ARN response = client.create_table(...) waiter = client.get_waiter('table_exists') waiter.wait(TableName='YourTableName') print('Table created:', response['TableDescription']['TableArn']

Weitere Informationen finden Sie im Waiter-Leitfaden und in der Waiter-Referenz.