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家族系列
進入專案,整個README.md文件也不長。通常情況下,如果你能啃完這個文件及相關連結,你對這個開源專案就已經超過99%的人了。
對Repo的相關注意事項,大家逐行閱讀即可,整體比較簡單,我簡單列舉下關鍵點:
- 建議閱讀官網文件(恭喜你,上次我們已經讀完了官方文件)
- 在專案中的引入,建議用go mod
- 優先支援3個Go語言最新發布的版本
- 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
支援多個GoroutineSteams
中,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
排查非關鍵性的問題Error
gRPC調用出現無法返回到客戶端的問題Fatal
導致程式無法恢復的致命問題
proxy
使用預設的HTTP或HTTPS代理。
rpc error
結合官方提供的錯誤碼,用status.New
或者status.Error
建立錯誤。
server reflection
服務端方法對映,跟著教程走即可。
值得一提的是,採用c++中的grpc_cli模組,可以檢視指定埠暴露出來的服務詳情。
versioning
版本演進,一般情況下每6週一個小版本,緊急修復會打補丁號。