小編給大家分享一下hystrix-go怎么用,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

開篇
這周在看內部一個熔斷限流包時,發現它是基于一個開源項目hystrix-go 實現了,因此有了這篇文章。
Hystrix 是由Netflex 開發的一款開源組件,提供了基礎的熔斷功能。Hystrix 將降級的策略封裝在Command 中,提供了run 和fallback 兩個方法,前者表示正常的邏輯,比如微服務之間的調用……,如果發生了故障,再執行fallback方法返回結果,我們可以把它理解成保底操作。如果正常邏輯在短時間內頻繁發生故障,那么可能會觸發短路,也就是之后的請求不再執行run,而是直接執行 fallback。更多關于Hystrix 的信息可以查看https://github.com/Netflix/Hystrix,而hystrix-go 則是用go 實現的hystrix 版,更確切的說,是簡化版。只是上一次更新還是 2018年 的一次pr,也就畢業了?
為什么需要這些工具?
比如一個微服務化的產品線上,每一個服務都專注于自己的業務,并對外提供相應的服務接口,或者依賴于外部服務的某個邏輯接口,就像下面這樣。
假設我們當前是服務A,有部分邏輯依賴于服務C,服務C 又依賴于服務E,當前微服務之間進行rpc或者http通信,假設此時服務C 調用 服務E 失敗,比如由于網絡波動導致超時或者服務E由于過載,系統E 已經down掉了。
調用失敗,一般會有失敗重試等機制。但是再想想,假設服務E已然不可用的情況下,此時新的調用不斷產生,同時伴隨著調用等待和失敗重試,會導致 服務C對服務E的調用而產生大量的積壓,慢慢會耗盡服務C的資源,進而導致服務C也down掉,這樣惡性循環下,會影響到整個微服務體系,產生雪崩效應。
雖然導致雪崩的發生不僅僅這一種,但是我們需要采取一定的措施,來保證不讓這個噩夢發生。而hystrix-go就很好的提供了 熔斷和降級的措施。它的主要思想在于,設置一些閥值,比如較大并發數(當并發數大于設置的并發數,攔截),錯誤率百分比(請求數量大于等于設置 的閥值,并且錯誤率達到設置的百分比時,觸發熔斷)以及熔斷嘗試恢復時間等 。
hystrix-go 的使用非常簡單,你可以調用它的Go 或者Do方法,只是Go 方法是異步的方式。而Do 方法是同步方式。我們從一個簡單的例子開啟。
_ = hystrix.Do("wuqq", func() error {
// talk to other services
_, err := http.Get("https://www.baidu.com/")
if err != nil {
fmt.Println("get error:%v",err)
return err }
return nil
}, func(err error) error {
fmt.Printf("handle error:%v\n", err)
return nil
})Do 函數需要三個參數,第一個參數commmand 名稱,你可以把每個名稱當成一個獨立當服務,第二個參數是處理正常的邏輯,比如http 調用服務,返回參數是err。如果處理|調用失敗,那么就執行第三個參數邏輯, 我們稱為保底操作。由于服務錯誤率過高導致熔斷器開啟,那么之后的請求也直接回調此函數。
既然熔斷器是按照配置的規則而進行是否開啟的操作,那么我們當然可以設置我們想要的值。
hystrix.ConfigureCommand("wuqq", hystrix.CommandConfig{
Timeout: int(3 * time.Second),
MaxConcurrentRequests: 10,
SleepWindow: 5000,
RequestVolumeThreshold: 10,
ErrorPercentThreshold: 30,
})
_ = hystrix.Do("wuqq", func() error {
// talk to other services
_, err := http.Get("https://www.baidu.com/")
if err != nil {
fmt.Println("get error:%v",err)
return err }
return nil
}, func(err error) error {
fmt.Printf("handle error:%v\n", err)
return nil
})稍微解釋一下上面配置的值含義:
Timeout: 執行command 的超時時間。
MaxConcurrentRequests:command 的較大并發量 。
SleepWindow:當熔斷器被打開后,SleepWindow 的時間就是控制過多久后去嘗試服務是否可用了。
RequestVolumeThreshold: 一個統計窗口10秒內請求數量。達到這個請求數量后才去判斷是否要開啟熔斷
ErrorPercentThreshold:錯誤百分比,請求數量大于等于RequestVolumeThreshold并且錯誤率到達這個百分比后就會啟動熔斷
當然你不設置的話,那么自動走的默認值。
我們再來看一個簡單的例子:
package mainimport (
"fmt"
"github.com/afex/hystrix-go/hystrix" "net/http" "time")type Handle struct{}func (h *Handle) ServeHTTP(r http.ResponseWriter, request *http.Request) {
h.Common(r, request)}func (h *Handle) Common(r http.ResponseWriter, request *http.Request) {
hystrix.ConfigureCommand("mycommand", hystrix.CommandConfig{
Timeout: int(3 * time.Second),
MaxConcurrentRequests: 10,
SleepWindow: 5000,
RequestVolumeThreshold: 20,
ErrorPercentThreshold: 30,
})
msg := "success"
_ = hystrix.Do("mycommand", func() error {
_, err := http.Get("https://www.baidu.com")
if err != nil {
fmt.Printf("請求失敗:%v", err)
return err }
return nil
}, func(err error) error {
fmt.Printf("handle error:%v\n", err)
msg = "error"
return nil
})
r.Write([]byte(msg))}func main() {
http.ListenAndServe(":8090", &Handle{})}我們開啟了一個http 服務,監聽端口號8090,所有請求的處理邏輯都在 Common 方法中,在這個方法中,我們主要是發起一次http請求,請求成功響應success,如果失敗,響應失敗原因。
我們再寫另一個簡單程序,并發11 次的請求8090 端口。
package mainimport (
"fmt"
"io/ioutil"
"net/http"
"sync"
"time")var client *http.Clientfunc init() {
tr := &http.Transport{
MaxIdleConns: 100,
IdleConnTimeout: 1 * time.Second,
}
client = &http.Client{Transport: tr}}type info struct {
Data interface{} `json:"data"`}func main() {
var wg sync.WaitGroup for i := 0; i < 11; i++ {
wg.Add(1)
go func(int2 int) {
defer wg.Done()
req, err := http.NewRequest("GET", "http://localhost:8090", nil)
if err != nil {
fmt.Printf("初始化http客戶端處錯誤:%v", err)
return
}
resp, err := client.Do(req)
if err != nil {
fmt.Printf("初始化http客戶端處錯誤:%v", err)
return
}
defer resp.Body.Close()
nByte, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("讀取http數據失敗:%v", err)
return
}
fmt.Printf("接收到到值:%v\n", string(nByte))
}(i)
}
wg.Wait()
fmt.Printf("請求完畢\n")}由于我們配置MaxConcurrentRequests 為10,那么意味著還有個 g 請求會失敗:
和我們想的一樣。
接著我們把網絡斷開,并發請求改成10次。再次運行程序并發請求8090 端口,此時由于網絡已關閉,導致請求百度失敗:
接著繼續請求:
熔斷器已開啟,上面我們配置的RequestVolumeThreshold 和ErrorPercentThreshold 生效。
然后我們把網連上,五秒后 (SleepWindow的值)繼續并發調用,當前熔斷器處于半開的狀態,此時請求允許調用依賴,如果成功則關閉,失敗則繼續開啟熔斷器。
可以看到,有一個成功了,那么此時熔斷器已關閉,接下來繼續運行函數并發調用:
可以看到,10個都已經是正常成功的狀態了。
那么問題來了,為什么最上面的圖只有一個是成功的?5秒已經過了,并且當前網絡正常,應該是10個請求都成功,但是我們看到的只有一個是成功狀態。通過源碼我們可以找到答案:
具體邏輯在判斷當前請求是否可以調用依賴
if !cmd.circuit.AllowRequest() {
......
return
}func (circuit *CircuitBreaker) AllowRequest() bool {
return !circuit.IsOpen() || circuit.allowSingleTest()}func (circuit *CircuitBreaker) allowSingleTest() bool {
circuit.mutex.RLock()
defer circuit.mutex.RUnlock()
now := time.Now().UnixNano()
openedOrLastTestedTime := atomic.LoadInt64(&circuit.openedOrLastTestedTime)
if circuit.open && now > openedOrLastTestedTime+getSettings(circuit.Name).SleepWindow.Nanoseconds() {
/
swapped := atomic.CompareAndSwapInt64(&circuit.openedOrLastTestedTime, openedOrLastTestedTime, now) //這一句才是關鍵
if swapped {
log.Printf("hystrix-go: allowing single test to possibly close circuit %v", circuit.Name)
}
return swapped }
return false}這段代碼首先判斷了熔斷器是否開啟,并且當前時間大于 上一次開啟熔斷器的時間+SleepWindow 的時間,如果條件都符合的話,更新此熔斷器新的openedOrLastTestedTime ,是通過 CompareAndSwapInt64 原子操作完成的,意外著必然只會有一個成功。
此時熔斷器還是半開的狀態,接著如果能拿到令牌,執行run 函數(也就是Do傳入的第二個簡單封裝后的函數),發起http 請求,如果成功,上報成功狀態,關閉熔斷器。如果失敗,那么熔斷器依舊開啟。

看完了這篇文章,相信你對“hystrix-go怎么用”有了一定的了解,如果想了解更多相關知識,歡迎關注創新互聯行業資訊頻道,感謝各位的閱讀!
當前標題:hystrix-go怎么用-創新互聯
轉載源于:http://www.yijiale78.com/article10/dgsgdo.html
成都網站建設公司_創新互聯,為您提供移動網站建設、小程序開發、全網營銷推廣、微信小程序、Google、用戶體驗
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