使用 gRPC

本頁面提供 Cloud Run 專屬詳細資料,供想要使用 gRPC 將 Cloud Run 服務連結至其他服務的開發人員參考,例如,在內部微服務之間提供簡單且高效能通訊。您可以搭配 Cloud Run 使用所有 gRPC 類型,包括串流或一元。

可能的用途包括:

  • 內部微服務之間的通訊。
  • 資料負載高 (gRPC 使用通訊協定緩衝區,比 REST 呼叫快上七倍)。
  • 您只需要簡單的服務定義,不必編寫完整的用戶端程式庫。
  • 在 gRPC 伺服器中使用串流 gRPC,以建構回應速度更快的應用程式和 API。

如要將服務與 gRPC 整合,請按照下列步驟操作:

  • 如果您使用串流 gRPC,請將服務設定為使用 HTTP/2。HTTP/2 是 gRPC 串流的傳輸方法。
  • 在 proto 檔案中定義要求訊息和回應,並編譯這些訊息。
  • 建立 gRPC 伺服器來處理要求並傳回回應:應監聽 PORT 環境變數。
  • 建立用來傳送要求,並處理 gRPC 伺服器回應的用戶端。
  • 視需要新增驗證機制。
  • 建構及部署服務。

將服務設定為使用 HTTP/2

如果您將 gRPC 與 Cloud Run 搭配使用,Google 建議您設定服務以使用 HTTP/2。雖然某些簡單的 gRPC 功能不必使用 HTTP/2 也能運作,但許多 gRPC 功能 (例如串流和中繼資料) 都需要使用 HTTP/2。

在 Proto 檔案中定義及編譯訊息

您不需要在 proto 定義中加入任何額外或 Cloud Run 專屬項目。如同其他 gRPC 用途,您可以使用 gRPC 通訊協定緩衝區定義服務和資料序列化。

建立 gRPC 用戶端

您不需要在使用 gRPC 的用戶端中新增任何額外或 Cloud Run 專屬項目:請按照 gRPC 說明文件中的說明,在用戶端程式碼中使用服務定義,以及在特定語言gRPC 教學課程中提供的範例用戶端。

自動調度資源與負載平衡

Cloud Run 會使用 Google 管理的負載平衡器,在用戶端和 Cloud Run 執行個體之間維持獨立的連線。在 gRPC 中,自動調整資源配置的行為如下:

  • 來自用戶端的 gRPC 連線會在邊緣負載平衡器終止。調整 KeepAlive 設定只會影響與負載平衡器的連線,不會影響 Cloud Run 執行個體。用戶端無法辨識執行個體何時掉落。
  • 在縮放期間,負載平衡器會在後端執行個體關閉時,傳送 GOAWAY 訊息來關閉連線。
  • 在擴展期間,負載平衡器會建立與後端執行個體的新連線。所有這些作業對用戶端來說都是公開透明的。
  • 在自動調整大小期間,許多執行個體可能會啟動,並在用戶端和 Proxy 負載平衡器之間建立單一連線。
  • 並行作業是由訊息的每個執行個體的並行要求數量上限決定。在串流中,系統會將每個串流計為一次並計入並行要求數量上限。

在 Cloud Run 服務中監聽 gRPC 要求

在 Cloud Run 中執行的 gRPC 伺服器唯一特殊要求,就是監聽 PORT 環境變數指定的通訊埠,如以下程式碼所示:

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 連線

如要開啟與服務的 gRPC 連線,以便傳送 gRPC 訊息,您必須指定主機網域,也就是 Cloud Run 服務的網址,或已對應至該服務的自訂網域,以及 gRPC 預期使用的通訊埠 443。

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 要求

以下範例說明如何使用先前所述的 gRPC 連線,傳送未經驗證的請求。

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 要求

以下範例說明如何在服務之間使用驗證,前提是呼叫服務擁有接收服務的叫用者權限。請注意,這個程式碼會建立具有適當身分權杖的授權標頭:這是必要的。如需詳細說明必要權限和授權標頭,請參閱服務對服務驗證

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

gRPC 串流程式碼範例

如需程式碼範例,請參閱 gRPC 基礎教學課程中,您所選語言的 RouteGuide 實作方式。舉例來說,使用 Go 時,請參閱「實作 RouteGuide」一文。