gRPC verwenden

Diese Seite enthält spezifische Details zu Cloud Run für Entwickler, die gRPC zum Herstellen einer Verbindung zwischen einem Cloud Run-Dienst und anderen Diensten verwenden möchten, um beispielsweise eine einfache Hochleistungskommunikation zwischen internen Mikrodiensten zu ermöglichen. Sie können alle gRPC-Typen, Streaming oder Unäre, mit Cloud Run verwenden.

Mögliche Anwendungsfälle:

  • Kommunikation zwischen internen Mikrodiensten.
  • Hohe Datenmengen (gRPC verwendet Protokollzwischenspeicher, die bis zu siebenmal schneller sind als REST-Aufrufe).
  • Es wird nur eine einfache Dienstdefinition benötigt. Das Schreiben einer vollständigen Clientbibliothek ist nicht erforderlich.
  • Verwenden Sie Streaming-gRPC auf Ihrem gRPC-Server, um responsive Anwendungen und APIs zu erstellen.

So binden Sie Ihren Dienst in gRPC ein:

  • Konfigurieren Sie Ihren Dienst für die Verwendung von HTTP/2, wenn Sie gRPC verwenden. HTTP/2 ist die Transportmethode für das gRPC-Streaming.
  • Definieren Sie die Anfragenachrichten und -antworten in einer proto-Datei und kompilieren Sie sie.
  • Erstellen Sie einen gRPC-Server, der Anfragen verarbeitet und Antworten zurückgibt. Er sollte die Umgebungsvariable PORT beobachten.
  • Erstellen Sie einen Client, der Anfragen sendet und Antworten vom gRPC-Server verarbeitet.
  • Optional können Sie eine Authentifizierung hinzufügen.
  • Erstellen Sie Ihren Dienst und stellen Sie ihn bereit.

Dienst für die Verwendung von HTTP/2 konfigurieren

Google empfiehlt, den Dienst für die Verwendung von HTTP/2 zu konfigurieren, wenn Sie gRPC mit Cloud Run verwenden. Einige einfache gRPC-Funktionen funktionieren auch ohne HTTP/2. Viele gRPC-Funktionen wie Streaming und Metadaten erfordern HTTP/2.

Nachrichten in einer proto-Datei definieren und kompilieren

Ihren proto-Definitionen müssen keine zusätzlichen oder Cloud Run-spezifischen Elemente hinzugefügt werden. Wie bei jedem anderen Einsatz von gRPC verwenden Sie für Dienstdefinitionen und Datenserialisierung gRPC-Protokollpuffer.

gRPC-Client erstellen

Ihrem Client, der gRPC verwendet, müssen keine zusätzlichen oder Cloud Run-spezifischen Elemente hinzugefügt werden. Folgen Sie der gRPC-Dokumentation zur Verwendung von Dienstdefinitionen im Clientcode und den Beispielclients aus den sprachspezifischen gRPC-Anleitungen.

Autoscaling und Load Balancing

Cloud Run verwendet von Google verwaltete Load Balancer, die separate Verbindungen zwischen Clients und Ihren Cloud Run-Instanzen aufrechterhalten. Bei gRPC verhält sich das Autoscaling so:

  • gRPC-Verbindungen von Clients enden am Edge-Load Balancer. Die Anpassung der KeepAlive-Einstellungen wirkt sich nur auf die Verbindung zum Load Balancer aus, nicht auf die Cloud Run-Instanzen. Der Client erkennt nicht, wenn eine Instanz gelöscht wird.
  • Beim Scale-In schließt der Load Balancer Verbindungen, indem er beim Herunterfahren der Back-End-Instanzen GOAWAY-Nachrichten sendet.
  • Beim Skalieren erstellt der Load Balancer neue Verbindungen zu den Back-End-Instanzen. Alle diese Vorgänge sind für Clients transparent.
  • Während des Autoscalings können viele Instanzen gestartet und zu einer einzigen Verbindung zwischen dem Client und dem Proxy-Load-Balancer multipliziert werden.
  • Die Gleichzeitigkeit wird durch die maximale Anzahl gleichzeitiger Anfragen pro Instanz für Nachrichten bestimmt. Beim Streaming wird jeder Stream einmal auf die maximale Anzahl gleichzeitiger Anfragen angerechnet.

gRPC-Anfragen in einem Cloud Run-Dienst überwachen

Die einzige spezielle Anforderung an einen in Cloud Run ausgeführten gRPC-Server besteht darin, den in der Umgebungsvariable PORT angegebenen Port wie im folgenden Code dargestellt zu beobachten:

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

gRPC-Verbindung zu einem Dienst öffnen

Wenn Sie eine gRPC-Verbindung zu einem Dienst öffnen möchten, um gRPC-Nachrichten senden zu können, müssen Sie die Host-Domain angeben. Dies ist die URL des Cloud Run-Dienstes oder die benutzerdefinierte Domain, die diesem Dienst neben Port 443 zugeordnet ist. Port 443 ist der von gRPC erwartete Port.

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

gRPC-Anfragen ohne Authentifizierung senden

Im folgenden Beispiel wird gezeigt, wie eine Anfrage ohne Authentifizierung über eine gRPC-Verbindung gesendet wird, die wie oben beschrieben konfiguriert ist.

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

gRPC-Anfragen mit Authentifizierung senden

Im folgenden Beispiel wird gezeigt, wie die Authentifizierung zwischen Diensten verwendet wird, wenn der aufrufende Dienst die Berechtigung als Aufrufer für den empfangenden Dienst hat. Beachten Sie, dass mit diesem Code ein Autorisierungsheader mit dem richtigen Identitätstoken erstellt wird. Dies ist erforderlich. Die erforderlichen Berechtigungen und der Autorisierungsheader werden unter Dienst-zu-Dienst-Authentifizierung ausführlich beschrieben.

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

Beispielcode für gRPC-Streaming

Einen Beispielcode finden Sie in der RouteGuide-Implementierung in der gRPC in einer Sprache Ihrer Wahl. Beispiele zu Go finden Sie im Implementierungsleitfaden.