Fonctions distantes Spanner

Une fonction distante Spanner vous permet d'implémenter votre fonction dans des langages autres que SQL. Les fonctions doivent être hébergées dans Cloud Run Functions ou Cloud Run. L'hébergement de fonctions de cette manière permet de répartir la logique métier complexe dans des fonctions à distance distinctes.

Un déploiement de fonction à distance type comprend les étapes suivantes :

  1. Créez un point de terminaison HTTPS dans Cloud Run Functions ou Cloud Run.

    • Si vous ne connaissez pas les fonctions à distance, nous vous recommandons d'utiliser Cloud Run Functions.
  2. Créez une fonction distante dans Spanner pointant vers ce point de terminaison HTTPS.

  3. Utilisez la fonction distante dans une requête.

Rôles requis

Pour vous assurer que votre compte de service de l'agent Spanner (service-PROJECT_ID@gcp-sa-spanner.iam.gserviceaccount.com) dispose des autorisations nécessaires pour utiliser les fonctions à distance Spanner, demandez à votre administrateur d'accorder à votre compte de service de l'agent Spanner (service-PROJECT_ID@gcp-sa-spanner.iam.gserviceaccount.com) le rôle IAM Agent de service de l'API Spanner (roles/spanner.serviceAgent) sur le projet.

Pour en savoir plus sur l'attribution de rôles, consultez Gérer l'accès aux projets, aux dossiers et aux organisations.

Votre administrateur peut également être en mesure d'accorder à votre compte de service de l'agent Spanner (service-PROJECT_ID@gcp-sa-spanner.iam.gserviceaccount.com) les autorisations requises avec des rôles personnalisés ou d'autres rôles prédéfinis.

Types compatibles

Les fonctions distantes sont compatibles avec les types de données suivants en tant que types d'arguments ou types renvoyés :

  • ARRAY (de l'un des types compatibles suivants)
  • BOOLEAN
  • BYTES
  • DATE
  • JSON
  • INTEGER
  • NUMERIC
  • STRING
  • TIMESTAMP

Limites

  • Vous ne pouvez pas créer de fonctions distantes basées sur des valeurs de table.

  • Les fonctions à distance ne sont pas acceptées dans les expressions de colonnes générées.

  • Des requêtes répétées avec les mêmes données vers votre point de terminaison peuvent s'afficher, parfois même après des réponses réussies, en raison d'erreurs réseau temporaires ou de redémarrages internes de Spanner.

  • L'exécution de fonctions à distance dans des instances Spanner fractionnaires n'est pas prise en charge.

  • Les fonctions à distance ne sont pas compatibles avec les Cloud Run Functions derrière des domaines personnalisés.

  • Les fonctions à distance ne sont pas compatibles avec le dialecte PostgreSQL.

Créer un point de terminaison

La logique métier doit être implémentée en tant que fonction Cloud Run ou Cloud Run. Le point de terminaison doit pouvoir traiter un lot de lignes dans une seule requête HTTPS POST et renvoyer le résultat du lot sous forme de réponse HTTPS.

Si vous avez créé des fonctions distantes pour BigQuery, vous pouvez les réutiliser pour Spanner.

Consultez le tutoriel Cloud Run Functions et la documentation Cloud Run Functions pour découvrir comment écrire, déployer, tester et gérer une fonction Cloud Run.

Consultez le guide de démarrage rapide de Cloud Run et les autres documents sur Cloud Run pour savoir comment écrire, déployer, tester et gérer un service Cloud Run.

Nous vous recommandons de conserver l'authentification par défaut pour votre fonction Cloud Run ou votre service Cloud Run. Évitez de configurer le service pour autoriser les appels non authentifiés.

Format d'entrée

Spanner envoie des requêtes HTTPS POST avec des corps JSON au format suivant :

Nom du champ Description Type de champ
requestId Identifiant de la demande. Unique sur plusieurs requêtes envoyées au point de terminaison dans une requête GoogleSQL. Toujours fourni. Chaîne.
calls Un lot de données d'entrée. Toujours fourni. Un tableau JSON.

Chaque élément est un tableau JSON qui représente une liste d'arguments encodés au format JSON pour un seul appel de fonction distante.

Exemple de requête :

// 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]
 ]
}

