Cloud Bigtable für Cassandra-Nutzer

1. Einführung

Dieses Codelab ist ein Leitfaden für alle, die Abfragen von Apache Cassandra zu Google Cloud Bigtable migrieren.

In diesem Codelab

  • Cloud Bigtable-Emulator verwenden
  • Anwendungsfall für Zeitreihen ansehen
  • Tabelle und Spaltenfamilie erstellen
  • Lernen Sie die Java-Äquivalente von Cloud Bigtable für Einfügen, Aktualisieren, Auswählen und Löschen in CQL kennen

Wie würden Sie Ihre Erfahrungen im Umgang mit der Google Cloud Platform bewerten?

<ph type="x-smartling-placeholder"></ph> Neuling Mittel Kompetent

Wie möchten Sie diese Anleitung nutzen?

<ph type="x-smartling-placeholder"></ph> Nur bis zum Ende lesen Lies sie dir durch und absolviere die Übungen

2. Einrichten

Sie sehen sich ein Beispiel-Dataset mit nur wenigen Zeilen an, damit Sie sich schnell einen Überblick über die wichtigsten Konzepte verschaffen können.

Cassandra

Bei jedem Schritt sind gleichwertige Cassandra-Abfragen vorhanden. Sie können also gerne in einem lokalen Cluster mitarbeiten, wenn Sie möchten, oder schnell einen Click-to-Deploy-Cassandra-Cluster einrichten und eine SSH-Verbindung dazu herstellen.

Wenn Sie mitmachen, erstellen Sie einen Schlüsselraum und verwenden Sie ihn. Die Replikationsstrategie ist hier nicht wichtig.

cqlsh> create keyspace mykeyspace with replication = {'class':'SimpleStrategy','replication_factor' : 2};
cqlsh> use mykeyspace;

Cloud Bigtable

Sie benötigen eine Cloud Bigtable-Instanz für Ihre Tabelle. Mit dem Emulator können Sie eine lokale Instanz kostenlos einrichten. Sie müssen keinen Schlüsselraum in Cloud Bigtable erstellen. Ihre Replikation wird von Ihrer Instanzkonfiguration gesteuert.

Verwenden Sie den folgenden Befehl, um den Emulator zu starten:

gcloud beta emulators bigtable start

Legen Sie dann in einem anderen Shell-Fenster oder Tab die Umgebungsvariable des Emulators mit diesem Befehl fest:

$(gcloud beta emulators bigtable env-init) #Sets BIGTAB`LE_EMULATOR_HOST

Erstellen Sie dann ein Java-Projekt, in dem Sie die Codebeispiele ausführen, und importieren Sie den Cloud Bigtable-Client mit Maven, Gradle oder SBT. Erstellen Sie dann in einer neuen Java-Datei eine Verbindung zum Datenclient.

BigtableDataSettings settings =
    BigtableDataSettings.newBuilder().setProjectId(projectId).setInstanceId(instanceId).build();

try {
  dataClient = BigtableDataClient.create(settings);
} catch (Exception e) {
  System.out.println("Error during data client connection: \n" + e.toString());
}

3. Tabellenerstellung

Sowohl in Cassandra- als auch in Cloud Bigtable-Tabellen ist jeder Zeile ein Schlüssel zugeordnet. Cassandra-Schlüssel haben einen Partitionierungsschlüssel und eine Clustering-Spalte, die getrennt oder überlappend sein können. Die gesamten Cloud Bigtable-Schlüssel werden für Aufteilungen (Partitionen) und Sortierung verwendet. Bei der Erstellung von Haupt-/Zeilenschlüsseln sind diese beiden Systeme sehr ähnlich. Beide Systeme sind im Grunde lexikografisch sortierte Listen, bei denen die Schlüssel die Hauptform der Zeilenverteilung zwischen den Knoten sind. In den meisten Fällen können Sie denselben Schlüssel für Cloud Bigtable wiederverwenden.

In diesem Codelab verwenden Sie Cloud Bigtable zum Speichern von Zeitreihendaten über Smartphones und Tablets (nicht zu verwechseln mit Bigtable-Tablets). Nachfolgend finden Sie die Anleitung zum Erstellen der Tabelle.

Cassandra

cqlsh:mykeyspace> create table mobileTimeSeries (
           deviceid text,
           devicetype text,
           date date,
           connected_cell map<timestamp,Boolean>, 
           os_build text, 
           os_name text,
           PRIMARY KEY((devicetype, deviceid), date));

Cloud Bigtable

