Bigtable et Dataflow: Surveillance de bases de données (client Java HBase)

1. Introduction

Dans cet atelier de programmation, vous allez utiliser les outils de surveillance de Cloud Bigtable pour créer diverses œuvres d'art via l'écriture et la lecture de données avec Cloud Dataflow et le client Java HBase.

Vous apprendrez à effectuer les tâches suivantes :

  • Charger de grandes quantités de données dans Bigtable à l'aide de Cloud Dataflow
  • Surveiller les instances et les tables Bigtable pendant l'ingestion de vos données
  • Interroger Bigtable avec un job Dataflow
  • Explorer l'outil Key Visualizer qui peut être utilisé pour identifier les hotspots en raison de la conception de votre schéma
  • Créer des œuvres d'art à l'aide de Key Visualizer

d098cc81f78f02eb.png

Comment évalueriez-vous votre expérience avec Cloud Bigtable ?

Débutant Intermédiaire Expert

Comment allez-vous utiliser ce tutoriel ?

<ph type="x-smartling-placeholder"></ph> Je vais seulement le lire Je vais le lire et effectuer les exercices
.

2. Créer votre base de données Bigtable

Cloud Bigtable est le service de base de données NoSQL big data de Google. Cette base de données est utilisée par de nombreux services principaux de Google, tels que la recherche, Analytics, Maps et Gmail. Il est idéal pour exécuter des charges de travail analytiques volumineuses et créer des applications à faible latence. Pour une présentation plus détaillée, reportez-vous à l'atelier de programmation Cloud Bigtable.

Créer un projet

Commencez par créer un projet. Utiliser la fenêtre Cloud Shell intégrée, que vous pouvez ouvrir en cliquant sur "Activer Cloud Shell" dans le coin supérieur droit.

a74d156ca7862b28.png

Définissez les variables d'environnement suivantes pour faciliter la copie et le collage des commandes de l'atelier de programmation:

BIGTABLE_PROJECT=$GOOGLE_CLOUD_PROJECT
INSTANCE_ID="keyviz-art-instance"
CLUSTER_ID="keyviz-art-cluster"
TABLE_ID="art"
CLUSTER_NUM_NODES=1
CLUSTER_ZONE="us-central1-c" # You can choose a zone closer to you

Cloud Shell est fourni avec les outils que vous utiliserez dans cet atelier de programmation : l'outil de ligne de commande gcloud, l'interface de ligne de commande cbt et Maven, qui sont déjà installés.

Activez les API Cloud Bigtable en exécutant cette commande.

gcloud services enable bigtable.googleapis.com bigtableadmin.googleapis.com

Créez une instance en exécutant la commande suivante:

gcloud bigtable instances create $INSTANCE_ID \
    --cluster=$CLUSTER_ID \
    --cluster-zone=$CLUSTER_ZONE \
    --cluster-num-nodes=$CLUSTER_NUM_NODES \
    --display-name=$INSTANCE_ID

Une fois l'instance créée, remplissez le fichier de configuration cbt, puis créez une table et une famille de colonnes en exécutant les commandes suivantes:

echo project = $GOOGLE_CLOUD_PROJECT > ~/.cbtrc
echo instance = $INSTANCE_ID >> ~/.cbtrc

cbt createtable $TABLE_ID
cbt createfamily $TABLE_ID cf

3. Apprendre à écrire dans Bigtable avec Dataflow

Principes de base de l'écriture

Lorsque vous écrivez dans Cloud Bigtable, vous devez fournir un objet de configuration CloudBigtableTableConfiguration. Cet objet spécifie l'ID de projet et l'ID d'instance de votre table, ainsi que le nom de la table elle-même:

CloudBigtableTableConfiguration bigtableTableConfig =
    new CloudBigtableTableConfiguration.Builder()
        .withProjectId(PROJECT_ID)
        .withInstanceId(INSTANCE_ID)
        .withTableId(TABLE_ID)
        .build();

Votre pipeline peut ensuite transmettre des objets HBase Mutation, qui peuvent inclure PUT et Delete.

