Ottimizzazione del networking

La semplicità di Cloud Functions consente di sviluppare rapidamente il codice ed eseguirlo in un completamente serverless. Su scala moderata, il costo di esecuzione delle funzioni è basso, e l'ottimizzazione del codice potrebbe non sembrare una priorità elevata. Quando il deployment fa lo scale up, ma l'ottimizzazione del codice diventa sempre più importante.

Questo documento descrive come ottimizzare la rete per le funzioni. Alcuni di i vantaggi dell'ottimizzazione del networking sono i seguenti:

  • Riduci il tempo della CPU impiegato per stabilire nuove connessioni in uscita a ogni chiamata di funzione.
  • Riduci le probabilità di esaurire la connessione o il DNS quote di spazio di archiviazione.

Mantenimento di connessioni permanenti

Questa sezione fornisce esempi di come mantenere le connessioni permanenti in un personalizzata. In caso contrario, le quote di connessione potrebbero esaurirsi rapidamente.

In questa sezione vengono trattati i seguenti scenari:

  • HTTP/S
  • API di Google

Richieste HTTP/S

Lo snippet di codice ottimizzato di seguito mostra come gestire le connessioni permanenti anziché creare una nuova connessione a ogni chiamata di funzione:

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

Questa funzione HTTP utilizza un pool di connessioni per effettuare richieste HTTP. Prende un oggetto di richiesta (flask.Request) e restituisce il testo della risposta o qualsiasi insieme di valori che possono essere trasformati in Response oggetto utilizzando make_response

Accesso alle API di Google

L'esempio riportato di seguito utilizza Cloud Pub/Sub, ma questo approccio funziona anche per altre librerie client, ad esempio Cloud Natural Language oppure Cloud Spanner. Tieni presente che il rendimento miglioramenti possono dipendere dall'implementazione corrente di un particolare client librerie.

La creazione di un oggetto client Pub/Sub genera una connessione e due query DNS per chiamata. Per evitare connessioni e query DNS non necessarie, crea il metodo Oggetto client Pub/Sub in ambito globale, come mostrato nell'esempio riportato di seguito:

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

Questa funzione HTTP utilizza un'istanza della libreria client memorizzata nella cache per ridurre il numero di connessioni necessarie per ogni chiamata di funzione. Prende un oggetto request (flask.Request) e restituisce il testo della risposta o qualsiasi insieme di valori che può essere trasformato in un oggetto Response utilizzando make_response.

La variabile di ambiente GCP_PROJECT viene impostata automaticamente nel file Python 3.7. Nei runtime successivi, assicurati di specificare il deployment delle funzioni. Consulta Configurare le variabili di ambiente.

Reimpostazione della connessione in uscita

Gli stream di connessione dalla funzione sia al VPC sia a internet possono essere occasionalmente interrotti e sostituiti quando l'infrastruttura sottostante viene riavviata o aggiornata. Se la tua applicazione riutilizza connessioni di lunga durata, ti consigliamo di configurare l'applicazione per ristabilire le connessioni evitare il riutilizzo di una connessione inattiva.

Test di carico della funzione

Per misurare il numero di connessioni eseguite in media dalla funzione, è sufficiente eseguire il deployment come funzione HTTP e usare un framework di test delle prestazioni per richiamarla alcune QPS. Puoi scegliere Artillery, che può richiamare con una sola riga:

$ artillery quick -d 300 -r 30 URL

Questo comando recupera l'URL specificato a 30 QPS per 300 secondi.

Dopo aver eseguito il test, controlla l'utilizzo della quota di connessione sulla Pagina della quota API Cloud Functions nella console Cloud. Se l'utilizzo è costantemente intorno ai 30 (o i suoi multipli), stabilisce una (o più) connessioni in ogni chiamata. Dopo ottimizzare il codice, dovresti notare alcune (10-30) connessioni solo all'inizio del test.

Puoi anche confrontare il costo della CPU prima e dopo l'ottimizzazione grafico della quota di spazio di archiviazione sulla stessa pagina.