# gRPC 簡介

gRPC 是由 Google 開發的高性能 RPC 框架,基於 HTTP/2 協議,專為微服務設計。它支持多種編程語言,使用 Protocol Buffers 進行強類型接口定義,並提供雙向流通信。這使得 gRPC 成為跨語言、高效通信的理想選擇,特別適合現代化微服務架構。

# 1. 安裝

首先,我們需要安裝 Go 和 gRPC 的相關工具。

# 安裝 Go

Go 官方網站下載並安裝 Go。

# 安裝 gRPC 相關工具

在 Windows 平台上,請按照以下步驟進行安裝:

  1. 安裝 protoc 編譯器

    Protocol Buffers Releases 下載適用於 Windows 的 protoc 編譯器。下載最新版本的壓縮包並解壓縮,然後將 bin 目錄添加到系統的 PATH 環境變數中。

  2. 安裝 Go 插件

    打開命令提示符或 PowerShell,運行以下命令來安裝 protoc-gen-goprotoc-gen-go-grpc 插件:

    go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
    go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
  3. 設置 Go 二進制目錄到 PATH

    確保你的 GOPATH 目錄的 bin 子目錄已添加到系統的 PATH 環境變數中。可以通過以下命令來確認:

    set PATH=%PATH%;%GOPATH%\\bin

# 2. 編寫 proto

創建一個 .proto 文件來定義 gRPC 服務和消息:

// example.proto
syntax = "proto3";
package example;
service ExampleService {
  rpc GetExample (ExampleRequest) returns (ExampleResponse);
}
message ExampleRequest {
  int32 id = 1;
}
message ExampleResponse {
  string message = 1;
}

# 3. 使用 protoc 編譯 proto

運行以下命令以生成 Go 代碼:

protoc --go_out=. --go-grpc_out=. example.proto

這將生成兩個文件:

  • example.pb.go : 包含消息的 Go 定義
  • example_grpc.pb.go : 包含 gRPC 服務的 Go 定義

# 4. 實作 Service

編寫 gRPC 服務的實現:

// server.go
package main
import (
    "context"
    "log"
    "net"
    "google.golang.org/grpc"
    pb "path/to/your/protos"
    "google.golang.org/grpc/reflection"
)
type server struct {
    pb.UnimplementedExampleServiceServer
}
func (s *server) GetExample(ctx context.Context, in *pb.ExampleRequest) (*pb.ExampleResponse, error) {
    return &pb.ExampleResponse{Message: "Hello, World!"}, nil
}
func main() {
    lis, err := net.Listen("tcp", ":50051")
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    s := grpc.NewServer()
    pb.RegisterExampleServiceServer(s, &server{})
    // Register reflection service on gRPC server.
    reflection.Register(s)
    log.Printf("server listening at %v", lis.Addr())
    if err := s.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}

# 5. 執行

啟動服務器:

go run server.go

# 6. 配置重試策略

使用 gRPC 的 ServiceConfig 配置來設置重試策略。我們可以在創建客戶端連接時傳遞 ServiceConfig 來指定每個方法的重試行為。以下是示例代碼:

package main
import (
    "context"
    "log"
    "time"
    "google.golang.org/grpc"
    pb "path/to/your/protos"
)
func main() {
    serviceConfig := `{
        "methodConfig": [{
            "name": [{"service": "example.ExampleService"}],
            "retryPolicy": {
                "maxAttempts": 4,
                "initialBackoff": "0.1s",
                "maxBackoff": "1s",
                "backoffMultiplier": 1.6,
                "retryableStatusCodes": ["UNAVAILABLE"]
            }
        }]
    }`
    conn, err := grpc.Dial(
        "localhost:50051",
        grpc.WithInsecure(),
        grpc.WithDefaultServiceConfig(serviceConfig),
    )
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    client := pb.NewExampleServiceClient(conn)
    // 發送請求示例
    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    defer cancel()
    req := &pb.ExampleRequest{Id: 1}
    res, err := client.GetExample(ctx, req)
    if err != nil {
        log.Fatalf("could not get example: %v", err)
    }
    log.Printf("Response: %s", res.Message)
}

# 配置說明

  • maxAttempts: 重試的最大次數,包含初始請求次數。例如,設置為 4 表示最多嘗試 4 次(1 次初始請求 + 3 次重試)。
  • initialBackoff: 初始重試等待時間。
  • maxBackoff: 最大重試等待時間。
  • backoffMultiplier: 每次重試等待時間的乘數。
  • retryableStatusCodes: 可重試的狀態碼列表,這裡配置為 UNAVAILABLE

這段代碼配置了一個 gRPC 客戶端,該客戶端將在請求失敗並返回 UNAVAILABLE 狀態碼時最多重試 4 次,每次重試的等待時間按指數增加,初始等待時間為 0.1 秒,最大等待時間為 1 秒。

當然,以下是第七點的詳細說明,包括如何配置 gRPC 客戶端的重連行為:

# 7. gRPC 重連配置

gRPC 客戶端配置可以通過環境變數或通道選項來實現重連行為。以下是一些關鍵的配置選項:

  1. 重連初始後退時間(initial backoff time):第一次重試前等待的時間。
  2. 重連最大後退時間(max backoff time):兩次重試之間的最大等待時間。
  3. 重連後退乘數(backoff multiplier):用於計算每次重試等待時間的倍數。

以下是一個示例,展示了如何在 Go 中設置這些選項來配置 gRPC 客戶端的重連行為:

package main
import (
    "context"
    "log"
    "time"
    "google.golang.org/grpc"
    "google.golang.org/grpc/backoff"
    pb "path/to/your/protos"
)
func main() {
    backoffConfig := backoff.Config{
        BaseDelay: 1 * time.Second,  // 初始後退時間
        Multiplier: 1.6,             // 後退乘數
        Jitter:     0.2,             // 隨機抖動
        MaxDelay:   10 * time.Second, // 最大後退時間
    }
    conn, err := grpc.Dial(
        "localhost:50051",
        grpc.WithInsecure(),
        grpc.WithBackoffConfig(backoffConfig),
    )
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    client := pb.NewExampleServiceClient(conn)
    // 發送請求示例
    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    defer cancel()
    req := &pb.ExampleRequest{Id: 1}
    res, err := client.GetExample(ctx, req)
    if err != nil {
        log.Fatalf("could not get example: %v", err)
    }
    log.Printf("Response: %s", res.Message)
}

# 配置說明

  • BaseDelay: 初始後退時間,這是在第一次重試之前的等待時間。在這個示例中設置為 1 秒。
  • Multiplier: 後退乘數,用於計算每次重試的等待時間。在這個示例中設置為 1.6,表示每次重試等待時間是上一次的 1.6 倍。
  • Jitter: 隨機抖動,增加一點隨機性以避免重試請求集中在同一時間點。在這個示例中設置為 0.2。
  • MaxDelay: 最大後退時間,兩次重試之間的最大等待時間。在這個示例中設置為 10 秒。

這段代碼配置了一個 gRPC 客戶端,它將根據設置的後退策略在連接失敗時進行重連。這些配置可以幫助應對網絡不穩定或服務暫時不可用的情況。