hystrix-goの使い方と原理を詳しく解説
次のコラム golang チュートリアルでは、bash コマンド解析を実行するための bash 関数をカプセル化する golang について紹介します。
冒頭
今週、内部回路ブレーカーの電流制限パッケージを調べていたところ、それがオープンソース プロジェクトに基づいていることがわかりましたhystrix-go
それが実現したので、この記事を作成します。
Hystrix
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 })
上記で設定した値の意味を簡単に説明しましょう:
- 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 <p>由于我们配置 <code>MaxConcurrentRequests</code> 为10,那么意味着还有个 g 请求会失败:<br><img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/020/a47bae3dcfa1730bb3b1136eddb4f59b-5.png" class="lazy" alt=""><br>和我们想的一样。</p><p>接着我们把网络断开,并发请求改成10次。再次运行程序并发请求 <code>8090</code> 端口,此时由于网络已关闭,导致请求百度失败:<br><img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/020/a47bae3dcfa1730bb3b1136eddb4f59b-6.png" class="lazy" alt=""><br>接着继续请求:<br><img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/020/a47bae3dcfa1730bb3b1136eddb4f59b-7.png" class="lazy" alt=""><br>熔断器已开启,上面我们配置的<code>RequestVolumeThreshold</code> 和 <code>ErrorPercentThreshold</code> 生效。</p><p>然后我们把网连上,五秒后 (<code>SleepWindow</code>的值)继续并发调用,当前熔断器处于半开的状态,此时请求允许调用依赖,如果成功则关闭,失败则继续开启熔断器。<br><img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/020/a47bae3dcfa1730bb3b1136eddb4f59b-8.png" class="lazy" alt=""><br>可以看到,有一个成功了,那么此时熔断器已关闭,接下来继续运行函数并发调用:<br><img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/020/24be5795ca6d697af3d1d7ffdfdafc03-9.png" class="lazy" 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 サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









Go ではファイルを安全に読み書きすることが重要です。ガイドラインには以下が含まれます。 ファイル権限の確認 遅延を使用してファイルを閉じる ファイル パスの検証 コンテキスト タイムアウトの使用 これらのガイドラインに従うことで、データのセキュリティとアプリケーションの堅牢性が確保されます。

Go データベース接続の接続プーリングを構成するにはどうすればよいですか?データベース接続を作成するには、database/sql パッケージの DB タイプを使用します。同時接続の最大数を制御するには、MaxOpenConns を設定します。アイドル状態の接続の最大数を設定するには、ConnMaxLifetime を設定します。

Golang 単体テストでアサーションに Gomega を使用する方法 Golang 単体テストでは、Gomega は、開発者がテスト結果を簡単に検証できるように、豊富なアサーション メソッドを提供する人気のある強力なアサーション ライブラリです。 Gomegagoget-agithub.com/onsi/gomega をインストールする アサーションに Gomega を使用する アサーションに Gomega を使用する一般的な例をいくつか示します。 1. 等価アサーション import "github.com/onsi/gomega" funcTest_MyFunction(t*testing.T){

GoLang フレームワークと Go フレームワークの違いは、内部アーキテクチャと外部機能に反映されています。 GoLang フレームワークは Go 標準ライブラリに基づいてその機能を拡張していますが、Go フレームワークは特定の目的を達成するための独立したライブラリで構成されています。 GoLang フレームワークはより柔軟であり、Go フレームワークは使いやすいです。 GoLang フレームワークはパフォーマンスの点でわずかに優れており、Go フレームワークはよりスケーラブルです。ケース: gin-gonic (Go フレームワーク) は REST API の構築に使用され、Echo (GoLang フレームワーク) は Web アプリケーションの構築に使用されます。

JSON データは、gjson ライブラリまたは json.Unmarshal 関数を使用して MySQL データベースに保存できます。 gjson ライブラリは、JSON フィールドを解析するための便利なメソッドを提供します。json.Unmarshal 関数には、JSON データをアンマーシャリングするためのターゲット型ポインターが必要です。どちらの方法でも、SQL ステートメントを準備し、データをデータベースに永続化するために挿入操作を実行する必要があります。

ベスト プラクティス: 明確に定義されたエラー タイプ (エラー パッケージ) を使用してカスタム エラーを作成する 詳細を提供する エラーを適切にログに記録する エラーを正しく伝播し、非表示または抑制しないようにする コンテキストを追加するために必要に応じてエラーをラップする

Go フレームワークで一般的なセキュリティ問題に対処する方法 Web 開発で Go フレームワークが広く採用されているため、そのセキュリティを確保することが重要です。以下は、一般的なセキュリティ問題を解決するための実践的なガイドであり、サンプル コードも含まれています。 1. SQL インジェクション SQL インジェクション攻撃を防ぐには、プリペアド ステートメントまたはパラメータ化されたクエリを使用します。例: constquery="SELECT*FROMusersWHEREusername=?"stmt,err:=db.Prepare(query)iferr!=nil{//Handleerror}err=stmt.QueryR

FindStringSubmatch 関数は、正規表現に一致する最初の部分文字列を検索します。この関数は、最初の要素が一致した文字列全体で、後続の要素が個々の部分文字列である、一致する部分文字列を含むスライスを返します。コード例: regexp.FindStringSubmatch(text,pattern) は、一致する部分文字列のスライスを返します。実際のケース: 電子メール アドレスのドメイン名を照合するために使用できます。たとえば、email:="user@example.com", pattern:=@([^\s]+)$ を使用してドメイン名を照合します。 [1]。
