Funzioni remote di Spanner

Una funzione remota Spanner ti consente di implementare la funzione in linguaggi diversi da SQL. Le funzioni devono essere ospitate in Cloud Run Functions o Cloud Run. L'hosting delle funzioni in questo modo consente di suddividere la logica di business complessa in funzioni remote separate.

Un deployment tipico di una funzione remota prevede i seguenti passaggi:

  1. Crea un endpoint HTTPS in Cloud Run Functions o Cloud Run.

    • Se non hai mai utilizzato le funzioni remote, ti consigliamo di utilizzare Cloud Run Functions.
  2. Crea una funzione remota in Spanner che rimandi all'endpoint HTTPS.

  3. Utilizza la funzione remota in una query.

Ruoli obbligatori

Per assicurarti che il account di servizio dell'agente Spanner (service-PROJECT_ID@gcp-sa-spanner.iam.gserviceaccount.com) disponga delle autorizzazioni necessarie per utilizzare le funzioni remote Spanner, chiedi all'amministratore di concedere il ruolo IAM Agente di servizio API Spanner (roles/spanner.serviceAgent) al account di servizio dell'agente Spanner (service-PROJECT_ID@gcp-sa-spanner.iam.gserviceaccount.com) sul progetto.

Per ulteriori informazioni sulla concessione dei ruoli, consulta Gestire l'accesso a progetti, cartelle e organizzazioni.

L'amministratore potrebbe anche essere in grado di concedere al account di servizio dell'agente Spanner (service-PROJECT_ID@gcp-sa-spanner.iam.gserviceaccount.com) le autorizzazioni richieste tramite i ruoli personalizzati o altri ruoli predefiniti .

Tipi supportati

Le funzioni remote supportano i seguenti tipi di dati come tipi di argomento o di restituzione:

  • ARRAY (di uno dei seguenti tipi supportati)
  • BOOLEAN
  • BYTES
  • DATE
  • JSON
  • INTEGER
  • NUMERIC
  • STRING
  • TIMESTAMP

Limitazioni

  • Non puoi creare funzioni remote con valori di tabella.

  • Le funzioni remote non sono supportate nelle espressioni delle colonne generate.

  • Potresti visualizzare richieste ripetute con gli stessi dati al tuo endpoint, a volte anche dopo risposte riuscite, a causa di errori di rete temporanei o riavvii interni di Spanner.

  • L'esecuzione di funzioni remote in istanze Spanner frazionarie non è supportata.

  • Le funzioni remote non sono supportate per Cloud Run Functions dietro domini personalizzati.

  • Le funzioni remote non sono supportate nel dialetto PostgreSQL.

Creazione di un endpoint

La logica di business deve essere implementata come funzione Cloud Run o Cloud Run. L'endpoint deve essere in grado di elaborare un batch di righe in una singola richiesta POST HTTPS e restituire il risultato per il batch come risposta HTTPS.

Se hai creato funzioni remote per BigQuery, puoi riutilizzarle per Spanner.

Consulta il tutorial di Cloud Run Functions e altra documentazione di Cloud Run Functions su come scrivere, eseguire il deployment, testare e gestire una funzione Cloud Run.

Consulta la guida rapida di Cloud Run e altra documentazione di Cloud Run su come scrivere, eseguire il deployment, testare e gestire un servizio Cloud Run.

Ti consigliamo di mantenere l'autenticazione predefinita per la funzione Cloud Run o il servizio Cloud Run. Evita di configurare il servizio in modo da consentire la chiamata non autenticata.

Formato di input

Spanner invia richieste POST HTTPS con corpi JSON nel seguente formato:

Nome campo Descrizione Tipo di campo
requestId Identificatore della richiesta. Valore univoco per più richieste inviate all'endpoint in una query GoogleSQL. Fornito sempre. Stringa.
calls Un batch di dati di input. Fornito sempre. Un array JSON.

Ogni elemento è un array JSON che rappresenta un elenco di argomenti codificati in JSON per una singola chiamata di funzione remota.

Un esempio di richiesta:

// Sample request to a Cloud Run functions to calculate sum of two numbers. This request
// has two calls batched together into a single request.
{
 "requestId": "124ab1c",
 "calls": [
  [1, 2],
  [3, 4]
 ]
}

Formato di output

Spanner si aspetta che l'endpoint restituisca una risposta HTTPS nel seguente formato; in caso contrario, Spanner non può utilizzare la risposta e la query non riesce a chiamare la funzione remota.

Nome campo Descrizione Intervallo di valori
replies Un batch di valori restituiti. Array JSON.

Ogni elemento corrisponde a un valore restituito codificato in JSON della funzione esterna.

La dimensione dell'array deve corrispondere alla dimensione dell'array JSON di calls nella richiesta HTTPS. Ad esempio, se l'array JSON in calls ha 4 elementi, anche questo array JSON deve avere 4 elementi. Obbligatorio per una risposta riuscita.
errorMessage Messaggio di errore quando viene restituito il codice di risposta HTTPS diverso da 200. Per gli errori non riprovabili, Spanner restituisce questo messaggio di errore all'utente. Obbligatorio nelle risposte non riuscite. In genere meno di 1 KB. Stringa.

Un esempio di risposta riuscita:

