Appeler avec gRPC

Cette page présente des détails spécifiques à la diffusion Knative pour les développeurs qui souhaitent utiliser gRPC pour connecter un service de diffusion Knative à d'autres services, par exemple, afin de fournir une communication simple et hautes performances entre des microservices internes. La diffusion Knative est compatible avec les appels gRPC unaires et en flux continu.

gRPC unaire

Dans un appel RPC unaire, le client envoie une seule requête au serveur et obtient une seule réponse, comme pour un appel de fonction normal:
rpc SayHello(HelloRequest) returns (HelloResponse);

Streaming gRPC

Les options de streaming suivantes sont disponibles avec gRPC. Les RPC de streaming de serveur, où le client envoie une requête au serveur et obtient un flux à lire, qui contient une séquence de messages. Le client lit le flux renvoyé jusqu'à ce qu'il n'y ait plus de messages.

rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);

Les RPC de streaming de client, où le client écrit une séquence de messages et l'envoie au serveur dans un flux. Une fois que le client a terminé d'écrire des messages, il attend que le serveur renvoie sa réponse.

rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);

Les RPC de streaming bidirectionnels, dans lesquels le client et le serveur envoient des messages dans deux flux en lecture/écriture qui fonctionnent indépendamment.

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

Voici des exemples d'utilisation possible :

  • Communication entre des microservices internes.
  • Charges de données élevées (gRPC utilise des tampons de protocole, qui sont jusqu'à sept fois plus rapides que les appels REST).
  • Seule une définition de service simple est nécessaire, vous n'avez pas besoin d'écrire une bibliothèque cliente complète.

Pour intégrer votre service à gRPC, procédez comme suit :

  • Définissez les messages de requête et les réponses dans un fichier proto, puis compilez-les.
  • Créez un serveur gRPC pour gérer les requêtes et renvoyer des réponses : il doit écouter la variable d'environnement PORT.
  • Créez un client qui envoie des requêtes et gère les réponses du serveur gRPC.
  • Vous pouvez éventuellement ajouter une authentification.
  • Créez et déployez votre service.

Définir et compiler des messages dans un fichier proto

Vous n'avez pas besoin d'ajouter d'éléments spécifiques de diffusion supplémentaires ou Knative à vos définitions de proto. Comme pour toute autre utilisation de gRPC, vous utilisez des tampons de protocole gRPC pour les définitions de service et la sérialisation des données.

Créer un client gRPC

Vous n'avez pas besoin d'ajouter d'éléments supplémentaires ou spécifiques à la diffusion avec Knative à un client qui utilise gRPC: suivez les documents gRPC sur l'utilisation des définitions de service dans le code client et les exemples de clients fournis dans les tutoriels gRPC spécifiques au langage.

Écouter les requêtes gRPC dans un service de diffusion Knative

La seule condition requise pour un serveur gRPC exécuté dans la diffusion Knative est d'écouter le port spécifié par la variable d'environnement PORT, comme indiqué dans le code:

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

Ouvrir une connexion gRPC à un service

Pour ouvrir une connexion gRPC à un service afin de pouvoir envoyer des messages gRPC, vous devez spécifier le domaine hôte, qui est l'URL du service de diffusion Knative ou le domaine personnalisé mappé sur ce service, ainsi que le port 443, qui est le port censé être utilisé par 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...)
}

Envoyer des requêtes gRPC sans authentification

L'exemple suivant montre comment envoyer une requête sans authentification, à l'aide d'une connexion gRPC configurée comme indiqué précédemment.

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