目前有三類重試:超時重試、Backup Request,建連失敗重試(默認)。其中建連失敗是網絡層面問題,由于請求未發(fā)出,框架會默認重試。 本文檔介紹前兩類重試的使用:
因為很多的業(yè)務請求不具有冪等性,這兩類重試不會作為默認策略。
超時重試和 Backup Request 策略只能配置其中之一。
配置項 | 默認值 | 說明 | 限制 |
---|---|---|---|
MaxRetryTimes
|
2 | 最大重試次數,不包含首次請求。如果配置為 0 表示停止重試。 | 合法值:[0-5] |
MaxDurationMS
|
0 | 累計最大耗時,包括首次失敗請求和重試請求耗時,如果耗時達到了限制的時間則停止后續(xù)的重試。0 表示無限制。注意:如果配置,該配置項必須大于請求超時時間。 | |
EERThreshold
|
10% | 重試熔斷錯誤率閾值, 方法級別請求錯誤率超過閾值則停止重試。 | 合法值:(0-30%] |
ChainStop
|
- | 鏈路中止, 默認啟用。如果上游請求是重試請求,超時后不會重試。 | >= v0.0.5 后作為默認策略 |
DDLStop
|
false | 鏈路超時中止,該策略是從鏈路的超時時間判斷是否需要重試。注意,Kitex 未內置該實現(xiàn),需通過 retry.RegisterDDLStop(ddlStopFunc) 注冊 DDL func,結合鏈路超時判斷,實現(xiàn)上建議基于上游的發(fā)起調用的時間戳和超時時間判斷。?? | |
BackOff
|
None | 重試等待策略,默認立即重試(NoneBackOff )??蛇x:固定時長退避 (FixedBackOff )、隨機時長退避 (RandomBackOff )。 |
|
RetrySameNode
|
false | 框架默認選擇其他節(jié)點重試,若需要同節(jié)點重試,可配置為 true。 |
配置項 | 默認值 | 說明 | 限制 |
---|---|---|---|
RetryDelayMS
|
- | Backup Request 的等待時間,若該時間內若請求未返回,會發(fā)送新的請求。必須手動配置,建議參考 TP99。 | |
MaxRetryTimes
|
1 | 最大重試次數,不包含首次請求。 如果配置為 0 表示停止重試。 | 合法值:[0-2] |
EERThreshold
|
10% | 重試熔斷錯誤率閾值,方法級別請求錯誤率超過閾值則停止重試。 | 合法值:(0-30%] |
ChainStop
|
- | 鏈路中止, 默認啟用。如果上游請求是重試請求,不會發(fā)送 Backup Request。 | >= v0.0.5 后作為默認策略 |
RetrySameNode
|
false | 框架默認選擇其他節(jié)點重試,若需要同節(jié)點重試,可配置為 true |
注意:若通過代碼配置開啟重試,動態(tài)配置 (見 3.3) 則無法生效。
// import "github.com/cloudwego/kitex/pkg/retry"
fp := retry.NewFailurePolicy()
fp.WithMaxRetryTimes(3) // 配置最多重試3次
xxxCli := xxxservice.NewClient("destServiceName", client.WithFailureRetry(fp))
fp := retry.NewFailurePolicy()
// 重試次數, 默認2,不包含首次請求
fp.WithMaxRetryTimes(xxx)
// 總耗時,包括首次失敗請求和重試請求耗時達到了限制的duration,則停止后續(xù)的重試。
fp.WithMaxDurationMS(xxx)
// 關閉鏈路中止
fp.DisableChainRetryStop()
// 開啟DDL中止
fp.WithDDLStop()
// 退避策略,默認無退避策略
fp.WithFixedBackOff(fixMS int) // 固定時長退避
fp.WithRandomBackOff(minMS int, maxMS int) // 隨機時長退避
// 開啟重試熔斷
fp.WithRetryBreaker(errRate float64)
// 同一節(jié)點重試
fp.WithRetrySameNode()
建議配置為 TP99,則 1% 請求會觸發(fā) Backup Request。
// 首次請求 xxx ms未返回,發(fā)起 backup 請求,并開啟鏈路中止
bp := retry.NewBackupPolicy(xxx)
xxxCli := xxxservice.NewClient("destServiceName", client.WithBackupRequest(bp))
bp := retry.NewBackupPolicy(xxx)
// 重試次數, 默認1,不包含首次請求
bp.WithMaxRetryTimes(xxx)
// 關閉鏈路中止
bp.DisableChainRetryStop()
// 開啟重試熔斷
bp.WithRetryBreaker(errRate float64)
// 同一節(jié)點重試
bp.WithRetrySameNode()
當開啟了服務的熔斷配置可以復用熔斷的統(tǒng)計減少額外的 CPU 消耗,注意重試的熔斷閾值須低于服務的熔斷閾值,使用如下:
// 1. 初始化 kitex 內置的 cbsuite
cbs := circuitbreak.NewCBSuite(circuitbreak.RPCInfo2Key)
// 2. 初始化 retryContainer,傳入ServiceControl和ServicePanel
retryC := retry.NewRetryContainerWithCB(cs.cbs.ServiceControl(), cs.cbs.ServicePanel())
var opts []client.Option
// 3. 配置 retryContainer
opts = append(opts, client.WithRetryContainer(retryC))
// 4. 配置 Service circuit breaker
opts = append(opts, client.WithMiddleware(cbs.ServiceCBMW()))
// 5. 初始化 Client, 傳入配置 option
cli, err := xxxservice.NewClient(targetService, opts...)
若需要結合遠程配置,動態(tài)開啟重試或運行時調整策略,可以通過 retryContainer 的 NotifyPolicyChange 方法生效,目前 Kitex 開源版本暫未提供遠程配置模塊,使用者可集成自己的配置中心。注意:若已通過代碼配置開啟,動態(tài)配置則無法生效。 使用示例:
retryC := retry.NewRetryContainer()
// demo
// 1. define your change func
// 2. exec yourChangeFunc in your config module
yourChangeFunc := func(key string, oldData, newData interface{}) {
newConf := newData.(*retry.Policy)
method := parseMethod(key)
retryC.NotifyPolicyChange(method, policy)
}
// configure retryContainer
cli, err := xxxservice.NewClient(targetService, client.WithRetryContainer(retryC))
Kitex 對重試的請求在 rpcinfo 中記錄了重試次數和之前請求的耗時,可以在Client側的 metric 或日志中根據 retry tag 區(qū)分上報或輸出。獲取方式:
var retryCount string
var lastCosts string
toInfo := rpcinfo.GetRPCInfo(ctx).To()
if retryTag, ok := toInfo.Tag(rpcinfo.RetryTag); ok {
retryCount = retryTag
if lastCostTag, ok := toInfo.Tag(rpcinfo.RetryLastCostTag); ok {
lastCosts = lastCostTag
}
}
如果使用 TTHeader 作為傳輸協(xié)議,下游 handler 可以通過如下方式判斷當前是否是重試請求,自行決定是否繼續(xù)處理。
retryReqCount, exist := metainfo.GetPersistentValue(ctx,retry.TransitKey)
比如 retryReqCount = 2,表示第二次重試請求(不包括首次請求),則采取業(yè)務降級策略返回部分或 mock 數據返回(非重試請求沒有該信息)。
Q: 框架默認開啟鏈路中止,業(yè)務是否還有必要識別重試請求?
鏈路中止是指鏈路上的重試請求不會重試,比如 A->B->C,A 向 B 發(fā)送的是重試請求,如果 B->C 超時了或者配置了 Backup,則 B 不會再發(fā)送重試請求到 C。如果業(yè)務自行識別重試請求,可以直接決定是否繼續(xù)請求到 C。簡言之鏈路中止避免了 B 向 C 發(fā)送重試請求導致重試放大,業(yè)務自己控制可以完全避免 B 到 C 的請求。
更多建議: