Usa Cloud Bigtable con Cloud Functions

Objetivos

Escribe, implementa y activa una función de HTTP de Cloud Functions que acceda a Cloud Bigtable.

Costos

En este tema, se usan Cloud Bigtable y Cloud Functions, que son componentes facturables de Google Cloud.

Antes de comenzar

  1. En este tema, se supone que tienes una instancia de Cloud Bigtable llamada test-instance y una tabla llamada test-table. Puedes crear estos recursos si sigues los pasos en Crea una tabla de prueba. Asegúrate de borrar los recursos cuando termines para evitar incurrir en costos innecesarios.

  2. Habilita la API de Cloud Functions.

    Habilita la API

  3. Instala y, luego, inicializa el SDK de Cloud.

  4. Actualiza los componentes de gcloud:

    gcloud components update
    
  5. Prepara tu entorno de desarrollo:

Prepara la aplicación

  1. Clona el repositorio de la app de muestra en tu máquina local:

    Node.js

    git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git

    De manera opcional, puedes descargar la muestra como un archivo ZIP y extraerla.

    Python

    git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git

    De manera opcional, puedes descargar la muestra como un archivo ZIP y extraerla.

    Go

    git clone https://github.com/GoogleCloudPlatform/golang-samples.git

    De manera opcional, puedes descargar la muestra como un archivo ZIP y extraerla.

  2. Cambia al directorio que contiene el código de muestra de Cloud Functions para acceder a Cloud Bigtable:

    Node.js

    cd nodejs-docs-samples/functions/bigtable/

    Python

    cd python-docs-samples/functions/bigtable/

    Go

    cd golang-samples/functions/bigtable/
  3. Observa el código de muestra:

    Node.js

    // Imports the Google Cloud client library
    const {Bigtable} = require('@google-cloud/bigtable');
    
    // Instantiates a client
    const bigtable = new Bigtable();
    
    exports.readRows = async (req, res) => {
      // Gets a reference to a Cloud Bigtable instance and database
      const instance = bigtable.instance(req.body.instanceId);
      const table = instance.table(req.body.tableId);
    
      // Execute the query
      try {
        const prefix = 'phone#';
        const rows = [];
        await table
          .createReadStream({
            prefix,
          })
          .on('error', err => {
            res.send(`Error querying Bigtable: ${err}`);
            res.status(500).end();
          })
          .on('data', row => {
            rows.push(
              `rowkey: ${row.id}, ` +
                `os_build: ${row.data['stats_summary']['os_build'][0].value}\n`
            );
          })
          .on('end', () => {
            rows.forEach(r => res.write(r));
            res.status(200).end();
          });
      } catch (err) {
        res.send(`Error querying Bigtable: ${err}`);
        res.status(500).end();
      }
    };
    

    Python

    from google.cloud import bigtable
    from google.cloud.bigtable.row_set import RowSet
    
    client = bigtable.Client()
    
    def bigtable_read_data(request):
        instance = client.instance(request.headers.get("instance_id"))
        table = instance.table(request.headers.get("table_id"))
    
        prefix = 'phone#'
        end_key = prefix[:-1] + chr(ord(prefix[-1]) + 1)
    
        outputs = []
        row_set = RowSet()
        row_set.add_row_range_from_keys(prefix.encode("utf-8"),
                                        end_key.encode("utf-8"))
    
        rows = table.read_rows(row_set=row_set)
        for row in rows:
            output = 'Rowkey: {}, os_build: {}'.format(
                row.row_key.decode('utf-8'),
                row.cells["stats_summary"]["os_build".encode('utf-8')][0]
                .value.decode('utf-8'))
            outputs.append(output)
    
        return '\n'.join(outputs)
    

    Go

    
    // Package bigtable contains an example of using Bigtable from a Cloud Function.
    package bigtable
    
    import (
    	"context"
    	"fmt"
    	"log"
    	"net/http"
    	"sync"
    
    	"cloud.google.com/go/bigtable"
    )
    
    // client is a global Bigtable client, to avoid initializing a new client for
    // every request.
    var client *bigtable.Client
    var clientOnce sync.Once
    
    // BigtableRead is an example of reading Bigtable from a Cloud Function.
    func BigtableRead(w http.ResponseWriter, r *http.Request) {
    	clientOnce.Do(func() {
    		// Declare a separate err variable to avoid shadowing client.
    		var err error
    		client, err = bigtable.NewClient(context.Background(), r.Header.Get("projectID"), r.Header.Get("instanceId"))
    		if err != nil {
    			http.Error(w, "Error initializing client", http.StatusInternalServerError)
    			log.Printf("bigtable.NewClient: %v", err)
    			return
    		}
    	})
    
    	tbl := client.Open(r.Header.Get("tableID"))
    	err := tbl.ReadRows(r.Context(), bigtable.PrefixRange("phone#"),
    		func(row bigtable.Row) bool {
    			osBuild := ""
    			for _, col := range row["stats_summary"] {
    				if col.Column == "stats_summary:os_build" {
    					osBuild = string(col.Value)
    				}
    			}
    
    			fmt.Fprintf(w, "Rowkey: %s, os_build:  %s\n", row.Key(), osBuild)
    			return true
    		})
    
    	if err != nil {
    		http.Error(w, "Error reading rows", http.StatusInternalServerError)
    		log.Printf("tbl.ReadRows(): %v", err)
    	}
    }
    

    La función envía una solicitud de lectura a la tabla para recuperar todos los datos de stats_summary de las filas con un prefijo de clave de fila de phone. La función se ejecuta cuando haces una solicitud HTTP al extremo de la función.

