次のコラム golang チュートリアルでは、bash コマンド解析を実行するための bash 関数をカプセル化する golang について紹介します。
冒頭
今週、内部回路ブレーカーの電流制限パッケージを調べていたところ、それがオープンソース プロジェクトに基づいていることがわかりましたhystrix-go
それが実現したので、この記事を作成します。
Hystrix
は、Netflex
によって開発されたオープン ソース コンポーネントであり、基本的な融合機能を提供します。 Hystrix
は、ダウングレード戦略を Command
にカプセル化し、run
と fallback
という 2 つのメソッドを提供します。前者は、間の呼び出しなどの通常のロジックを表します。 microservices... 障害が発生した場合、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 がダウンしました。
呼び出しが失敗した場合、通常は失敗時の再試行などのメカニズムがあります。しかし、もう一度考えてみてください。サービス E がすでに利用できなくなっていると仮定すると、この時点でも新しいコールが生成され続け、コール待機や再試行の失敗が伴い、サービス C からサービス E へのコールの大量のバックログが発生することになります。サービス C のリソースが枯渇すると、サービス C もダウンしてしまい、この悪循環はマイクロサービス システム全体に影響を及ぼし、雪崩現象を引き起こします。
雪崩の原因はこれだけではありませんが、この悪夢が起こらないようにするためには、何らかの対策を講じる必要があります。 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
この関数には 3 つのパラメータが必要です。最初のパラメータは commmand
名前です。各名前を独立したサービスとして扱うことができます。2 番目のパラメータはプロセスの通常のロジックですサービスを呼び出す http
など、戻りパラメータは err
です。 | 処理呼び出しが失敗した場合、保証された操作と呼ばれる 3 番目のパラメーター ロジックが実行されます。サービス エラー率が高すぎてヒューズが開いているため、後続のリクエストもこの関数を直接コールバックします。
ヒューズは設定されたルールに従ってオンまたはオフになるため、もちろん必要な値を設定できます。
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 })
上記で設定した値の意味を簡単に説明しましょう:
command
的超时时间。command
的最大并发量 。SleepWindow
的时间就是控制过多久后去尝试服务是否可用了。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 <p>由于我们配置 <code>MaxConcurrentRequests</code> 为10,那么意味着还有个 g 请求会失败:<br><img src="https://img.php.cn/upload/article/000/000/020/a47bae3dcfa1730bb3b1136eddb4f59b-5.png" alt=""><br>和我们想的一样。</p><p>接着我们把网络断开,并发请求改成10次。再次运行程序并发请求 <code>8090</code> 端口,此时由于网络已关闭,导致请求百度失败:<br><img src="https://img.php.cn/upload/article/000/000/020/a47bae3dcfa1730bb3b1136eddb4f59b-6.png" alt=""><br>接着继续请求:<br><img src="https://img.php.cn/upload/article/000/000/020/a47bae3dcfa1730bb3b1136eddb4f59b-7.png" alt=""><br>熔断器已开启,上面我们配置的<code>RequestVolumeThreshold</code> 和 <code>ErrorPercentThreshold</code> 生效。</p><p>然后我们把网连上,五秒后 (<code>SleepWindow</code>的值)继续并发调用,当前熔断器处于半开的状态,此时请求允许调用依赖,如果成功则关闭,失败则继续开启熔断器。<br><img src="https://img.php.cn/upload/article/000/000/020/a47bae3dcfa1730bb3b1136eddb4f59b-8.png" alt=""><br>可以看到,有一个成功了,那么此时熔断器已关闭,接下来继续运行函数并发调用:<br><img src="https://img.php.cn/upload/article/000/000/020/24be5795ca6d697af3d1d7ffdfdafc03-9.png" alt=""><br>可以看到,10个都已经是正常成功的状态了。</p><p>那么问题来了,为什么最上面的图只有一个是成功的?5秒已经过了,并且当前网络正常,应该是10个请求都成功,但是我们看到的只有一个是成功状态。通过源码我们可以找到答案:<br>具体逻辑在判断当前请求是否可以调用依赖</p><pre class="brush:php;toolbar:false">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
请求,如果成功,上报成功状态,关闭熔断器。如果失败,那么熔断器依旧开启。
以上就是大体的流程讲解,下一篇文章将解读核心源码以及进一步当思考。
更多相关技术文章,请访问go语言教程栏目!
以上がhystrix-goの使い方と原理を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。