go-kit 微服務 服務熔斷(hystrix-go 實現)
- 對客戶端請求login方法添加熔斷
Hystrix
- 在微服務架構中,每個服務都是相互關聯的,比如我們下單服務和扣錢服務是分開的,現在扣錢服務出現的bug不能正常服務
- Hystrix可以讓我們在在微服務架構中對服務間的調用進行控制,加入一些調用延遲或者服務降級的容錯機制。
Hystrix的設計原則
- 對依賴服務調用時出現的調用延遲和調用失敗進行控制和容錯保護
- 在復雜的分布式系統中,阻止某一個依賴服務的故障在整個系統中蔓延
- 提供fail-fast(快速失敗)和快速恢復的支持
- 提供fallback優雅降級的支持
- 支持近實時的監控、報警以及運維操作
編寫Hystrix類
import (
"errors"
"github.com/afex/hystrix-go/hystrix"
"sync"
)
var config = hystrix.CommandConfig{
Timeout: 5000, //執行command的超時時間(毫秒)
MaxConcurrentRequests: 8, //command的最大並發量
SleepWindow: 1000, //過多長時間,熔斷器再次檢測是否開啟。單位毫秒
ErrorPercentThreshold: 30, //錯誤率 請求數量大於等於RequestVolumeThreshold並且錯誤率到達這個百分比后就會啟動
RequestVolumeThreshold: 5, //請求閾值(一個統計窗口10秒內請求數量) 熔斷器是否打開首先要滿足這個條件;這里的設置表示至少有5個請求才進行ErrorPercentThreshold錯誤百分比計算
}
type runFunc func() error
type Hystrix struct {
loadMap *sync.Map //儲存每個調用函數對應的 Hystrix
fallback string //降級信息
}
func NewHystrix(msg string) *Hystrix {
return &Hystrix{
loadMap: new(sync.Map),
fallback: msg,
}
}
func (s *Hystrix) Run(name string, run runFunc) error {
if _, ok := s.loadMap.Load(name); !ok {
hystrix.ConfigureCommand(name, config)
s.loadMap.Store(name, name)
}
//name 為執行的命令名稱
//run 我們要執行的函數
//fallback:run運行過程中發生錯誤時的回調方法
err := hystrix.Do(name, func() error {
return run()
}, func(err error) error {
//fmt.Println("運行 run 方法錯誤", err)
return errors.New(s.fallback)
})
if err != nil {
return err
}
return nil
}
添加Hystrix到調用客戶端
- 這里為了展示Hystrix的狀態去掉了一些日志信息
hy := utils.NewHystrix("調用錯誤服務降級")
cbs, _, _ := hystrix.GetCircuit("login")
for i := 0; i < 100; i++ {
time.Sleep(time.Millisecond * 100)
userAgent, err := client.UserAgentClient()
if err != nil {
t.Error(err)
return
}
err = hy.Run("login", func() error {
_, err := userAgent.Login(context.Background(), &pb.Login{
Account: "hwholiday",
Password: "123456",
})
if err != nil {
return err
}
//fmt.Println(ack.Token)
return nil
})
fmt.Println("熔斷器開啟狀態:", cbs.IsOpen(), "請求是否允許:", cbs.AllowRequest())
if err != nil {
t.Log(err)
}
}
去掉服務端的請求限制功能
func NewEndPointServer(svc Service, limit *rate.Limiter) EndPointServer {
var loginEndPoint endpoint.Endpoint
{
loginEndPoint = MakeLoginEndPoint(svc)
//loginEndPoint = NewGolangRateAllowMiddleware(limit)(loginEndPoint)
}
return EndPointServer{LoginEndPoint: loginEndPoint}
}
模擬服務器錯誤功能
if in.Account != "hwholiday" || in.Password != "123456" {
err = errors.New("用戶信息錯誤")
return
}
//模擬耗時
//rand.Seed(time.Now().UnixNano())
//sl := rand.Int31n(10-1) + 1
//time.Sleep(time.Duration(sl) * time.Millisecond * 100)
//模擬錯誤
if rand.Intn(10) > 3 {
err = errors.New("服務器運行錯誤")
return
}
ack = &pb.LoginAck{}
運行
-
運行 TestNewUserAgentClient 方法 (調用Login接口100次)
熔斷器開啟狀態: true 請求是否允許: false
熔斷器開啟狀態: true 請求是否允許: false
s.LoginEndPoint rpc error: code = Unknown desc = 服務器運行錯誤
s.LoginEndPoint rpc error: code = Unknown desc = 服務器運行錯誤
s.LoginEndPoint rpc error: code = Unknown desc = 服務器運行錯誤
s.LoginEndPoint rpc error: code = Unknown desc = 服務器運行錯誤 (previously: rpc error: code = Unknown desc = 服務器運行錯誤; rpc error: code = Unknown desc = 服務器運行錯誤)
熔斷器開啟狀態: true 請求是否允許: false
熔斷器開啟狀態: true 請求是否允許: false
熔斷器開啟狀態: true 請求是否允許: false
熔斷器開啟狀態: true 請求是否允許: false
熔斷器開啟狀態: true 請求是否允許: false
熔斷器開啟狀態: true 請求是否允許: false
熔斷器開啟狀態: true 請求是否允許: false
熔斷器開啟狀態: true 請求是否允許: false
熔斷器開啟狀態: true 請求是否允許: false
熔斷器開啟狀態: true 請求是否允許: false
熔斷器開啟狀態: false 請求是否允許: true
s.LoginEndPoint rpc error: code = Unknown desc = 服務器運行錯誤
熔斷器開啟狀態: false 請求是否允許: true
## 結語
+ 我們可以看到Hystrix的狀態從 打開 ->關閉 -> 打開
+ Hystrix的用法還有很多,這里只展示簡單的使用,更加高級的功能歡迎大家一起討論
+ 歡迎添加QQ一起討論
### [完整代碼地址](https://github.com/hwholiday/learning_tools/tree/master/go-kit/v8)
作者:hwholiday
鏈接:https://www.jianshu.com/p/15975197c2be
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。