1. 程式人生 > 實用技巧 >gRPC原始碼分析(三):從Github文件瞭解gRPC的專案細節

gRPC原始碼分析(三):從Github文件瞭解gRPC的專案細節

gRPC原始碼分析(三):從Github文件瞭解gRPC的專案細節

官方Git總覽

我們先看看GRPC這個專案的總覽,主要分三種:

  • 基於C實現,包括了 C++, Python, Ruby, Objective-C, PHP, C#
  • 其餘語言實現的,最主要是go,java,node
  • proposal,即grpc的RFC,關於實現、討論的文件彙總

從這裡可以看出,gRPC雖然是支援多語言,但原生的實現並不多。如果想在一些小眾語言裡引入gRPC,還是有很大風險的,有興趣的可以搜尋下TiDB在探索rust的gRPC的經驗分享。

gRPC-Go

作為一名Go語言開發者,我自然選擇從最熟悉的語言入手。同時,值得注意的是,grpc-go是除了C家族系列

以外使用量最大的repo,加上Go語言優秀的可讀性,是一個很好的入門gRPC的閱讀材料。

進入專案,整個README.md文件也不長。通常情況下,如果你能啃完這個文件及相關連結,你對這個開源專案就已經超過99%的人了。

對Repo的相關注意事項,大家逐行閱讀即可,整體比較簡單,我簡單列舉下關鍵點:

  1. 建議閱讀官網文件(恭喜你,上次我們已經讀完了官方文件)
  2. 在專案中的引入,建議用go mod
  3. 優先支援3個Go語言最新發布的版本
  4. FAQ中的常見問題,主要關注package下載問題如何開啟追蹤日誌

通讀完成,我們再深入看看文件細節,Example這塊我們在官網的測試中已經看過,我們的接下來重點是godoc和具體細節的文件。

go doc

DefaultBackoffConfig

注意,這個變數被棄用,被挪到ConnectParams裡了(詳情連結)。那這個所謂的連線引數是什麼用呢?程式碼不長,我們選擇幾個比較重要的內容來閱讀下,原連結可以點選這裡

// Backoff returns the amount of time to wait before the next retry given the
// number of retries.
// 根據retries返回等待時間,可以認為是一種退避策略
func (bc Exponential) Backoff(retries int) time.Duration {
	if retries == 0 {
    // 之前沒有retries過,就返回BaseDelay
		return bc.Config.BaseDelay
	}
	backoff, max := float64(bc.Config.BaseDelay), float64(bc.Config.MaxDelay)
  // 等待時間不能超過max,等待時間 = BaseDelay * Multiplier的retries次方
  // Multiplier預設1.6,並不是官方http包中的2
	for backoff < max && retries > 0 {
		backoff *= bc.Config.Multiplier
		retries--
	}
	if backoff > max {
		backoff = max
	}
	// Randomize backoff delays so that if a cluster of requests start at
	// the same time, they won't operate in lockstep.
  // 乘以一個隨機因子,數值為(1-Jitter,1+Jitter),預設為(0.8,1.2),防止同一時刻有大量請求發出,引起鎖的問題
	backoff *= 1 + bc.Config.Jitter*(grpcrand.Float64()*2-1)
	if backoff < 0 {
		return 0
	}
	return time.Duration(backoff)
}

EnableTracing

用來設定是否開啟 trace,追蹤日誌

Code

gRPC的錯誤碼,原始碼見連結,我們大概瞭解其原因即可:

  • OK正常
  • Canceled客戶端取消
  • Unknown未知
  • InvalidArgument未知引數
  • DeadlineExceeded超時
  • NotFound未找到資源
  • AlreadyExists資源已經建立
  • PermissionDenied許可權不足
  • ResourceExhausted資源耗盡
  • FailedPrecondition前置條件不滿足
  • Aborted異常退出
  • OutOfRange超出範圍
  • Unimplemented未實現方法
  • Internal內部問題
  • Unavailable不可用狀態
  • DataLoss資料丟失
  • Unauthenticated未認證

讀完上面的內容,發現跟HTTP/1.1的Status Code非常相似。

CallOption

呼叫在客戶端Invoke方法中,包括before傳送前,after為接收後。

官方提供了幾個常用的CallOption,按場景呼叫。

ClientConn

抽象的客戶端連線。

值得注意的是,conns是一個map,所以實際可能有多個tcp連線。

CodeC

定義了Marshal和Unmarshal的介面,在grpc底層實現是proto,詳細可見codec

Compressor

壓縮相關的定義

MetaData

元資料,也就是key-value,可以類比到http的header

DialOption

客戶端新建連線時的選項,按場景呼叫。

ServerOption

服務端監聽時的選項,按場景呼叫。

文件

文件連結

benchmark

效能測試,有興趣的可以細看gRPC是從哪幾個維度做RPC效能測試的。

Compression

可用encoding.RegisterCompressor實現自定義的壓縮方法。

注意,壓縮演算法應用於客戶端和服務端兩側。

Concurrency

支援併發,從三個角度分析:

  • ClientConn支援多個Goroutine
  • Steams中,SendMsg/RecvMsg可分別在兩個Goroutine中執行,但任何一個方法執行在多個Goroutine上是不安全的
  • Server每個客戶端的invoke會對應一個Server端的Goroutine

Encoding

類似Compression,可用encoding.RegisterCodec實現自定義的序列化方法。

go mock

用mock生成測試程式碼,詳細可細看。

Authentication

認證的相關選項,包括 TLS/OAuth2/GCE/JWT ,一般用前兩者即可。

Metadata

介紹了Metadata的使用,類比於HTTP/1.1的Header。

Keepalive

長連線的引數分為3類:

  • ClientParameters 客戶端側引數,主要用來探活
  • SeverParameters 服務端引數,控制連線時間
  • EnforcementPolicy 服務端加強型引數

log level

四個級別的log level,針對不同場景:

  • Info用於debug問題
  • Warning排查非關鍵性的問題
  • ErrorgRPC調用出現無法返回到客戶端的問題
  • Fatal導致程式無法恢復的致命問題

proxy

使用預設的HTTP或HTTPS代理。

rpc error

結合官方提供的錯誤碼,用status.New或者status.Error建立錯誤。

server reflection

服務端方法對映,跟著教程走即可。

值得一提的是,採用c++中的grpc_cli模組,可以檢視指定埠暴露出來的服務詳情。

versioning

版本演進,一般情況下每6週一個小版本,緊急修復會打補丁號。