Cloud Bigtable para usuarios de Cassandra

1. Introducción

Este codelab es una guía para cualquier persona que migre consultas de Apache Cassandra a Google Cloud Bigtable.

En este codelab,

  • Usa el emulador de Cloud Bigtable
  • Explora un caso de uso de una serie temporal
  • Crea una tabla y una familia de columnas
  • Aprende los equivalentes de Java para Cloud Bigtable de insertar, actualizar, seleccionar y borrar CQL

¿Cómo calificarías tu experiencia en el uso de Google Cloud Platform?

Principiante Intermedio Avanzado

¿Cómo usarás este instructivo?

Solo lectura Léelo y completa los ejercicios. .
.

2. Configurar

Observarás un conjunto de datos de muestra con solo algunas filas, lo que te permitirá comprender los conceptos básicos rápidamente.

Cassandra

En cada paso, habrá consultas equivalentes de Cassandra, así que puedes seguir las instrucciones de un clúster local si lo deseas, o puedes configurar rápidamente un clúster de Cassandra con implementación en un clic y establecer una conexión SSH a él.

Si estás siguiendo el proceso, crea un espacio de teclas y úsalo. La estrategia de replicación no será importante en este caso.

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

Cloud Bigtable

Necesitarás una instancia de Cloud Bigtable para tu tabla. Puedes configurar una instancia local de forma gratuita con el emulador. No es necesario crear un espacio de claves en Cloud Bigtable, ya que la configuración de tu instancia se encarga de la replicación.

Usa el siguiente comando para iniciar el emulador:

gcloud beta emulators bigtable start

Luego, en otra ventana o pestaña del shell, configura la variable de entorno del emulador con este comando:

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

Luego, crea un proyecto de Java que usarás para ejecutar los ejemplos de código y, luego, importa el cliente de Cloud Bigtable con Maven, Gradle o SBT. Luego, en un nuevo archivo Java, crea una conexión con el cliente de datos.

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. Creación de tablas

Tanto en las tablas de Cassandra como en las de Cloud Bigtable, cada fila tiene una clave asociada. Las claves de Cassandra tienen una clave de partición y una columna de agrupamiento en clústeres que pueden estar separadas o superpuestas. Se usa la totalidad de las claves de Cloud Bigtable para las divisiones y el ordenamiento. Estos dos sistemas son increíblemente similares en lo que respecta a la construcción de claves primarias y de fila. Ambos sistemas son listas ordenadas lexicográficamente en las que las claves actúan como la forma principal de distribución de filas entre nodos. En la mayoría de los casos, puedes volver a usar la misma clave para Cloud Bigtable.

En este codelab, usarás Cloud Bigtable para almacenar datos de series temporales sobre teléfonos celulares y tablets (no debe confundirse con las tablets de Bigtable). A continuación, se encuentran las instrucciones para crear la tabla.

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

Puedes crear una tabla y una familia de columnas con el cliente de Java, pero es más fácil usar el siguiente comando con la herramienta cbt:

cbt createtable mobile-time-series families=stats_summary

Cloud Bigtable es una base de datos NoSQL, por lo que no necesitarás definir un esquema cuando crees la tabla, pero deberás pensar en las consultas que ejecutarás y optimizar la clave de fila para ellas.

La estrategia más común para la migración de claves es simplemente tomar todas las claves de partición y las columnas de agrupamiento en clústeres y unirlas a fin de formar una string que represente la clave de fila de Cloud Bigtable. Por lo general, recomendamos usar claves basadas en cadenas, ya que ayudan a depurar la distribución de claves a través de Key Visualizer. Puede utilizar un separador, como un hash “#” entre los valores de las columnas para facilitar la legibilidad.

En este ejemplo, usaremos una clave de fila de “[DEVICE_TYPE]#[DEVICE_ID]#[YYYYMMDD]"

4. Inserciones

Las inserciones son bastante similares entre Cassandra y Cloud Bigtable. Aquí insertarás una fila y, luego, varias con una clave de fila de "[DEVICE_TYPE]#[DEVICE_ID]#[YYYYMMDD]".

Cassandra

Sencillo

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

