Kubernetes 提供了一些控制重試政策來處理與 API 互動時可能發生的錯誤和故障。這些政策可以幫助您實作可靠的操作,提高應用程式的容錯性。
- 重試:
-
政策在操作失敗時會立即進行重試。Retry
- 控制器或用戶端可以指定重試次數,如果操作在重試次數内仍然失敗,則放棄重試并傳回錯誤。
- 指數退避(Exponential Backoff):
-
政策會根據重試次數逐漸增加重試的時間間隔。Exponential Backoff
- 控制器或用戶端可以指定初始的重試間隔和最大的重試間隔。
- 重試間隔會根據指數函數逐漸增加,例如每次重試的間隔時間是前一次的兩倍。
- 這樣的政策有助于避免在操作失敗時産生過多的請求,減少對系統的負載壓力。
- 等待(Wait):
-
政策會在操作失敗時等待一段固定的時間間隔,然後再進行重試。Wait
- 控制器或用戶端可以指定等待的時間間隔。
package main
import (
"fmt"
"math/rand"
"time"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/util/retry"
"k8s.io/klog/v2"
)
var numberOfRetries = 0
func main() {
// 建立一個自定義的退避政策
waitBackoff := wait.Backoff{
Duration: 2 * time.Second, // 初始退避間隔
Factor: 2, // 退避系數
Jitter: 0.1, // 随機化因子
Steps: 10, // 最大重試次數
}
// 自定義的退避政策函數
backoffFunc := func() error {
klog.Infof("Performing operation...")
err := performOperation()
if err != nil {
klog.Warningf("Operation failed: %v", err)
return err
}
klog.Infof("Operation succeeded.")
return nil
}
// 使用自定義的退避政策執行操作
err := retry.OnError(waitBackoff, shouldRetry, backoffFunc)
if err != nil {
klog.Errorf("Failed to perform operation: %v", err)
} else {
klog.Infof("Operation completed successfully.")
}
}
// 執行操作的函數
func performOperation() error {
numberOfRetries++
klog.Infof(fmt.Sprintf("Start %d retry", numberOfRetries))
// 模拟操作失敗的情況
if rand.Intn(10) < 9 {
return fmt.Errorf("Operation failed")
}
return nil
}
// 判斷是否應該重試的函數
func shouldRetry(err error) bool {
// 這裡可以根據具體的錯誤類型進行判斷
return true
}
使用
wait.Backoff{}
結構體時,各個字段的含義如下:
-
:初始退避間隔是 2 秒。在進行第一次重試之前,我們會等待 2 秒鐘,這是重試的初始等待時間。Duration: 2 * time.Second
-
:退避系數是 2。每次重試時,我們會将上一次的等待時間乘以 2,以獲得下一次重試的等待時間。例如,如果第一次重試等待了 2 秒,那麼下一次将等待 4 秒,再下一次将等待 8 秒,依此類推。Factor: 2
-
:随機化因子是 0.1。為了避免所有重試操作同時發生,我們可以在每次計算等待時間時引入一定的随機性。随機化因子表示在計算等待時間時,我們會将結果乘以一個介于 0 和 1 之間的随機值。這樣可以使得每個重試操作之間有一定的随機差異。Jitter: 0.1
-
:最大重試次數是 5。我們會在達到最大重試次數後停止重試操作。在這種情況下,即使上一次重試失敗,我們也不會再進行下一次重試。Steps: 5
假設我們有一個需要重試的操作。初始退避間隔為 2 秒,然後每次重試的等待時間都會翻倍。為了避免同時進行所有重試操作,我們會在每次計算等待時間時引入一定的随機性。最大重試次數為 5,如果達到最大重試次數後仍然失敗,我們将停止重試。
如果想提高模拟測試的時候,程式在中間成功的機率的話,可以修改這裡的值if rand.Intn(10) < 9 { return fmt.Errorf("Operation failed") }
除了
retry.OnError
還有
retry.RetryOnConflict
,
RetryOnConflict
函數的作用是在發生沖突錯誤(Conflict Error)時進行重試。
函數接受兩個參數:
-
:一個實作了backoff
接口的對象,用于定義最大重試次數和兩次重試之間的等待間隔。wait.Backoff
-
:一個函數,表示要執行的操作函數。fn
在函數内部,
RetryOnConflict
調用了
OnError
函數,并傳入了
errors.IsConflict
函數作為
retriable
參數。
errors.IsConflict
是一個用于判斷錯誤是否為沖突錯誤的函數。
OnError
函數會在每次重試時調用
fn
函數執行操作,并根據傳回的錯誤判斷是否可重試。而将
errors.IsConflict
作為
retriable
參數,意味着隻有當傳回的錯誤是沖突錯誤時,才會進行重試。
通過使用
RetryOnConflict
函數,我們可以在執行某個操作時遇到沖突錯誤時自動進行重試,直到操作成功或達到最大重試次數。這樣可以處理并發通路資源時可能發生的沖突情況,提高操作的成功率。
何為Conflict Error?
在Kubernetes中,沖突錯誤(Conflict Error)通常指的是針對資源對象的更新操作時發生的沖突情況。
當多個并發的操作嘗試修改同一個資源對象時,可能會發生沖突。例如,兩個操作同時嘗試更新同一個資源的字段,或者一個操作在另一個操作完成之前修改了資源的狀态。
當這種沖突發生時,Kubernetes會傳回一個沖突錯誤。這個錯誤通常是HTTP狀态碼為 409(Conflict)的響應。它表示目前的操作與其他操作存在沖突,無法順利執行。
沖突錯誤的常見原因包括:
- 資源版本不比對:當多個操作使用相同的資源版本号來修改同一個資源時,會導緻沖突。
- 并發更新:當多個操作同時嘗試更新同一個資源的字段或狀态時,可能會發生沖突。
- 樂觀并發控制:某些資源對象使用樂觀并發控制機制,即在更新時會比較資源的版本号,如果版本号不比對,則表示發生了沖突。