Sie können eine Tabelle und eine Spaltenfamilie mit dem Java-Client erstellen. Am einfachsten ist es aber, den folgenden Befehl mit dem cbt-Tool auszuführen:

cbt createtable mobile-time-series families=stats_summary

Cloud Bigtable ist eine NoSQL-Datenbank, daher müssen Sie bei der Tabellenerstellung kein Schema definieren. Sie sollten jedoch über die Abfragen nachdenken, die Sie ausführen werden, und den Zeilenschlüssel dafür optimieren.

Die gängigste Strategie für die Schlüsselmigration besteht darin, alle Partitionsschlüssel und Clustering-Spalten zu einem String zusammenzuführen, der den Cloud Bigtable-Zeilenschlüssel darstellt. Wir empfehlen im Allgemeinen, stringbasierte Schlüssel zu verwenden, da sie bei der Fehlerbehebung für die Schlüsselverteilung über Key Visualizer helfen. Sie können ein Trennzeichen wie z. B. eine Raute „#“ verwenden zwischen den Spaltenwerten, um die Lesbarkeit zu verbessern.

In diesem Beispiel verwenden wir den Zeilenschlüssel "[DEVICE_TYPE]#[DEVICE_ID]#[YYYYMMDD]".

4. Einfügungen

Einfügungen sind bei Cassandra und Cloud Bigtable ziemlich ähnlich. Hier fügen Sie eine Zeile und dann mehrere Zeilen mit dem Zeilenschlüssel "[DEVICE_TYPE]#[DEVICE_ID]#[JJJJMMTT]" ein.

Cassandra

Single

cqlsh:mykeyspace> insert into mobileTimeSeries (deviceid, devicetype, date, connected_cell, os_build) values ('4c410523', 'phone',toDate(now()), {toTimeStamp(now()): true}, 'PQ2A.190405.003');

Batch

cqlsh:mykeyspace> BEGIN BATCH
insert into mobileTimeSeries (deviceid, devicetype, date, os_name, os_build) values ('a0b81f74', 'tablet', '2019-01-01', 'chromeos', '12155.0.0-rc1');
insert into mobileTimeSeries (deviceid, devicetype, date, os_name, os_build) values ('a0b81f74', 'tablet', '2019-01-02','chromeos', '12145.0.0-rc6');
APPLY BATCH;

Cloud Bigtable

Single

Erstellen Sie eine Mutation mit dem Zeilenschlüssel und den Daten, die Sie verwenden möchten, und wenden Sie die Mutation dann mit dem Datenclient an. Sie fügen eine Datenzeile für ein Smartphone mit Informationen zu seiner Mobilfunkverbindung und dem Betriebssystem hinzu.

try {
  System.currentTimeMillis();
  long timestamp = (long) 1556712000 * 1000; // Timestamp of June 1, 2019 12:00

  String rowKey = "phone#4c410523#20190501";
  ByteString one = ByteString.copyFrom(new byte[] {0, 0, 0, 0, 0, 0, 0, 1});

  RowMutation rowMutation =
      RowMutation.create(tableId, rowKey)
          .setCell(
              COLUMN_FAMILY_NAME,
              ByteString.copyFrom("connected_cell".getBytes()),
              timestamp,
              one)
          .setCell(COLUMN_FAMILY_NAME, "os_build", timestamp, "PQ2A.190405.003");

  dataClient.mutateRow(rowMutation);
} catch (Exception e) {
  System.out.println("Error during Write: \n" + e.toString());
}

Batch

Definieren Sie mehrere Mutationen für ein BulkMutation-Objekt und verwenden Sie dann den Datenclient, um alle Mutationen mit einem einzigen API-Aufruf anzuwenden. Sie fügen einige Tage Daten zum Betriebssystemnamen und zur Betriebssystemversion eines Smartphones hinzu.

try {
  long timestamp = (long) 1556712000 * 1000; // Timestamp of June 1, 2019 12:00

  BulkMutation bulkMutation =
      BulkMutation.create(tableId)
          .add(
              "tablet#a0b81f74#20190501",
              Mutation.create()
                  .setCell(COLUMN_FAMILY_NAME, "os_name", timestamp, "chromeos")
                  .setCell(COLUMN_FAMILY_NAME, "os_build", timestamp, "12155.0.0-rc1"))
          .add(
              "tablet#a0b81f74#20190502",
              Mutation.create()
                  .setCell(COLUMN_FAMILY_NAME, "os_name", timestamp, "chromeos")
                  .setCell(COLUMN_FAMILY_NAME, "os_build", timestamp, "12155.0.0-rc6"));

  dataClient.bulkMutateRows(bulkMutation);
} catch (Exception e) {
  System.out.println("Error during WriteBatch: \n" + e.toString());
}

