Usa gRPC

En esta página, se muestran detalles específicos de Cloud Run para desarrolladores que desean usar gRPC a fin de conectar un servicio de Cloud Run con otros servicios, por ejemplo, con el objetivo de proporcionar una comunicación simple y de alto rendimiento entre microservicios internos. Puedes usar todos los tipos de gRPC, de transmisión o unario, con Cloud Run.

Entre los casos prácticos se incluyen los siguientes:

  • Comunicación entre microservicios internos
  • Cargas altas de datos (gRPC usa búferes de protocolo, que son hasta siete veces más rápidos que las llamadas de REST).
  • Solo se necesita una definición de servicio simple; no es necesario que escribas una biblioteca cliente completa
  • Usa gRPC de transmisión en tu servidor de gRPC para compilar API y aplicaciones más responsivas.

Para integrar el servicio a gRPC, sigue estos pasos:

  • Configura tu servicio para que utilice HTTP/2 si usas gRPC de transmisión. HTTP/2 es el método de transporte para la transmisión de gRPC.
  • Define los mensajes y las respuestas de la solicitud en un archivo proto y compílalos.
  • Crea un servidor de gRPC para administrar las solicitudes y mostrar las respuestas: debe escuchar la variable de entorno PORT.
  • Crea un cliente que envíe solicitudes y administre respuestas desde el servidor de gRPC.
  • De manera opcional, agrega autenticación.
  • Compila y, luego, implementa el servicio.

Configura tu servicio para usar HTTP/2

Google recomienda configurar el servicio para que use HTTP/2 si utilizas gRPC con Cloud Run. Aunque algunas funciones simples de gRPC funcionan sin el uso de HTTP/2, muchas otras, como la transmisión y los metadatos, requieren HTTP/2.

Define y compila mensajes en un archivo proto

No hay elementos adicionales o específicos de Cloud Run para agregar a las definiciones de proto. Como con cualquier otro uso de gRPC, usa búferes de protocolo de gRPC para las definiciones de servicios y la serialización de datos.

Crea un cliente de gRPC

No hay elementos adicionales o específicos de Cloud Run para agregar a un cliente que usa gRPC. Sigue los documentos de gRPC acerca del uso de definiciones de servicios en el código del cliente y los clientes de muestra proporcionados en los instructivos de gRPC específicos del lenguaje.

Ajuste de escala automático y balanceo de cargas

Cloud Run usa balanceadores de cargas administrados por Google que mantienen conexiones separadas entre los clientes y las instancias de Cloud Run. Con gRPC, el ajuste de escala automático se comporta de la siguiente manera:

  • Las conexiones de gRPC de los clientes finalizan en el balanceador de cargas perimetral. El ajuste de la configuración de KeepAlive solo afecta la conexión con el balanceador de cargas, no con las instancias de Cloud Run. El cliente no reconoce cuando se descarta una instancia.
  • Durante la reducción de escala, el balanceador de cargas cierra las conexiones mediante el envío de mensajes GOAWAY a las instancias de backend a medida que se apagan.
  • Durante el escalamiento horizontal, el balanceador de cargas crea conexiones nuevas a las instancias de backend. Todas estas operaciones son transparentes para los clientes.
  • Durante el ajuste de escala automático, muchas instancias pueden iniciarse y multiplexar en una sola conexión entre el cliente y el balanceador de cargas del proxy.
  • La simultaneidad se determina mediante la cantidad máxima de solicitudes simultáneas por instancia para los mensajes. En la transmisión, cada transmisión se cuenta una vez en la cantidad máxima de solicitudes simultáneas.

Escucha las solicitudes de gRPC en un servicio de Cloud Run

El único requisito especial para un servidor de gRPC que se ejecuta en Cloud Run es escuchar en el puerto que la variable de entorno PORT especificó como se muestra en el siguiente código:

Go

func main() {
	log.Printf("grpc-ping: starting server...")

	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
		log.Printf("Defaulting to port %s", port)
	}

	listener, err := net.Listen("tcp", ":"+port)
	if err != nil {
		log.Fatalf("net.Listen: %v", err)
	}

	grpcServer := grpc.NewServer()
	pb.RegisterPingServiceServer(grpcServer, &pingService{})
	if err = grpcServer.Serve(listener); err != nil {
		log.Fatal(err)
	}
}

