NoSQL-Implementierung von Amazon DynamoDB beschleunigen und verschlüsseln

Autor / Redakteur: Sascha Möllering * / Stephan Augsten

„Wir würden gerne Amazon DynamoDB nutzen, um eine vollständig verwaltete NoSQL-Implementierung nutzen zu können. Welche Empfehlungen und Entwurfsmuster existieren für Amazon DynamoDB?“

Anbieter zum Thema

Referenzarchitektur mit DynamoDB, wie sie beim Gaming-Anbieter Zynga zum Einsatz kommt.
Referenzarchitektur mit DynamoDB, wie sie beim Gaming-Anbieter Zynga zum Einsatz kommt.
(Bild: Amazon Web Services)

Amazon DynamoDB ist ein schneller, flexibler NoSQL-Datenbankservice für alle Anwendungen, die eine konsistente Latenz im einstelligen Millisekunden-Bereich für alle Größenordnungen benötigen. Es handelt sich um eine vollständig verwaltete Cloud-Datenbank, die sowohl Dokument- als auch Schlüssel-Wert-Speichermodelle unterstützt. Benutzer erstellen lediglich eine Datenbanktabelle, legen die angepeilte Nutzung für Auto Scaling fest und überlassen dem Service den Rest.

DynamoDB-Tabellen werden auf unterschiedliche Partitionen verteilt. Um bestmögliche Resultate zu erreichen, sollten sowohl die Anwendung als auch die Tabellen so gestaltet sein, dass alle Lesen- und Schreibaktivitäten über alle Einträge in den Tabellen möglichst gleich verteilt sind, um I/O-„Hotspots“ zu vermeiden, die die Geschwindigkeit signifikant reduzieren können.

Um eine optimale Nutzung des provisionierten Durchsatzes einer Tabelle hängt von folgenden Faktoren ab:

  • Der Wahl eines geeigneten Primärschlüssels
  • Die Zugriffsmuster auf individuelle Einträge

Der Primärschlüssel identifiziert eindeutig jeden Eintrag in der Tabelle und kann entweder einfach (ein Partitionsschlüssel) oder zusammengesetzt sein (Partitionsschlüssel und Sortierschlüssel). Wenn Daten gespeichert werden, werden die Einträge in einer Tabelle in mehreren Partitionen unterteilt. Die Daten werden dabei primär basierend auf dem Wert des Partitionsschlüssels verteilt.

Um einen möglichst hohen Durchsatz an Anfragen zu erreichen, sollte der Workload unterschiedliche Werte für den Partitionsschlüssel besitzen. Ein Beispiel für einen guten Partitionsschlüssel ist die Benutzer-ID, wenn eine Applikation sehr viele Benutzer hat. Ein Statuscode hingegen, bei dem nur wenige Status möglich sind, ist kein geeigneter Partitionsschlüssel.

Für die Optimierung von lese-lastigen Zugriffen existiert mit Amazon DynamoDB Accelerator (DAX) ein vollständig verwalteter In-Memory-Cache für DynamoDB, der die Reaktionszeiten drastisch senken kann. Bei DAX müssen sich die Entwickler nicht um Dinge wie Cache-Invalidierung, Befüllung des Caches oder Cluster-Management kümmern.

Global und Local Secondary Index

DynamoDB unterstützt zwei verschiedene Arten von Indizes: Global Secondary Indexes und Local Secondary Indexes. Ein Global Secondary Index ist ein Index mit einem Partitionsschlüssel und einem Sortierungsschlüssel, die sich von dem der Basistabelle unterscheiden können.

Im Gegensatz dazu hat ein Local Secondary Index denselben Partitionsschlüssel wie die Basistabelle, aber einen davon abweichenden Sortierungsschlüssel. Local Secondary Indexes sollten sparsam eingesetzt werden und beispielsweise nicht auf Basis von Attributen erzeugt werden, die nicht oft in Abfragen verwendet werden. Eine sinnvolle Anwendung von Local Secondary Indexes sind Tabellen, die nicht oft aktualisiert, dafür aber über viele unterschiedliche Kriterien abgefragt werden.