Format de sortie

Spanner s'attend à ce que le point de terminaison renvoie une réponse HTTPS au format suivant. Sinon, Spanner ne pourra pas la consommer et la requête appelant la fonction distante échouera.

Nom du champ Description Plage de valeurs
replies Un lot de valeurs de retour. Tableau JSON.

Chaque élément correspond à une valeur de retour de la fonction externe au format JSON.

La taille du tableau doit correspondre à celle du tableau JSON de calls dans la requête HTTPS. Par exemple, si le tableau JSON dans calls contient quatre éléments, ce tableau JSON doit également contenir quatre éléments. Obligatoire pour une réponse positive.
errorMessage Message d'erreur lorsqu'un code de réponse HTTPS autre que 200 est renvoyé. Pour les erreurs ne permettant aucune autre tentative, Spanner renvoie ce message d'erreur à l'utilisateur. Obligatoire en cas d'échec de la réponse. Généralement moins de 1 Ko. Chaîne.

Voici un exemple de réponse positive :

// 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
  ]
}

Exemple de réponse ayant échoué :

{
  // 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."
}

Code de réponse HTTPS

Votre point de terminaison renvoie un code HTTPS 200 pour une réponse positive. Lorsque Spanner reçoit une autre valeur, il considère la réponse comme un échec et effectue une nouvelle tentative lorsque le code de réponse HTTPS est 408, 429, 500, 503 ou 504 jusqu'à ce qu'une limite interne soit atteinte.

Exemple de code

Fonction Cloud Run

L'exemple de code Python suivant met en œuvre l'ajout de tous les arguments entiers de la fonction distante. Il traite une requête avec les arguments des appels par lot et renvoie tous les résultats dans une réponse.

"""
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

Si la fonction est déployée dans le projet PROJECT_ID dans la région us-east1 avec le nom de fonction remote_add, elle est accessible à l'aide du point de terminaison https://us-east1-PROJECT_ID.cloudfunctions.net/remote_add.

Cloud Run

L'exemple de code Python suivant implémente un service Web, qui peut être créé et déployé sur Cloud Run pour la même fonctionnalité.

"""
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)))

Pour créer et déployer le code, consultez Guide de démarrage rapide : Créer et déployer une application Web Python (Flask) sur Cloud Run.

Si le service Cloud Run est déployé dans le projet PROJECT_ID dans la région us-east1 comme nom de service remote_add, il est accessible à l'aide du point de terminaison https://remote_add-<project_id_hash>-ue.a.run.app.

Créer une fonction distante

Pour créer une fonction distante, procédez comme suit :

SQL

Exécutez l'instruction CREATE FUNCTION suivante dans 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
);

Remplacez les éléments suivants :

  • REMOTE_FUNCTION_NAME : nom de votre fonction distante. Exemple : sum_func.
  • ENDPOINT_URL : point de terminaison Cloud Run Functions ou Cloud Run créé à l'étape précédente.
  • MAX_BATCHING_ROWS (facultatif) : nombre maximal de lignes à envoyer dans une requête. Si elle n'est pas spécifiée, Spanner détermine automatiquement la taille du lot.

Utiliser une fonction distante dans une requête

Pour appeler la fonction distante de l'étape précédente dans une requête, utilisez l'exemple suivant :

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

Tarifs

  • La tarification standard de Spanner s'applique.

  • Spanner facture les octets envoyés à Cloud Run Functions ou Cloud Run, et ceux reçus de ces services.

  • Cette fonctionnalité peut entraîner des coûts liés à Cloud Run Functions et Cloud Run. Pour en savoir plus, consultez les pages sur les tarifs de Cloud Run Functions et Cloud Run.