Optimizar la red (1.ª gen.)
La sencillez de las funciones de Cloud Run te permite desarrollar código rápidamente y ejecutarlo en un entorno sin servidor. A una escala moderada, el coste de ejecutar funciones es bajo, por lo que optimizar el código puede no parecer una prioridad alta. Sin embargo, a medida que tu implementación se amplía, optimizar el código se vuelve cada vez más importante.
En este documento se describe cómo optimizar las redes de tus funciones. Estas son algunas de las ventajas de optimizar la red:
- Reduce el tiempo de CPU dedicado a establecer nuevas conexiones en cada llamada de función.
- Reduce la probabilidad de agotar las cuotas de conexión o DNS.
Mantener conexiones persistentes
En esta sección se ofrecen ejemplos de cómo mantener conexiones persistentes en una función. Si no lo haces, es posible que agotes rápidamente las cuotas de conexión.
En esta sección se tratan los siguientes casos:
- HTTP/S
- APIs de Google
Solicitudes HTTP/S
El siguiente fragmento de código optimizado muestra cómo mantener conexiones persistentes en lugar de crear una conexión nueva cada vez que se invoca una función:
Node.js
Python
Go
PHP
Te recomendamos que utilices el framework HTTP de PHP Guzzle para enviar solicitudes HTTP, ya que gestiona las conexiones persistentes automáticamente.
Acceder a las API de Google
En el siguiente ejemplo se usa Cloud Pub/Sub, pero este enfoque también funciona con otras bibliotecas de cliente, como Cloud Natural Language o Cloud Spanner. Ten en cuenta que las mejoras en el rendimiento pueden depender de la implementación actual de bibliotecas de cliente concretas.
Al crear un objeto de cliente de Pub/Sub, se genera una conexión y dos consultas DNS por invocación. Para evitar conexiones y consultas de DNS innecesarias, crea el objeto de cliente de Pub/Sub en el ámbito global, tal como se muestra en el siguiente ejemplo:
Node.js
Python
Go
// Package contexttip is an example of how to use Pub/Sub and context.Context in // a Cloud Function. package contexttip import ( "context" "encoding/json" "fmt" "log" "net/http" "os" "sync" "cloud.google.com/go/pubsub" "github.com/GoogleCloudPlatform/functions-framework-go/functions" ) // client is a global Pub/Sub client, initialized once per instance. var client *pubsub.Client var once sync.Once // createClient creates the global pubsub Client func createClient() { // GOOGLE_CLOUD_PROJECT is a user-set environment variable. var projectID = os.Getenv("GOOGLE_CLOUD_PROJECT") // err is pre-declared to avoid shadowing client. var err error // client is initialized with context.Background() because it should // persist between function invocations. client, err = pubsub.NewClient(context.Background(), projectID) if err != nil { log.Fatalf("pubsub.NewClient: %v", err) } } func init() { // register http function functions.HTTP("PublishMessage", PublishMessage) } type publishRequest struct { Topic stringjson:"topic"
Message stringjson:"message"
} // PublishMessage publishes a message to Pub/Sub. PublishMessage only works // with topics that already exist. func PublishMessage(w http.ResponseWriter, r *http.Request) { // use of sync.Once ensures client is only created once. once.Do(createClient) // Parse the request body to get the topic name and message. p := publishRequest{} if err := json.NewDecoder(r.Body).Decode(&p); err != nil { log.Printf("json.NewDecoder: %v", err) http.Error(w, "Error parsing request", http.StatusBadRequest) return } if p.Topic == "" || p.Message == "" { s := "missing 'topic' or 'message' parameter" log.Println(s) http.Error(w, s, http.StatusBadRequest) return } m := &pubsub.Message{ Data: []byte(p.Message), } // Publish and Get use r.Context() because they are only needed for this // function invocation. If this were a background function, they would use // the ctx passed as an argument. id, err := client.Topic(p.Topic).Publish(r.Context(), m).Get(r.Context()) if err != nil { log.Printf("topic(%s).Publish.Get: %v", p.Topic, err) http.Error(w, "Error publishing message", http.StatusInternalServerError) return } fmt.Fprintf(w, "Message published: %v", id) }
Restablecimientos de conexiones salientes
Las secuencias de conexión de tu función a la VPC y a Internet se pueden terminar y sustituir ocasionalmente cuando se reinicia o se actualiza la infraestructura subyacente. Si tu aplicación reutiliza conexiones de larga duración, te recomendamos que la configures para que restablezca las conexiones y así evitar que se reutilice una conexión inactiva.
Tiempos de espera de solicitudes salientes
Los sockets salientes se pueden recuperar después de 10 minutos de inactividad. Cualquier operación de socket mantiene el socket activo durante 10 minutos más.
Prueba de carga de tu función
Para medir cuántas conexiones realiza tu función de media, despliégala como función HTTP y usa un framework de pruebas de rendimiento para invocarla a un determinado número de consultas por segundo. Una opción es Artillery, que puedes invocar con una sola línea:
$ artillery quick -d 300 -r 30 URL
Este comando obtiene la URL indicada a 30 QPS durante 300 segundos.
Después de realizar la prueba, comprueba el uso de tu cuota de conexiones en la página de cuotas de la API de funciones de Cloud Run de la consola de Google Cloud . Si el uso es de aproximadamente 30 (o un múltiplo de este valor), estás estableciendo una (o varias) conexiones en cada invocación. Después de optimizar el código, deberías ver que se producen algunas conexiones (entre 10 y 30) solo al principio de la prueba.
También puede comparar el coste de CPU antes y después de la optimización en el gráfico de cuota de CPU de la misma página.