Blog

DynamoDB als Cache verwenden

Jan Vermeir

Aktualisiert Oktober 15, 2025
4 Minuten
Caching ist eine nützliche Technik, um die Leistung zu verbessern oder eine Überlastung von Diensten zu vermeiden. Es sind viele Lösungen verfügbar, und in AWS ist eine davon die Verwendung von DynamoDB. Die Verwendung von DynamoDB als Cache zum Speichern von Daten mit einer begrenzten Lebensdauer (TTL) war in unserem Anwendungsfall sinnvoll.
Wir haben die Datenbank bereits für Kundendaten verwendet. Durch die Verwendung als Cache konnten wir die Anzahl der Dienste, für die wir Expertenwissen benötigten, begrenzen. Außerdem ist sie ziemlich schnell und lässt sich weit über unseren Bedarf hinaus skalieren. In diesem Blog zeige ich, wie man einen Cache mit DynamoDB und einem in TypeScript geschriebenen Lambda implementiert. In einem Folgeblog zeige ich eine weitere Technik zur Verbesserung der Leistung von Abfragen auf großen Datensätzen. Den Quellcode für die Beispiele in diesem Blog finden Sie auf Github cache-blog. Ich habe CDK verwendet, um die für den Cache-Dienst benötigte Infrastruktur aufzubauen. Die Infrastruktur ist in cache-blog/lib/cache-blog-stack.ts definiert. Die wichtigsten Teile sind
const cacheTable = new dynamoDB.Table(this, 'CacheTable'...
und
const handler = new lambda.Function(this, 'CacheHandler', ...
Die Cache-Tabelle hat einen partitionKey namens id. Über diese id kann sehr effizient auf die Daten zugegriffen werden. Die Tabellendefinition fügt außerdem ein Attribut namens timeToLiveAttribute mit dem Wert ttl. Dieses Attribut steuert, wie lange ein Datensatz in der Tabelle gültig bleibt. DynamoDB entfernt einen Datensatz automatisch, wenn seine ttl abgelaufen ist. Es gibt keine sinnvollen Garantien für den Bereinigungsprozess, aber darauf werden wir später zurückkommen.
Dieser Code erstellt die Tabelle:
    const cacheTable = new dynamoDB.Table(this, 'CacheTable', {
      tableName: 'Cache',
      partitionKey: {
        name: 'id',
        type: dynamoDB.AttributeType.STRING,
      },
      billingMode: dynamoDB.BillingMode.PROVISIONED,
      timeToLiveAttribute: 'ttl',
      removalPolicy: cdk.RemovalPolicy.DESTROY,
    });
Das Lambda wird mit Node18 als Laufzeitumgebung definiert:
    const handler = new lambda.Function(this, 'CacheHandler', {
      runtime: lambda.Runtime.NODEJS_18_X,
      code: lambda.Code.fromAsset('lambda'),
      handler: 'cache.handler',
    });
Neben der Tabelle und dem Lambda, cache-blog-stack.ts definiert auch ein Api-Gateway, das den http-Zugriff auf den Cache-Lambda ermöglicht. Um den Stack einzusetzen, führen Sie aus:
cdk bootstrap
um den Stack in Ihrem aws-Konto zu erstellen. Und dann
npm run build && cdk deploy
Der Stack wird nun erstellt. Die Ausgabe zeigt den Endpunkt des Api-Gateways, der für den Zugriff auf das Caching-Lambda verwendet wird. Es sieht so aus:
CacheBlogStack
Deployment time: 22.37s
Outputs:
CacheBlogStack.CacheServicecacheapiEndpointDA49EE49 
  = https://0znqtkdtml.execute-api.eu-west-1.amazonaws.com/prod/
Jetzt können wir Werte aus dem Cache wie folgt speichern und abrufen:
curl -X POST https://0znqtkdtml.execute-api.eu-west-1.amazonaws.com/prod/ -H "Accept: application/json" -d '{ "id": "id1", "value":"30"}'

curl https://0znqtkdtml.execute-api.eu-west-1.amazonaws.com/prod/?id=id1
Der Wert von id spielt eigentlich keine Rolle, aber ein Muster, das wir für nützlich hielten, sieht so aus: <tableName> - < uuid >, z.B.. PersonalData - dbf275d5-d61b-488a-97fc-c2cb1832c852. Hier werden persönliche Daten für ein Benutzerkonto mit der ID dbf275d5-d61b-488a-97fc-c2cb1832c852 gespeichert, die möglicherweise von einem Backend-Dienst abgerufen werden. Im Prinzip würde der uuid-Wert ausreichen, aber wir haben festgestellt, dass wir oft verschiedene Arten von Daten über ein bestimmtes Benutzerkonto speichern möchten. In diesem Fall wäre die uuid die uuid des Kontos und das Präfix des Cache-Schlüssels würde die Art der Daten im Cache-Datensatz identifizieren. Der Lambda-Code ist einfach und implementiert eine GET- und POST-Methode. Die GET-Methode ist interessant, weil sie zeigt, wie man einen Fallstrick mit dem TTL-Attribut umgeht. const getCacheItem = async (id: string): ... in cache-blog/lambda/database.ts führt diese Abfrage aus, wenn Sie den Wert mit der angegebenen ID abrufen:
    const queryCommand = new QueryCommand({
      TableName: CACHE_TABLE,
      ExpressionAttributeNames: {
        '#id': 'id',
        '#ttl': 'ttl',
      },
      KeyConditionExpression: '#id = :id',
      ExpressionAttributeValues: {
        ':id': id,
        ':now': now,
      },
      FilterExpression: '#ttl > :now',
    });
Der wichtige Teil ist FilterExpression: '#ttl >:now'. Dieser Filterausdruck ist notwendig, weil DynamoDB nicht garantiert, dass veraltete Datensätze entfernt werden, wenn ihre TTL überschritten ist. Daher kann ein Datensatz noch in der Datenbank sein, obwohl er eigentlich abgelaufen ist. Wir können dieses Problem beheben, indem wir den Filterausdruck hinzufügen. Beachten Sie, dass die TTL in Sekunden ausgedrückt wird. Das Entfernen der für diesen Blog erstellten Infrastruktur kann mit CDK erfolgen:
cdk destroy
Are you sure you want to delete: CacheBlogStack (y/n)? y
CacheBlogStack: destroying... [1/1]
CacheBlogStack: destroyed

Referenzen:

Verfasst von

Jan Vermeir

Developing software and infrastructure in teams, doing whatever it takes to get stable, safe and efficient systems in production.

Contact

Let’s discuss how we can support your journey.