Como usar o gRPC

Nesta página, mostramos detalhes específicos do Cloud Run para desenvolvedores que querem usar o gRPC para conectar 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. É possível usar todos os tipos de gRPC, streaming ou unary, com o Cloud Run.

Os possíveis casos de uso incluem:

  • Comunicação entre microsserviços internos.
  • Altas cargas de dados (o gRPC usa buffers de protocolo (em inglês), que são até sete vezes mais rápidos do que as chamadas REST).
  • Basta uma única definição de serviço simples. Não é necessário escrever uma biblioteca de cliente completa.
  • Use gRPCs de streaming no servidor gRPC para criar aplicativos e APIs mais responsivos.

Para integrar seu serviço ao gRPC:

  • Configure o serviço para usar HTTP/2 se você estiver usando o gRPC de streaming. HTTP/2 é o método de transporte para streaming de gRPC.
  • Defina as mensagens de solicitação e as respostas em um arquivo proto e compile-as.
  • Crie um servidor gRPC para processar solicitações e retornar respostas: ele precisa detectar a variável de ambiente PORT.
  • Crie um cliente que envie solicitações e processe respostas do servidor gRPC.
  • Como opção, adicione uma autenticação.
  • Crie e implante seu serviço.

Como configurar o serviço para usar HTTP/2

O Google recomenda configurar seu serviço para usar HTTP/2 se você usar o gRPC com o Cloud Run. Alguns recursos do gRPC simples funcionam sem o uso de HTTP/2. No entanto, muitos recursos do gRPC, como streaming e metadados, exigem HTTP/2.

Como definir e compilar mensagens em um arquivo proto

Não há itens extras ou específicos do Cloud Run para adicionar às suas definições de proto. Assim como qualquer outro uso do gRPC, você usa buffers de protocolo gRPC para definições de serviço e serialização de dados.

Como criar um cliente gRPC

Não há itens extras ou específicos do Cloud Run para adicionar a um cliente que usa o gRPC: siga os documentos do gRPC sobre como usar definições de serviço no código do cliente e os clientes de amostra fornecidos no Tutoriais do gRPC específicos de linguagem.

Escalonamento automático e balanceamento de carga

O Cloud Run usa balanceadores de carga gerenciados pelo Google que mantêm conexões separadas entre clientes e instâncias do Cloud Run. Com o gRPC, o escalonamento automático se comporta da seguinte maneira:

  • As conexões gRPC de clientes terminam no balanceador de carga de borda. Ajustar as configurações de KeepAlive afeta apenas a conexão com o balanceador de carga, não as instâncias do Cloud Run. O cliente não reconhece quando uma instância é descartada.
  • Durante o escalonamento vertical, o balanceador de carga encerra as conexões enviando mensagens GOAWAY para as instâncias de back-end quando elas são encerradas.
  • Durante o escalonamento horizontal, o balanceador de carga cria novas conexões com as instâncias de back-end. Todas essas operações são transparentes para os clientes.
  • Durante o escalonamento automático, muitas instâncias podem ser iniciadas e multiplexadas em uma única conexão entre o cliente e o balanceador de carga do proxy.
  • A simultaneidade é determinada pelo máximo de solicitações simultâneas por instância para mensagens. No streaming, cada fluxo é contado uma vez em relação ao máximo de solicitações simultâneas.

Como detectar solicitações gRPC em um serviço do Cloud Run

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

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

Como abrir uma conexão gRPC com um serviço

Para abrir uma conexão gRPC com um serviço e enviar mensagens gRPC, especifique o domínio do host, que é o URL do serviço do Cloud Run ou o domínio personalizado mapeado para esse serviço. a porta 443, que é a porta esperada para ser usada pelo 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...)
}

Como enviar solicitações gRPC sem autenticação

No exemplo a seguir, mostramos como enviar uma solicitação sem autenticação, usando uma conexão gRPC configurada conforme mencionado 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)
}

Como enviar solicitações gRPC com autenticação

No exemplo a seguir, mostramos como usar a autenticação entre serviços, se o serviço de chamada tiver permissão de invocador para o serviço de recebimento. Observe que esse código cria um cabeçalho de autorização que tem o token de identidade adequado: isso é obrigatório. As permissões necessárias e o cabeçalho de autorização estão descritos em detalhes na autenticação de serviço a serviço.

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

Código de amostra para streaming gRPC

Para ver um código de amostra, consulte a implementação de RouteGuide no tutorial do básico do gRPC da linguagem que você escolher. Ao usar o Go, por exemplo, consulte Como implementar o RouteGuide.