Usar gRPC

Esta página mostra detalhes específicos do Cloud Run para programadores que querem usar o gRPC para ligar um serviço do Cloud Run a outros serviços, por exemplo, para fornecer uma comunicação simples e de alto desempenho entre microsserviços internos. Pode usar todos os tipos de gRPC, streaming ou unário, com o Cloud Run.

Seguem-se alguns exemplos de utilização:

  • Comunicação entre microserviços internos.
  • Grandes cargas de dados (o gRPC usa buffers de protocolo, que são até sete vezes mais rápidos do que as chamadas REST).
  • Só precisa de uma definição de serviço simples e não quer escrever uma biblioteca de cliente completa.
  • Use gRPCs de streaming no seu servidor gRPC para criar aplicações e APIs mais dinâmicas.

Para integrar o seu serviço com o gRPC:

  • Configure o seu serviço para usar HTTP/2 se estiver a usar gRPC de streaming. O HTTP/2 é o método de transporte para o streaming gRPC.
  • Defina as mensagens de pedido e as respostas num ficheiro proto e compile-as.
  • Crie um servidor gRPC para processar pedidos e devolver respostas: deve ouvir a variável de ambiente PORT.
  • Crie um cliente que envie pedidos e processe respostas do servidor gRPC.
  • Opcionalmente, adicione autenticação.
  • Crie e implemente o seu serviço.

Configurar o seu serviço para usar HTTP/2

A Google recomenda configurar o seu serviço para usar HTTP/2 se usar gRPC com o Cloud Run. Embora algumas funcionalidades simples do gRPC funcionem sem usar o HTTP/2, muitas funcionalidades do gRPC, como o streaming e os metadados, requerem o HTTP/2.

Definir e compilar mensagens num ficheiro proto

Não existem elementos adicionais ou específicos do Cloud Run para adicionar às suas definições de proto. Tal como acontece com qualquer outra utilização do gRPC, usa buffers de protocolo gRPC para definições de serviços e serialização de dados.

Criar um cliente gRPC

Não existem elementos adicionais ou específicos do Cloud Run a adicionar a um cliente que use gRPC: siga as instruções da documentação do gRPC sobre a utilização de definições de serviços no código do cliente e os clientes de exemplo fornecidos nos tutoriais do gRPC específicos do idioma.

Escala automática e balanceamento de carga

O Cloud Run usa equilibradores de carga geridos pela Google que mantêm ligações separadas entre os clientes e as suas instâncias do Cloud Run. Com o gRPC, o dimensionamento automático funciona da seguinte forma:

  • As ligações gRPC dos clientes terminam no balanceador de carga de limite. O ajuste das definições KeepAliveafeta apenas a ligação ao equilibrador de carga e não as instâncias do Cloud Run. O cliente não reconhece quando uma instância é eliminada.
  • Durante a redução, o balanceador de carga fecha as ligações enviando mensagens GOAWAY para as instâncias de back-end à medida que são encerradas.
  • Durante a expansão, o balanceador de carga cria novas ligações às instâncias de back-end. Todas estas operações são transparentes para os clientes.
  • Durante o dimensionamento automático, podem ser iniciadas muitas instâncias e multiplexadas numa única ligação entre o cliente e o balanceador de carga de proxy.
  • A simultaneidade é determinada pelo máximo de pedidos simultâneos por instância para mensagens. No streaming, cada stream é contabilizada uma vez em relação ao máximo de pedidos concorrentes.

Ouvir pedidos gRPC num serviço do Cloud Run

O único requisito especial para um servidor gRPC em execução no Cloud Run é ouvir na porta especificada pela variável de ambiente PORT, conforme mostrado no código seguinte:

Ir

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 uma ligação gRPC a um serviço

Para abrir uma ligação gRPC a um serviço para que possa enviar mensagens gRPC, tem de especificar o domínio do anfitrião, que é o URL do serviço do Cloud Run ou o domínio personalizado mapeado para esse serviço, juntamente com a porta 443, que é a porta esperada para ser usada pelo gRPC.

Ir


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 pedidos gRPC sem autenticação

O exemplo seguinte mostra como enviar um pedido sem autenticação, usando uma ligação gRPC configurada como mencionado anteriormente.

Ir


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 pedidos gRPC com autenticação

O exemplo seguinte mostra como usar a autenticação entre serviços, se o serviço de chamada tiver autorização de invocador para o serviço de receção. Tenha em atenção que este código cria um cabeçalho de autorização com o token de identidade adequado. Isto é obrigatório. As autorizações necessárias e o cabeçalho de autorização são descritos detalhadamente na autenticação de serviço para serviço.

Ir


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

Exemplo de código para streaming gRPC

Para ver um código de exemplo, consulte a implementação da RouteGuide no tutorial de noções básicas do gRPC para o idioma da sua escolha. Quando usar o Go, por exemplo, consulte o artigo Implementar o RouteGuide.