5. Updates

Hier aktualisieren Sie eine Zelle, die noch nicht geschrieben wurde, und schreiben dann einen neuen Wert in eine Zelle und behalten gleichzeitig die vorherigen Versionen bei.

Cassandra

Zellen hinzufügen

cqlsh:mykeyspace> UPDATE mobileTimeSeries SET os_name = 'android' WHERE devicetype='phone' AND deviceid = '4c410523' AND date = '2019-09-06';

Zellen aktualisieren

cqlsh:mykeyspace> UPDATE mobileTimeSeries SET connected_cell = connected_cell +  {toTimeStamp(now()): false} WHERE devicetype='phone' AND deviceid = '4c410523' AND date = '2019-09-06';

Cloud Bigtable

In Cloud Bigtable können Aktualisierungen wie Schreibvorgänge behandelt werden.

Zellen hinzufügen

Dies entspricht dem Schreiben von Zellen. Geben Sie nur eine Spalte an, in die Sie noch nie geschrieben haben. Hier geben Sie den Namen des Betriebssystems in die Zeile des Smartphones ein.

try {
  long timestamp = (long) 1556713800 * 1000; // Timestamp of June 1, 2019 12:30

  String rowKey = "phone#4c410523#20190501";

  RowMutation rowMutation =
      RowMutation.create(tableId, rowKey)
          .setCell(COLUMN_FAMILY_NAME, "os_name", timestamp, "android");

  dataClient.mutateRow(rowMutation);
} catch (Exception e) {
  System.out.println("Error during update: \n" + e.toString());
}

Zellen werden aktualisiert

Hier kannst du neue Daten zum Status der Mobilfunkverbindung des Smartphones hinzufügen. Sie können Zellenversionen verwenden, um einen Teil der Zeitreihendaten einfach zu speichern. Geben Sie einfach einen Zeitstempel für Ihren Schreibvorgang an und Sie fügen eine neue Version für die Zelle hinzu. Zum Bereinigen Ihrer Daten können Sie die automatische Speicherbereinigung verwenden, um Versionen nach einer bestimmten Anzahl oder nach einem bestimmten Zeitraum zu löschen.

try {
  long timestamp = (long) 1556713800 * 1000; // Timestamp of June 1, 2019 12:30

  String rowKey = "phone#4c410523#20190501";

  ByteString zero = ByteString.copyFrom(new byte[] {0, 0, 0, 0, 0, 0, 0, 0});

  RowMutation rowMutation =
      RowMutation.create(tableId, rowKey)
          .setCell(
              COLUMN_FAMILY_NAME,
              ByteString.copyFrom("connected_cell".getBytes()),
              timestamp,
              zero);

  dataClient.mutateRow(rowMutation);
} catch (Exception e) {
  System.out.println("Error during update2: \n" + e.toString());
}

6. Auswählen

Jetzt rufen Sie die Daten ab, die Sie in die Tabelle geschrieben haben. Bei der Migration von CQL-Select-Anweisungen müssen Sie verschiedene Aspekte von select-Anweisungen berücksichtigen, z. B. Spalten, das Filtern durch Wo-Klauseln und Begrenzungs- und Aggregatfunktionen wie group by. Hier sehen Sie sich nur zwei einfache Auswahlanweisungen an, um eine Grundidee zu erhalten. Weitere Informationen zur Auswahl finden Sie in der Dokumentation. In Cloud Bigtable gibt es zwei Arten von Abrufvorgängen: Get und Scan. Mit "Get" wird eine Zeile abgerufen, während beim Scan ein Zeilenbereich abgerufen wird.

Cassandra

Single

cqlsh:mykeyspace> SELECT * FROM mobileTimeSeries WHERE devicetype='phone' AND deviceid = '4c410523' AND date = '2019-09-04';

Mehrere

cqlsh:mykeyspace> SELECT * FROM mobileTimeSeries WHERE devicetype='tablet' AND deviceid = 'a0b81f74' AND date >= '2019-09-04';

Cloud Bigtable

Single

Verwenden Sie eine Zeilensuche, um Daten für ein bestimmtes Telefon am angegebenen Datum zu erhalten, und das alles in einer Zeile. Dadurch wird jede Version der Werte mit Zeitstempel zurückgegeben, sodass für „connect_cell“ zwei Zeilen mit unterschiedlichen Zeitstempeln angezeigt werden.

