La simplicité de Cloud Functions vous permet de développer rapidement du code et de l'exécuter dans un sans serveur. À une échelle modérée, le coût d'exécution des fonctions est faible et l'optimisation de votre code ne semble pas être la priorité. Au fur et à mesure que votre déploiement évolue, l'optimisation de votre code gagne en importance.
Ce document décrit comment optimiser la mise en réseau de vos fonctions. L'optimisation de la mise en réseau présente des avantages, dont en voici une sélection :
- Elle diminue le temps CPU passé à établir de nouvelles connexions sortantes à chaque appel de fonction
- Elle réduit le risque de manquer de quotas DNS ou de connexion.
Maintenir des connexions persistantes
Cette section donne des exemples de maintien de connexions persistantes dans une fonction. À défaut, vous risquez d’épuiser rapidement les quotas de connexion.
Cette section porte sur les situations suivantes :
- HTTP/S
- API Google
Demandes HTTP/S
L'extrait de code optimisé ci-dessous montre comment maintenir des connexions persistantes plutôt que de créer une connexion à chaque appel de fonction :
Node.js
const http = require('http'); const functions = require('firebase-functions'); // Setting the `keepAlive` option to `true` keeps // connections open between function invocations const agent = new http.Agent({keepAlive: true}); exports.function = functions.https.onRequest((request, response) => { req = http.request({ host: '' , port: 80, path: '' , method: 'GET', agent: agent, // Holds the connection open after the first invocation }, res => { let rawData = ''; res.setEncoding('utf8'); res.on('data', chunk => { rawData += chunk; }); res.on('end', () => { response.status(200).send(`Data: ${rawData}`); }); }); req.on('error', e => { response.status(500).send(`Error: ${e.message}`); }); req.end(); });
Python
from firebase_functions import https_fn import requests # Create a global HTTP session (which provides connection pooling) session = requests.Session() @https_fn.on_request() def connection_pooling(request): # The URL to send the request to url = "http://example.com" # Process the request response = session.get(url) response.raise_for_status() return https_fn.Response("Success!")
Cette fonction HTTP utilise un pool de connexions pour effectuer des requêtes HTTP.
Elle prend un objet de requête (flask.Request
) et renvoie
le texte de la réponse ou tout ensemble de valeurs pouvant être transformés en
Objet Response
utilisant
make_response
Accéder aux API Google
L'exemple ci-dessous utilise Cloud Pub/Sub, mais cette approche fonctionne également pour d'autres bibliothèques clientes, par exemple, Cloud Natural Language ou Cloud Spanner. Notez que les améliorations de performances peuvent dépendre de la mise en œuvre actuelle de certaines bibliothèques clientes spécifiques.
La création d'un objet client PubSub donne lieu à une connexion et deux requêtes DNS par appel. Pour éviter les connexions et les requêtes DNS inutiles, créez l'objet client PubSub dans un champ d'application global, comme indiqué dans l'échantillon ci-dessous :
Node.js
const PubSub = require('@google-cloud/pubsub'); const functions = require('firebase-functions'); const pubsub = PubSub(); exports.function = functions.https.onRequest((req, res) => { const topic = pubsub.topic('' ); topic.publish('Test message', err => { if (err) { res.status(500).send(`Error publishing the message: ${err}`); } else { res.status(200).send('1 message published'); } }); });
Python
import os from firebase_functions import https_fn from google.cloud import pubsub_v1 # from firebase_functions import https_fn # Create a global Pub/Sub client to avoid unneeded network activity pubsub = pubsub_v1.PublisherClient() @https_fn.on_request() def gcp_api_call(request): project = os.getenv("GCP_PROJECT") request_json = request.get_json() topic_name = request_json["topic"] topic_path = pubsub.topic_path(project, topic_name) # Process the request data = b"Test message" pubsub.publish(topic_path, data=data) return https_fn.Response("1 message published")
Cette fonction HTTP utilise une instance de bibliothèque cliente mise en cache pour
de réduire le nombre de connexions
requises par appel de fonction.
Elle prend un objet de requête (flask.Request
) et renvoie
le texte de la réponse ou tout ensemble de valeurs pouvant être transformés en
Objet Response
utilisant
make_response
La variable d'environnement GCP_PROJECT
est définie automatiquement dans le fichier
3.7. Dans les environnements d'exécution ultérieurs, veillez à le spécifier sur
le déploiement de la fonction. Voir
Configurez les variables d'environnement.
Réinitialisation des connexions sortantes
Les flux de connexion de votre fonction vers un VPC et Internet peuvent parfois être arrêtés et remplacés lorsque l'infrastructure sous-jacente est redémarrée ou mise à jour. Si votre application réutilise des connexions à longue durée de vie, nous vous recommandons de configurer votre application de manière à rétablir les connexions afin d'éviter la réutilisation d'une connexion interrompue.
Test de charge de votre fonction
Pour évaluer le nombre moyen de connexions exécutées par votre fonction, déployez-la simplement en tant que fonction HTTP et utilisez un framework de test de performance pour l'appeler à un certain nombre de requêtes par seconde. Vous pouvez, par exemple, utiliser Artillery, que vous pouvez appeler avec une seule ligne :
$ artillery quick -d 300 -r 30 URL
Cette commande extrait l'URL indiquée à 30 requêtes par seconde pendant 300 secondes.
Après avoir effectué le test, vérifiez l'utilisation de votre quota de connexion sur le Page des quotas d'API Cloud Functions dans la console Cloud. Si la consommation tourne toujours autour de 30 (ou de son multiple), vous établissez une (ou plusieurs) connexion à chaque appel. Après avoir optimisé votre code, vous devriez voir quelques (10-30) connexions apparaître uniquement au début du test.
Vous pouvez également comparer le coût de processeur avant et après l'optimisation sur le tracé du quota de processeur figurant sur la même page.