Neuigkeiten von trion.
Immer gut informiert.

Cassandra Schema Migration mit Spring Boot

Cassandra ist eine noSQL Datenbank, die insbesondere im Kontext großer Datenmengen bei sehr hoher Verfügbarkeit eingesetzt wird. Dabei ist bei Cassandra entscheidend, dass das Schema passend zu den jeweils zu unterstützenden Anwendungsfällen konzipiert ist: Nur so wird die hohe Geschwindigkeit von Cassandra und die Verfügbarkeit sicher gestellt.

Doch Anforderungen können sich ändern, und damit muss auch die Anwendung angepasst werden. Das kann sich auch auf die Datenstrukturen in Cassandra auswirken.
Ein Weg, damit umzugehen, sind Cassandra Materialized Views oder ein kompletter Datenexport als CSV und Re-Import. Bei den für Cassandra typischen großen Datenmengen ist das selten praktikabel.

Unabhängig davon, um man sehr kleine Datenmengen in Cassandra vorhält, zum Beispiel zur Entwicklungszeit, oder eine spezielle Migrationsanwendung für den produktiven Einsatz mit Cassandra erstellt: Die Migrationen sollten sich einfach verwalten und in der Versionskontrolle ablegen lassen.

Analog zu Liquibase und Flyway gibt es Werkzeuge und Libraries zur Schemaverwaltung von Cassandra. Leider sind einige auch nicht mehr aktiv gepflegt, wie zum Beispiel:

Oder werden zwar aktiv gepflegt, sind jedoch lediglich für Cassandra 3 und nich für Cassandra 4 verfügbar:

Daher wird im folgenden das cassandra-migration Projekt (https://github.com/patka/cassandra-migration) vorgestellt. Der Branch _v4 ist speziell für Cassandra 4 konzipiert, was zu aktuellen Spring Boot Versionen passt.

Um cassandra-migration in einem Projekt einzusetzen, wird zunächst die Abhängigkeit ergänzt. Speziell für Spring Boot gibt es eine zusätzliche Abhängigkeit, die eine automatische Konfiguration und die Verwendung von Spring ConfigurationProperties unterstützt.

cassandra-migration Abhängigkeiten
<dependency>
    <groupId>org.cognitor.cassandra</groupId>
    <artifactId>cassandra-migration</artifactId>
    <version>2.5.0_v4</version>
</dependency>
<dependency>
    <groupId>org.cognitor.cassandra</groupId>
    <artifactId>cassandra-migration-spring-boot-starter</artifactId>
    <version>2.5.0_v4</version>
</dependency>

Durch Properties können dann relevante Parameter für die Cassandra Migration unter dem Präfix cassandra.migration. eingestellt werden:

  • keyspace-name: zu verwaltender Keyspace

  • script-location: Ort für CQL Scripte (Default: cassandra/migration )

  • strategy: Entweder IGNORE_DUPLICATES oder FAIL_ON_DUPLICATES

  • consistency-level: Consistency-Level für Migrationsausführung

  • table-prefix: Präfix für Tabelle zur Verwaltung von Migrationen

  • with-consensus: Soll bei parallelen Anwendungen lediglich ein Leader existieren (Default: false )

Die Library erwartet eine besonders ausgezeichnete Cassandra CQL Session, um die Migrationen durchzuführen. Mit dem @Qualifier("cassandraMigrationCqlSession") wird diese Spring Bean entsprechend bereitgestellt.

CQL Session für Migration
@Qualifier("cassandraMigrationCqlSession")  // (1)
@Bean
CqlSession cassandraMigrationCqlSession(CqlSessionBuilder cqlSessionBuilder)   // (2)
{
    final CqlSession cqlSession = cqlSessionBuilder.withKeyspace((CqlIdentifier) null)
        .build();
    var query = "CREATE KEYSPACE IF NOT EXISTS demo WITH replication = {'class':'SimpleStrategy','replication_factor':1};"; // (3)
    cqlSession.execute(query);
    return cqlSession;
}
  1. Die Spring Integration erwartet eine Bean mit diesem Qualifier

  2. Um Property Konfiguration zu nutzen wird Builder weiter verwendet

  3. Falls erforderlich, können zusätzliche Queries definiert werden

Zur Nutzung durch die Anwendung wird eine separate CQL Session bereitgestellt.

CQL Session für Anwendung
@DependsOn("migrationTask")  // (1)
@Primary  // (2)
@Bean
public CqlSession cqlSession(CqlSessionBuilder cqlSessionBuilder, MeterRegistry meterRegistry)
{
    return cqlSessionBuilder.withMetricRegistry(meterRegistry).build();
}
  1. Damit auf jeden Fall Migrationen als erstes erfolgen, wird darauf gewartet

  2. Spring löst nach Typ auf, um Konflikt der beiden CqlSessions aufzulösen, kann @Primary verwendet werden

Die Migrationsdateien werden nach dem Schema <version>_<name>.cql gesucht und der Reihe nach ausgeführt. Zur Protokollierung und Koordination werden im Keyspace zusätzliche Verwaltungstabellen erzeugt. In schema_migration findet sich die Historie über Migrationen. Zur Koordinierung bei paralleler Ausführung wird die Tabelle schema_migration_leader verwendet.

Im folgenden findet sich ein Beispiel für ein in CQL erstelltes Script zur Schemaevolution von Cassandra:

Beispiel Migrationsscript
-- create a table
CREATE TABLE demo.users
(
   user_id uuid,
   first_name text,
   last_name text,
   PRIMARY KEY (user_id)
);
-- # create some more keyspaces to illustrate slow migration
CREATE KEYSPACE IF NOT EXISTS other WITH replication = {'class': 'SimpleStrategy' , 'replication_factor': 1 }  ;
CREATE KEYSPACE IF NOT EXISTS other2 WITH replication = {'class': 'SimpleStrategy' , 'replication_factor': 1 }  ;

Die vorgestellte Library fügt sich erkennbar gut in Spring Boot ein und eignet sich sowohl zur Bereitstellung von Migrationen für ein agiles Entwicklungsteam als auch als Grundlage zur Erstellung von Migrationsanwendungen von Cassandra.




Zu den Themen Cassandra, Spring Boot und Docker bieten wir sowohl Beratung, Entwicklungsunterstützung als auch passende Schulungen an:

Auch für Ihren individuellen Bedarf können wir Workshops und Schulungen anbieten. Sprechen Sie uns gerne an.

Feedback oder Fragen zu einem Artikel - per Twitter @triondevelop oder E-Mail freuen wir uns auf eine Kontaktaufnahme!

Zur Desktop Version des Artikels