Invocar con gRPC

En esta página se muestran detalles específicos de Knative Serving para desarrolladores que quieran usar gRPC para conectar un servicio de Knative Serving con otros servicios. Por ejemplo, para proporcionar una comunicación sencilla y de alto rendimiento entre microservicios internos. Knative Serving admite llamadas gRPC unarias y de streaming.

Unario de gRPC

En una llamada RPC unaria, el cliente envía una única solicitud al servidor y recibe una única respuesta, de forma similar a una llamada de función normal:
rpc SayHello(HelloRequest) returns (HelloResponse);

Transmisión gRPC

gRPC ofrece las siguientes opciones de streaming. RPCs de streaming del servidor en los que el cliente envía una solicitud al servidor y obtiene un flujo para leer que contiene una secuencia de mensajes. El cliente lee el flujo devuelto hasta que no haya más mensajes.

rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);

RPCs de streaming del cliente en los que el cliente escribe una secuencia de mensajes y los envía al servidor en un flujo. Una vez que el cliente termina de escribir los mensajes, espera a que el servidor devuelva su respuesta.

rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);

RPCs de streaming bidireccionales en los que el cliente y el servidor envían mensajes en dos flujos de lectura y escritura que funcionan de forma independiente.

rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);

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.

Para integrar tu servicio con gRPC, sigue estos pasos:

  • Define los mensajes de solicitud y las respuestas 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.

Definir y compilar mensajes en un archivo proto

No hay nada más que añadir a tus definiciones de proto que sea específico de Knative Serving. 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 específico de Knative Serving 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 que se proporcionan en los tutoriales de gRPC específicos de cada lenguaje.

Escuchar solicitudes gRPC en un servicio de Knative Serving

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