try {
  String rowKey = "phone#4c410523#20190501";

  Row row = dataClient.readRow(tableId, rowKey);
  for (RowCell cell : row.getCells()) {

    System.out.printf(
        "Family: %s    Qualifier: %s    Value: %s    Timestamp: %s%n",
        cell.getFamily(),
        cell.getQualifier().toStringUtf8(),
        cell.getValue().toStringUtf8(),
        cell.getTimestamp());
  }
} catch (Exception e) {
  System.out.println("Error during lookup: \n" + e.toString());
}

Mehrere

Mit einem Bereichsscan können Sie die Daten eines Monats für ein bestimmtes Smartphone anzeigen, die auf mehrere Zeilen verteilt sind. Damit können Sie einen Filter verwenden, um nur bestimmte Versionen der Daten abzurufen oder nach Werten zu filtern.

try {
  Query query = Query.create(tableId).range("tablet#a0b81f74#201905", "tablet#a0b81f74#201906");
  ServerStream<Row> rowStream = dataClient.readRows(query);
  for (Row row : rowStream) {
    System.out.println("Row Key: " + row.getKey().toStringUtf8());
    for (RowCell cell : row.getCells()) {

      System.out.printf(
          "Family: %s    Qualifier: %s    Value: %s    Timestamp: %s%n",
          cell.getFamily(),
          cell.getQualifier().toStringUtf8(),
          cell.getValue().toStringUtf8(),
          cell.getTimestamp());
    }
  }
} catch (Exception e) {
  System.out.println("Error during scan: \n" + e.toString());
}

7. Löschvorgänge

Hier löschen Sie die Daten, die Sie in Ihre Tabelle eingefügt haben. Löschen Sie zuerst eine einzelne Zeile und dann mehrere Zeilen.

Die Cassandra-CQL ermöglicht das Löschen einzelner Zeilen sowie das Entfernen von Bereichen, wenn alle primären Spalten angegeben sind. Dies können Sie mit Bigtable tun, indem Sie einen Bereich scannen und dann Löschvorgänge auf Zeilenebene durchführen. Beachten Sie, dass Sie das gleiche Ergebnis erhalten, aber über mehr Vorgänge verfügen, da jeder Löschvorgang ein eigener Vorgang ist.

Cassandra

Single

cqlsh:mykeyspace> DELETE from mobileTimeSeries where devicetype='phone' and deviceid = '4c410523';

Mehrere

cqlsh:mykeyspace> DELETE from mobileTimeSeries where devicetype='tablet' and deviceid = 'a0b81f74';

Cloud Bigtable

Single

Hier löschen Sie die Daten für ein bestimmtes Telefon und ein bestimmtes Datum. Mit dem Zeilenschlüssel können Sie einzelne Zeilen löschen.

try {
  String rowKey = "phone#4c410523#20190501";

  RowMutation mutation = RowMutation.create(tableId, rowKey).deleteRow();

  dataClient.mutateRow(mutation);
} catch (Exception e) {
  System.out.println("Error during Delete: \n" + e.toString());
}

Mehrere

Hier löschen Sie alle Daten für ein bestimmtes Smartphone. Wenn Sie eine CQL-Abfrage migrieren möchten, bei der mehrere Zeilen gelöscht werden, müssen Sie einen Scan ausführen und dann jede Zeile mit dem resultierenden Zeilenschlüssel löschen.

try {
  Query query = Query.create(tableId).prefix("tablet#a0b81f7");
  ServerStream<Row> rowStream = dataClient.readRows(query);
  BulkMutation bulkMutation = BulkMutation.create(tableId);
  for (Row row : rowStream) {
    bulkMutation.add(row.getKey(), Mutation.create().deleteRow());
  }

  dataClient.bulkMutateRows(bulkMutation);
} catch (Exception e) {
  System.out.println("Error during DeleteMultiple: \n" + e.toString());
}

8. Fertigstellen

Aufräumen

Cassandra

Wenn Sie zu diesem Zweck einen Cassandra-Cluster erstellt haben, können Sie ihn wie gewohnt löschen.

Cloud Bigtable

Wenn Sie die Tabelle in einer vorhandenen Cloud Bigtable-Instanz erstellt haben, können Sie sie mit dem cbt-Befehl löschen.

cbt deletetable mobile-time-series

Wenn Sie den Emulator verwendet haben, können Sie ihn einfach beenden, um die gesamte Arbeit zu löschen. Drücken Sie dazu in dem Terminal, in dem Sie ihn gestartet haben, Strg + C.

Weiteres Vorgehen