Abre una conexión de gRPC a un servicio

Para abrir una conexión de gRPC a un servicio a fin de que puedas enviar mensajes de gRPC, debes especificar el dominio del host, que es la URL del servicio de Cloud Run o el dominio personalizado que se asignó a ese servicio, junto con el puerto 443, que es el que se espera que use gRPC.

Go


import (
	"crypto/tls"
	"crypto/x509"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
)

// NewConn creates a new gRPC connection.
// host should be of the form domain:port, e.g., example.com:443
func NewConn(host string, insecure bool) (*grpc.ClientConn, error) {
	var opts []grpc.DialOption
	if host != "" {
		opts = append(opts, grpc.WithAuthority(host))
	}

	if insecure {
		opts = append(opts, grpc.WithInsecure())
	} else {
		// Note: On the Windows platform, use of x509.SystemCertPool() requires
		// go version 1.18 or higher.
		systemRoots, err := x509.SystemCertPool()
		if err != nil {
			return nil, err
		}
		cred := credentials.NewTLS(&tls.Config{
			RootCAs: systemRoots,
		})
		opts = append(opts, grpc.WithTransportCredentials(cred))
	}

	return grpc.Dial(host, opts...)
}

Envía solicitudes de gRPC sin autenticación

En el siguiente ejemplo, se muestra cómo enviar una solicitud sin autenticación mediante una conexión de gRPC que se configuró como se mencionó antes.

Go


import (
	"context"
	"time"

	pb "github.com/GoogleCloudPlatform/golang-samples/run/grpc-ping/pkg/api/v1"
	"google.golang.org/grpc"
)

// pingRequest sends a new gRPC ping request to the server configured in the connection.
func pingRequest(conn *grpc.ClientConn, p *pb.Request) (*pb.Response, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	client := pb.NewPingServiceClient(conn)
	return client.Send(ctx, p)
}

Envía solicitudes de gRPC con autenticación

En el siguiente ejemplo, se muestra cómo usar la autenticación entre servicios si el servicio que realiza la llamada tiene permiso para invocar el servicio receptor. Ten en cuenta que este código crea un encabezado de autorización que tiene el token de identidad adecuado; esto es obligatorio. El encabezado de autorización y los permisos obligatorios se describen en detalle en Autenticación de servicio a servicio.

Go


import (
	"context"
	"fmt"
	"time"

	"google.golang.org/api/idtoken"
	"google.golang.org/grpc"
	grpcMetadata "google.golang.org/grpc/metadata"

	pb "github.com/GoogleCloudPlatform/golang-samples/run/grpc-ping/pkg/api/v1"
)

// pingRequestWithAuth mints a new Identity Token for each request.
// This token has a 1 hour expiry and should be reused.
// audience must be the auto-assigned URL of a Cloud Run service or HTTP Cloud Function without port number.
func pingRequestWithAuth(conn *grpc.ClientConn, p *pb.Request, audience string) (*pb.Response, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	// Create an identity token.
	// With a global TokenSource tokens would be reused and auto-refreshed at need.
	// A given TokenSource is specific to the audience.
	tokenSource, err := idtoken.NewTokenSource(ctx, audience)
	if err != nil {
		return nil, fmt.Errorf("idtoken.NewTokenSource: %w", err)
	}
	token, err := tokenSource.Token()
	if err != nil {
		return nil, fmt.Errorf("TokenSource.Token: %w", err)
	}

	// Add token to gRPC Request.
	ctx = grpcMetadata.AppendToOutgoingContext(ctx, "authorization", "Bearer "+token.AccessToken)

	// Send the request.
	client := pb.NewPingServiceClient(conn)
	return client.Send(ctx, p)
}

Código de muestra para la transmisión de gRPC

Para ver el código de muestra, consulta la implementación de RouteGuide en el instructivo de gRPC para el lenguaje que elijas. Cuando uses Go, por ejemplo, consulta Implementa RouteGuide.