p.apply(Create.of("hello", "world"))
    .apply(
        ParDo.of(
            new DoFn<String, Mutation>() {
              @ProcessElement
              public void processElement(@Element String rowkey, OutputReceiver<Mutation> out) {
                long timestamp = System.currentTimeMillis();
                Put row = new Put(Bytes.toBytes(rowkey));

                row.addColumn(...);
                out.output(row);
              }
            }))
    .apply(CloudBigtableIO.writeToTable(bigtableTableConfig));

Tâche Dataflow LoadData

La page suivante vous montre comment exécuter le job LoadData, mais je vais maintenant mentionner les parties importantes du pipeline.

Pour générer des données, vous allez créer un pipeline qui utilise la classe GenerateSequence (semblable à une boucle For) pour écrire un certain nombre de lignes avec quelques mégaoctets de données aléatoires. Le numéro de séquence sera rempli et inversé dans la clé de ligne. 250 devient donc 0000000052.

LoadData.java

String numberFormat = "%0" + maxLength + "d";

p.apply(GenerateSequence.from(0).to(max))
    .apply(
        ParDo.of(
            new DoFn<Long, Mutation>() {
              @ProcessElement
              public void processElement(@Element Long rowkey, OutputReceiver<Mutation> out) {
                String paddedRowkey = String.format(numberFormat, rowkey);

                // Reverse the rowkey for more efficient writing
                String reversedRowkey = new StringBuilder(paddedRowkey).reverse().toString();
                Put row = new Put(Bytes.toBytes(reversedRowkey));

                // Generate random bytes
                byte[] b = new byte[(int) rowSize];
                new Random().nextBytes(b);

                long timestamp = System.currentTimeMillis();
                row.addColumn(Bytes.toBytes(COLUMN_FAMILY), Bytes.toBytes("C"), timestamp, b);
                out.output(row);
              }
            }))
    .apply(CloudBigtableIO.writeToTable(bigtableTableConfig));

4. Générer des données dans Bigtable et surveiller les entrées

Les commandes suivantes exécutent un job de flux de données qui génère 40 Go de données dans votre table, ce qui est largement suffisant pour permettre l'activation de Key Visualizer:

Activer l'API Cloud Dataflow

gcloud services enable dataflow.googleapis.com

Récupérez le code sur GitHub et accédez au répertoire.

git clone https://github.com/GoogleCloudPlatform/java-docs-samples.git
cd java-docs-samples/bigtable/beam/keyviz-art

Générer les données (le script prend environ 15 minutes)

mvn compile exec:java -Dexec.mainClass=keyviz.LoadData \
"-Dexec.args=--bigtableProjectId=$BIGTABLE_PROJECT \
--bigtableInstanceId=$INSTANCE_ID --runner=dataflow \
--bigtableTableId=$TABLE_ID --project=$GOOGLE_CLOUD_PROJECT"

Surveiller l'importation

Vous pouvez surveiller la tâche dans l'interface utilisateur de Cloud Dataflow. Vous pouvez également afficher la charge sur votre instance Cloud Bigtable avec son UI de surveillance.

Dans l'interface utilisateur de Dataflow, vous pourrez voir le graphique du job et ses différentes métriques, y compris les éléments traités, les vCPU actuels et le débit.

9cecc290f5acea15.png

abb0561342dc6b60.png

Bigtable dispose d'outils de surveillance standards pour les opérations de lecture/écriture, l'espace de stockage utilisé, le taux d'erreur et plus encore au niveau de l'instance, du cluster et de la table. En outre, Bigtable dispose également de Key Visualizer, qui détaille votre utilisation en fonction des clés de ligne que nous utiliserons une fois qu'au moins 30 Go de données auront été générés.

996f8589332dfc19.png

5. Apprendre: Lire des données depuis Bigtable avec Dataflow

Bases de la lecture

Lorsque vous lisez des données depuis Cloud Bigtable, vous devez fournir un objet de configuration CloudBigtableTableScanConfiguration. Cette méthode est semblable à CloudBigtableTableConfiguration, mais vous pouvez spécifier les lignes à analyser et à partir desquelles lire.

