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 Verbindungen zwischen Clients und Ihren Cloud Run-Instanzen getrennt halten. Bei gRPC verhält sich 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.
  • Während des Herunterskalierens schließt der Load-Balancer Verbindungen, indem er GOAWAY-Nachrichten an die Backend-Instanzen sendet, wenn diese heruntergefahren werden.
  • Beim horizontalen Skalieren erstellt der Load-Balancer neue Verbindungen zu den Backend-Instanzen. All diese Vorgänge sind für den Kunden transparent.
  • Während des Autoscalings können viele Instanzen gestartet und mit Multiplex eine einzelne Verbindung zwischen dem Client und dem Proxy-Load-Balancer herstellen.
  • Die Gleichzeitigkeit wird durch die maximale Anzahl gleichzeitiger Anfragen pro Instanz für Nachrichten bestimmt. Beim Streaming wird jeder Stream einmal bei der maximalen Anzahl gleichzeitiger Anfragen gezählt.

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:

Einfach loslegen (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.

Einfach loslegen (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.

Einfach loslegen (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.

Einfach loslegen (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 Grundlegenden gRPC-Anleitung in einer Sprache Ihrer Wahl. Informationen zur Verwendung von Go finden Sie beispielsweise im Implementierungsleitfaden.