Usar gRPC

En esta página se muestran detalles específicos de Cloud Run para los desarrolladores que quieran usar gRPC para conectar un servicio de Cloud Run con otros servicios. Por ejemplo, para proporcionar una comunicación sencilla y de alto rendimiento entre microservicios internos. Puedes usar todos los tipos de gRPC, ya sean de streaming o unarios, con Cloud Run.

Estos son algunos de los posibles casos prácticos:

  • Comunicación entre microservicios internos.
  • Grandes cargas de datos (gRPC usa búferes de protocolo, que son hasta siete veces más rápidos que las llamadas REST).
  • Solo necesitas una definición de servicio sencilla, no quieres escribir una biblioteca de cliente completa.
  • Usa gRPCs de streaming en tu servidor gRPC para crear aplicaciones y APIs más rápidas.

Para integrar tu servicio con gRPC, sigue estos pasos:

  • Configura tu servicio para que use HTTP/2 si utilizas gRPC de streaming. HTTP/2 es el método de transporte de la transmisión de gRPC.
  • Define los mensajes de solicitud y respuesta en un archivo proto y compílalos.
  • Crea un servidor gRPC para gestionar las solicitudes y devolver las respuestas. Debe escuchar la variable de entorno PORT.
  • Crea un cliente que envíe solicitudes y gestione las respuestas del servidor gRPC.
  • Si quieres, añade la autenticación.
  • Compila y despliega el servicio.

Configurar un servicio para que use HTTP/2

Google recomienda configurar el servicio para que use HTTP/2 si usas gRPC con Cloud Run. Aunque algunas funciones sencillas de gRPC funcionan sin usar HTTP/2, muchas funciones de gRPC, como el streaming y los metadatos, requieren HTTP/2.

Definir y compilar mensajes en un archivo proto

No hay nada adicional ni específico de Cloud Run que debas añadir a tus definiciones de proto. Al igual que con cualquier otro uso de gRPC, se utilizan buffers de protocolo de gRPC para las definiciones de servicios y la serialización de datos.

Crear un cliente gRPC

No hay que añadir nada adicional ni específico de Cloud Run a un cliente que use gRPC: sigue las instrucciones de la documentación de gRPC sobre cómo usar definiciones de servicio en el código de cliente y los clientes de ejemplo proporcionados en los tutoriales de gRPC específicos de cada lenguaje.

Balanceo de carga y autoescalado

Cloud Run usa balanceadores de carga gestionados por Google que mantienen conexiones independientes entre los clientes y tus instancias de Cloud Run. Con gRPC, el autoescalado se comporta de la siguiente manera:

  • Las conexiones gRPC de los clientes terminan en el balanceador de carga perimetral. Ajustar la configuración de KeepAlive solo afecta a la conexión con el balanceador de carga, no a las instancias de Cloud Run. El cliente no reconoce cuándo se elimina una instancia.
  • Durante el escalado horizontal, el balanceador de carga cierra las conexiones enviando mensajes GOAWAY a las instancias de backend a medida que se apagan.
  • Durante el escalado horizontal, el balanceador de carga crea nuevas conexiones con las instancias de backend. Todas estas operaciones son transparentes para los clientes.
  • Durante el escalado automático, se pueden iniciar muchas instancias y multiplexar en una sola conexión entre el cliente y el balanceador de carga proxy.
  • La simultaneidad se determina mediante el número máximo de solicitudes simultáneas por instancia de mensajes. En el streaming, cada flujo se cuenta una vez en el número máximo de solicitudes simultáneas.

Escuchar solicitudes gRPC en un servicio de Cloud Run

El único requisito especial para un servidor gRPC que se ejecute en Cloud Run es que use el puerto especificado por la variable de entorno PORT, 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)
	}
}

Abrir una conexión gRPC a un servicio

Para abrir una conexión gRPC a un servicio y poder enviar mensajes gRPC, debes especificar el dominio del host, que es la URL del servicio de Cloud Run o el dominio personalizado asignado a ese servicio, junto con el puerto 443, que es el puerto 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...)
}

Enviar solicitudes gRPC sin autenticación

En el siguiente ejemplo se muestra cómo enviar una solicitud sin autenticación mediante una conexión gRPC configurada como se ha indicado anteriormente.

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

Enviar solicitudes gRPC con autenticación

En el siguiente ejemplo se muestra cómo usar la autenticación entre servicios si el servicio que llama tiene permiso de invocador para el servicio receptor. Ten en cuenta que este código crea un encabezado de autorización que tiene el token de identidad adecuado, lo cual es obligatorio. Los permisos necesarios y el encabezado de autorización se describen en detalle en el artículo sobre la 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 ejemplo para la transmisión por streaming de gRPC

Para ver un código de muestra, consulta la implementación de RouteGuide en el tutorial de conceptos básicos de gRPC para el idioma que elijas. Por ejemplo, si usas Go, consulta Implementación de RouteGuide.