Implementa la función

Ejecuta el siguiente comando en el directorio bigtable para implementar la función con un activador HTTP:

Node.js

gcloud functions deploy get \
--runtime nodejs10 --trigger-http
Puedes usar los siguientes valores para que la marca --runtime especifique tu versión preferida de Node.js:
  • nodejs10
  • nodejs12

Python

gcloud functions deploy bigtable_read_data \
--runtime python37 --trigger-http
Puedes usar los siguientes valores para que la marca --runtime especifique tu versión preferida de Python:
  • python37
  • python38

Go

gcloud functions deploy HelloBigtable \
--runtime go111 --trigger-http
Puedes usar los siguientes valores en la marca --runtime para especificar tu versión preferida de Go:
  • go111
  • go113

La implementación de la función puede tomar hasta dos minutos.

Cuando la función termina de implementarse, se muestra el valor url. Usarás ese valor cuando actives la función.

Puedes ver las funciones implementadas en la página de Cloud Functions en Google Cloud Console. También puedes crear y editar funciones en esa página, en la que además puedes obtener detalles y diagnósticos de tus funciones.

Activa la función

Haz una solicitud HTTP a tu función:

Node.js

curl "https://REGION-PROJECT_ID.cloudfunctions.net/get" --trigger-http

Python

curl "https://REGION-PROJECT_ID.cloudfunctions.net/bigtable_read_data" --trigger-http

Go

curl "https://REGION-PROJECT_ID.cloudfunctions.net/HelloBigtable" --trigger-http

En el ejemplo anterior, REGION y PROJECT_ID coinciden con los valores que son visibles en la terminal cuando la función se termina de implementar. Deberías ver un resultado que muestre los resultados de la solicitud de lectura.

También puedes visitar la URL de la función en tu navegador para ver los resultados de la solicitud de lectura.

Realiza una limpieza

Para evitar que se apliquen cargos adicionales a la cuenta de Google Cloud por los recursos de Cloud Bigtable y Cloud Functions usados en este tema, sigue estos pasos:

  1. Borra la instancia:

    gcloud bigtable instances delete test-instance
    
  2. Borra la función que implementaste:

    Node.js

    gcloud functions delete get --trigger-http

    Python

    gcloud functions delete bigtable_read_data --trigger-http

    Go

    gcloud functions delete HelloBigtable --trigger-http

Próximos pasos