Scan scan = new Scan();
scan.setCacheBlocks(false);
scan.setFilter(new FirstKeyOnlyFilter());

CloudBigtableScanConfiguration config =
    new CloudBigtableScanConfiguration.Builder()
        .withProjectId(options.getBigtableProjectId())
        .withInstanceId(options.getBigtableInstanceId())
        .withTableId(options.getBigtableTableId())
        .withScan(scan)
        .build();

Utilisez-le ensuite pour démarrer votre pipeline:

p.apply(Read.from(CloudBigtableIO.read(config)))
    .apply(...

Toutefois, si vous souhaitez effectuer une lecture dans le cadre de votre pipeline, vous pouvez transmettre un CloudBigtableTableConfiguration à un doFn qui étend AbstractCloudBigtableTableDoFn.

p.apply(GenerateSequence.from(0).to(10))
    .apply(ParDo.of(new ReadFromTableFn(bigtableTableConfig, options)));

Appelez ensuite super() avec votre configuration et getConnection() pour obtenir une connexion distribuée.

public static class ReadFromTableFn extends AbstractCloudBigtableTableDoFn<Long, Void> {
    public ReadFromTableFn(CloudBigtableConfiguration config, ReadDataOptions readDataOptions) {
      super(config);
    }

    @ProcessElement
    public void processElement(PipelineOptions po) {
        Table table = getConnection().getTable(TableName.valueOf(options.getBigtableTableId()));
        ResultScanner imageData = table.getScanner(scan);
    }   
}

Tâche Dataflow ReadData

Pour cet atelier de programmation, vous devrez lire la table toutes les secondes. Vous pourrez donc démarrer votre pipeline avec une séquence générée qui déclenche plusieurs plages de lecture en fonction de l'heure d'entrée d'un fichier CSV.

Il existe un certain nombre de calculs pour déterminer les plages de lignes à analyser en fonction de l'heure, mais vous pouvez cliquer sur le nom du fichier pour afficher le code source si vous souhaitez en savoir plus.

ReadData.java

p.apply(GenerateSequence.from(0).withRate(1, new Duration(1000)))
    .apply(ParDo.of(new ReadFromTableFn(bigtableTableConfig, options)));

ReadData.java

  public static class ReadFromTableFn extends AbstractCloudBigtableTableDoFn<Long, Void> {

    List<List<Float>> imageData = new ArrayList<>();
    String[] keys;

    public ReadFromTableFn(CloudBigtableConfiguration config, ReadDataOptions readDataOptions) {
      super(config);
      keys = new String[Math.toIntExact(getNumRows(readDataOptions))];
      downloadImageData(readDataOptions.getFilePath());
      generateRowkeys(getNumRows(readDataOptions));
    }

    @ProcessElement
    public void processElement(PipelineOptions po) {
      // Determine which column will be drawn based on runtime of job.
      long timestampDiff = System.currentTimeMillis() - START_TIME;
      long minutes = (timestampDiff / 1000) / 60;
      int timeOffsetIndex = Math.toIntExact(minutes / KEY_VIZ_WINDOW_MINUTES);

      ReadDataOptions options = po.as(ReadDataOptions.class);
      long count = 0;

      List<RowRange> ranges = getRangesForTimeIndex(timeOffsetIndex, getNumRows(options));
      if (ranges.size() == 0) {
        return;
      }

      try {
        // Scan with a filter that will only return the first key from each row. This filter is used
        // to more efficiently perform row count operations.
        Filter rangeFilters = new MultiRowRangeFilter(ranges);
        FilterList firstKeyFilterWithRanges = new FilterList(
            rangeFilters,
            new FirstKeyOnlyFilter(),
            new KeyOnlyFilter());
        Scan scan =
            new Scan()
                .addFamily(Bytes.toBytes(COLUMN_FAMILY))
                .setFilter(firstKeyFilterWithRanges);

        Table table = getConnection().getTable(TableName.valueOf(options.getBigtableTableId()));
        ResultScanner imageData = table.getScanner(scan);
      } catch (Exception e) {
        System.out.println("Error reading.");
        e.printStackTrace();
      }
    }

    /**
     * Download the image data as a grid of weights and store them in a 2D array.
     */
    private void downloadImageData(String artUrl) {
    ...
    }

    /**
     * Generates an array with the rowkeys that were loaded into the specified Bigtable. This is
     * used to create the correct intervals for scanning equal sections of rowkeys. Since Bigtable
     * sorts keys lexicographically if we just used standard intervals, each section would have
     * different sizes.
     */
    private void generateRowkeys(long maxInput) {
    ...
    }

    /**
     * Get the ranges to scan for the given time index.
     */
    private List<RowRange> getRangesForTimeIndex(@Element Integer timeOffsetIndex, long maxInput) {
    ...
    }
  }

6. Créez votre chef-d'œuvre

ad9c4c0b90626a3b.png

Maintenant que vous savez comment charger des données dans Bigtable et les lire avec Dataflow, vous pouvez exécuter la commande finale qui générera une image de la Joconde pendant huit heures.

mvn compile exec:java -Dexec.mainClass=keyviz.ReadData \
"-Dexec.args=--bigtableProjectId=$BIGTABLE_PROJECT \
--bigtableInstanceId=$INSTANCE_ID --runner=dataflow \
--bigtableTableId=$TABLE_ID --project=$GOOGLE_CLOUD_PROJECT"

Vous pouvez utiliser un bucket avec des images existantes. Vous pouvez également créer un fichier d'entrée à partir de l'une de vos propres images à l'aide de cet outil, puis l'importer dans un bucket GCS public.

Les noms de fichiers sont créés à partir de l'exemple gs://keyviz-art/[painting]_[hours]h.txt: gs://keyviz-art/american_gothic_4h.txt

options de peinture:

  • american_gothic
  • mona_lisa
  • pearl_earring
  • persistence_of_memory
  • starry_night
  • sunday_afternoon
  • the_scream

Options relatives aux heures: 1, 4, 8, 12, 24, 48, 72, 96, 120, 144

Rendez votre bucket ou fichier GCS public en attribuant le rôle Storage Object Viewer à allUsers.

ee089815364150d2.png

Une fois que vous avez choisi votre image, modifiez simplement le paramètre --file-path dans cette commande:

mvn compile exec:java -Dexec.mainClass=keyviz.ReadData \
"-Dexec.args=--bigtableProjectId=$BIGTABLE_PROJECT \
--bigtableInstanceId=$INSTANCE_ID --runner=dataflow \
--bigtableTableId=$TABLE_ID --project=$GOOGLE_CLOUD_PROJECT \
--filePath=gs://keyviz-art/american_gothic_4h.txt"

7. Vérifiez plus tard

L'image complète peut mettre quelques heures à prendre vie, mais après 30 minutes, vous devriez commencer à voir une activité dans le Key Visualizer. Vous pouvez jouer avec plusieurs paramètres: zoom, luminosité et métrique. Vous pouvez zoomer, en utilisant la molette de votre souris ou en faisant glisser un rectangle sur la grille Key Visualizer.

La luminosité modifie la mise à l'échelle de l'image, ce qui est utile si vous souhaitez examiner en détail une zone très chaude.

8e847f03df25572b.png

Vous pouvez également ajuster la métrique à afficher. Il y a OPs, Read bytes client, Writes bytes client pour n'en nommer que quelques-uns. "Read bytes client" (Lire les octets du client) semble produire des images fluides, tandis que produit des images avec plus de lignes, ce qui peut être vraiment sympa sur certaines images.

33eb5dcf4e4be861.png

8. Finaliser

Effectuer un nettoyage pour éviter que des frais ne vous soient facturés

Pour éviter que les ressources utilisées dans cet atelier de programmation soient facturées sur votre compte Google Cloud Platform, vous devez supprimer votre instance.

gcloud bigtable instances delete $INSTANCE_ID

Points abordés

  • Écrire dans Bigtable avec Dataflow
  • Lire des données à partir de Bigtable avec Dataflow (au début du pipeline, au milieu du pipeline)
  • Utiliser les outils de surveillance Dataflow
  • Utiliser les outils de surveillance Bigtable, y compris Key Visualizer

Étapes suivantes