DynamoDB Streams

Ein besonders interessantes Feature von DynamoDB sind die DynamoDB Streams: Amazon DynamoDB kann mit AWS Lambda integriert werden damit Lambda-Funktionen in Abhängigkeit von Ereignissen aus dem DynamoDB-Stream aufgerufen werden können. Wenn eine Tabelle modifiziert wird, erscheint ein neuer Eintrag in dem Stream der Tabelle.

AWS Lambda fragt diesen Stream ab und ruft die entsprechende Lambda-Funktion auf, wenn ein Eintrag im Stream gefunden wird. Die Lambda-Funktion kann dabei beliebige Funktionalitäten implementieren, üblicherweise werden auf Basis der Ereignisse Nachrichten versendet oder Workflows gestartet.

Für die Verschlüsselung von Daten in einer Amazon-DynamoDB-Tabelle existiert ein Open-Source-Projekt, das eine Client-seitige Verschlüsselung von Attributen unterstützt. Die Nutzung dieser Bibliothek ist denkbar einfach.

Angenommen, wir haben eine DynamoDB-Tabelle mit dem Namen „MyStore“ und möchten dort Informationen über Bücher speichern. Sensitive Informationen beinhalten die Attribute „Title“ und „Authors“. Die Book-Klasse kann folgendermaßen implementiert werden:

@DynamoDBTable(tableName="MyStore")
public class Book {
   private Integer id;
   private String title;
   private String ISBN;
   private Set<String> bookAuthors;
   private String someProp;
   // Not encrypted because it is a hash key
   @DynamoDBHashKey(attributeName="Id")
   public Integer getId() { return id;}
   public void setId(Integer id) {this.id = id;}
   // Encrypted by default
   @DynamoDBAttribute(attributeName="Title")
   public String getTitle() {return title; }
   public void setTitle(String title) { this.title = title; }
   // Specifically not encrypted
   @DoNotEncrypt
   @DynamoDBAttribute(attributeName="ISBN")
   public String getISBN() { return ISBN; }
   public void setISBN(String ISBN) { this.ISBN = ISBN; }
   // Encrypted by default
   @DynamoDBAttribute(attributeName = "Authors")
   public Set<String> getBookAuthors() { return bookAuthors; }
   public void setBookAuthors(Set<String> bookAuthors)
      { this.bookAuthors = bookAuthors; }
   // Not encrypted nor signed
   @DoNotTouch
   public String getSomeProp() { return someProp;}
   public void setSomeProp(String someProp)
      {this.someProp = someProp;}
}

Um transparente Verschlüsselung zu aktivieren, muss ein Book-Eintrag folgendermaßen gespeichert und wieder geladen werden:

AmazonDynamoDBClient client = new AmazonDynamoDBClient(...);
SecretKey cek = ...;      // Content encrypting key
SecretKey macKey = ...;   // Signing key
EncryptionMaterialsProvider provider = new
   SymmetricStaticProvider(cek, macKey);
mapper = new DynamoDBMapper(client,
   DynamoDBMapperConfig.DEFAULT,
      new AttributeEncryptor(provider));
Book book = new Book();
book.setId(123);
book.setTitle("Secret Book Title ");
// ... etc. setting other properties
// Saves the book both encrypted and signed to DynamoDB
mapper.save(bookFrom);
// Loads the book both with signature verified and decrypted    from DynamoDB
Book bookTo = new Book();
bookTo.setId(123);
Book bookTo = mapper.load(bookTo);

Sascha Möllering
Sascha Möllering
(Bild: AWS Germany GmbH)

Falls nicht anders spezifiziert, werden alle Attribute mit Ausnahme der Primärschlüssel verschlüsselt. Um die Verschlüsselung selektiv zu deaktivieren, kann die Annotation @DoNotEncrypt verwendet werden.

* Sascha Möllering arbeitet als Solutions Architect bei der Amazon Web Services Germany GmbH. Seine Interessen liegen in den Bereichen Automation, Infrastructure as Code, Distributed Computing, Container und JVM.

(ID:44762339)