Sencillo

Crea una mutación con la clave de fila y los datos que deseas usar y, luego, aplícala con el cliente de datos. Agregarás una fila de datos de un teléfono con información sobre su conexión móvil y sistema operativo.

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

Define varias mutaciones en un objeto bulkMutation y, luego, usa el cliente de datos para aplicar todas las mutaciones con una llamada a la API. Agregarás algunos días de datos sobre el nombre y la versión del sistema operativo de una tablet móvil.

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. Actualizaciones

Aquí, actualizarás una celda que aún no se escribió y, luego, escribirás un valor nuevo en una celda, manteniendo también las versiones anteriores.

Cassandra

Cómo agregar celdas

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

Actualiza celdas

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

En Cloud Bigtable, se pueden tratar las actualizaciones como las escrituras.

Cómo agregar celdas

Esto es lo mismo que escribir celdas, solo debes proporcionar una columna en la que no hayas escrito anteriormente. Aquí deberás agregar el nombre del sistema operativo a la fila de teléfonos.

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());
}

Actualizando celdas

Aquí agregarás datos nuevos sobre el estado de conexión móvil del teléfono. Puedes usar versiones de celda para almacenar parte de los datos de series temporales con facilidad. Simplemente proporciona una marca de tiempo para tu escritura y agregarás una nueva versión para la celda. Para limpiar tus datos, puedes usar la recolección de elementos no utilizados para borrar versiones después de un período o una cantidad determinados.

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. Permite seleccionar

Ahora, recuperarás los datos que escribiste en la tabla. Cuando migras sentencias de selección de CQL, debes tener en cuenta varios aspectos de estas sentencias, como las columnas, el filtrado por cláusulas WHERE y las funciones de limitar y agregación, como Group by. Aquí, solo verás dos sentencias SELECT simples para obtener la idea básica, pero puedes revisar la documentación para obtener más información sobre la selección. En Cloud Bigtable, hay dos tipos de operaciones de recuperación: Get y Scan. Get recupera una fila, mientras que el análisis recupera un rango de filas.

Cassandra

Sencillo

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

Varios

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

Cloud Bigtable

Solteros

Usa la búsqueda de filas para obtener datos de un teléfono específico en la fecha especificada que se encuentre en una sola fila. Esto mostrará cada versión con marca de tiempo de los valores, por lo que deberías ver dos líneas para connected_cell en marcas de tiempo diferentes.

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());
}

Varias

Usa un análisis de rango para ver los datos de un mes de una tablet móvil específica, que se distribuyen en varias filas. Puedes usar un filtro con estos valores para obtener solo ciertas versiones de los datos o filtrar según los valores.

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. Eliminaciones

Aquí borrarás los datos que colocaste en tu tabla. Primero, eliminará una fila individual y, luego, eliminará varias filas.

El CQL de Cassandra permite la eliminación de filas individuales y de rangos cuando se especifican todas las columnas principales. Puedes hacerlo con Bigtable analizando un rango y, luego, realizando eliminaciones a nivel de fila. Ten en cuenta que obtendrás el mismo resultado, pero tendrás más operaciones, ya que cada eliminación será su propia operación.

Cassandra

Sencillo

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

Varios

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

Cloud Bigtable

Sencillo

Aquí borrarás los datos de un teléfono y una fecha específicos. Usa la clave de fila para borrar una fila a la vez.

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());
}

Varios

Aquí eliminarás todos los datos de una tableta específica. Para migrar una consulta de CQL que borra varias filas, tendrías que realizar un análisis y, luego, borrar cada fila con el conjunto resultante de claves de fila.

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. Últimos pasos

Realiza una limpieza

Cassandra

Si creaste un clúster de Cassandra para continuar con esto, puedes borrarlo como lo harías normalmente.

Cloud Bigtable

Si creaste tu tabla en una instancia existente de Cloud Bigtable, puedes borrarla con el comando cbt

cbt deletetable mobile-time-series

Si utilizaste el emulador, puedes detenerlo para borrar todo el trabajo, escribiendo CTRL-C en la terminal en la que lo iniciaste.

Próximos pasos