// Sample response from the Cloud Run functions which has the sum of the two numbers. Note
// that the order of the values within `replies` field matches the `calls` field from
// the request.
{
  "replies": [
    3,  // 1 + 2 = 3
    7   // 3 + 4 = 7
  ]
}

Un esempio di risposta non riuscita:

{
  // The error message returned by your Cloud Run functions to indicate an error.
  // In this sample, the error message states that an overflow occurred when summing two numbers.
  "errorMessage": "Overflow detected when calculating sum of two numbers."
}

Codice di risposta HTTPS

L'endpoint restituisce un codice HTTPS 200 per una risposta riuscita. Quando Spanner riceve qualsiasi altro valore, considera la risposta non riuscita e riprova quando il codice di risposta HTTPS è 408, 429, 500, 503 o 504 fino a quando non viene raggiunto un limite interno.

Codice di esempio

Funzione Cloud Run

Il seguente codice Python di esempio implementa l'aggiunta di tutti gli argomenti interi della funzione remota. Gestisce una richiesta con gli argomenti per le chiamate in batch e restituisce tutti i risultati in una risposta.

"""
Python script which uses Flask framework to spin up a HTTP server to take
integers and return their sum. In case of overflow, it returns the error
as part of the response.
"""
import functions_framework

from flask import jsonify

# Max INT64 value encoded as a number in JSON by TO_JSON_STRING. Larger values are encoded as
# strings.
_MAX_LOSSLESS=9007199254740992

@functions_framework.http
def batch_add(request):
  try:
    return_value = []
    request_json = request.get_json()
    calls = request_json['calls']
    for call in calls:
      return_value.append(sum([int(x) if isinstance(x, str) else x for x in call if x is not None]))
    replies = [str(x) if x > _MAX_LOSSLESS or x < -_MAX_LOSSLESS else x for x in return_value]
    return_json = jsonify( { "replies":  replies } )
    return return_json
  except Exception as e:
    return jsonify( { "errorMessage": str(e) } ), 400

Supponendo che la funzione sia sottoposta a deployment nel progetto PROJECT_ID nella regione us-east1 con il nome della funzione remote_add, è possibile accedervi utilizzando l'endpoint https://us-east1-PROJECT_ID.cloudfunctions.net/remote_add.

Cloud Run

Il seguente codice Python di esempio implementa un servizio web, che può essere creato ed eseguito il deployment in Cloud Run per la stessa funzionalità.

"""
Python script which uses Flask framework to spin up a HTTP server to take
integers and return their sum. In case of overflow, it returns the error
as part of the response.
"""
import os

from flask import Flask, request, jsonify

# Max INT64 value encoded as a number in JSON by TO_JSON_STRING. Larger values are encoded as
# strings.
_MAX_LOSSLESS=9007199254740992

app = Flask(__name__)

@app.route("/", methods=['POST'])
def batch_add():
  try:
    return_value = []
    request_json = request.get_json()
    calls = request_json['calls']
    for call in calls:
      return_value.append(sum([int(x) if isinstance(x, str) else x for x in call if x is not None]))
    replies = [str(x) if x > _MAX_LOSSLESS or x < -_MAX_LOSSLESS else x for x in return_value]
    return jsonify( { "replies" :  replies } )
  except Exception as e:
    return jsonify( { "errorMessage": str(e) } ), 400

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))

Per creare ed eseguire il deployment del codice, consulta la guida rapida: creare ed eseguire il deployment di un'app web Python (Flask) in Cloud Run.

Supponendo che il servizio Cloud Run sia sottoposto a deployment nel progetto PROJECT_ID nella regione us-east1 con il nome del servizio remote_add, è possibile accedervi utilizzando l'endpoint https://remote_add-<project_id_hash>-ue.a.run.app.

Creazione di una funzione remota

Per creare una funzione remota:

SQL

Esegui la seguente istruzione CREATE FUNCTION in Spanner:

CREATE FUNCTION REMOTE_FUNCTION_NAME(x INT64, y INT64) RETURNS INT64 NOT DETERMINISTIC LANGUAGE REMOTE OPTIONS (
  endpoint = `ENDPOINT_URL`,
  max_batching_rows = MAX_BATCHING_ROWS
);

Sostituisci quanto segue:

  • REMOTE_FUNCTION_NAME: il nome della funzione remota. Ad esempio, sum_func.
  • ENDPOINT_URL: l'endpoint Cloud Run Functions o Cloud Run creato nel passaggio precedente.
  • MAX_BATCHING_ROWS (facoltativo): il numero massimo di righe da inviare come parte di una richiesta. Se non specificato, Spanner determina automaticamente la dimensione del batch.

Utilizzo della funzione remota in una query

Per chiamare la funzione remota del passaggio precedente all'interno di una query, utilizza il seguente esempio:

SELECT REMOTE_FUNCTION_NAME(1, 2); -- 1 + 2 = 3

Prezzi

  • Si applicano i prezzi standard di Spanner pricing.

  • Spanner fattura i byte inviati e ricevuti da Cloud Run Functions o Cloud Run.

  • Questa funzionalità potrebbe comportare costi da Cloud Run Functions e Cloud Run. Per i dettagli, consulta le pagine dei prezzi di Cloud Run Functions e Cloud Run.