ホームページ バックエンド開発 Golang hystrix-goの使い方と原理を詳しく解説

hystrix-goの使い方と原理を詳しく解説

Dec 29, 2020 am 09:25 AM
go golang

次のコラム golang チュートリアルでは、bash コマンド解析を実行するための bash 関数をカプセル化する golang について紹介します。

hystrix-goの使い方と原理を詳しく解説

冒頭

今週、内部回路ブレーカーの電流制限パッケージを調べていたところ、それがオープンソース プロジェクトに基づいていることがわかりましたhystrix-go それが実現したので、この記事を作成します。

Hystrix

Hystrix は、Netflex によって開発されたオープン ソース コンポーネントであり、基本的な融合機能を提供します。 Hystrix は、ダウングレード戦略を Command にカプセル化し、runfallback という 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 请求,如果成功,上报成功状态,关闭熔断器。如果失败,那么熔断器依旧开启。

hystrix-goの使い方と原理を詳しく解説

以上就是大体的流程讲解,下一篇文章将解读核心源码以及进一步当思考。

更多相关技术文章,请访问go语言教程栏目!                                                  

以上がhystrix-goの使い方と原理を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

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

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

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

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

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

Golang を使用してファイルを安全に読み書きするにはどうすればよいですか? Golang を使用してファイルを安全に読み書きするにはどうすればよいですか? Jun 06, 2024 pm 05:14 PM

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

Golang データベース接続用の接続プールを構成するにはどうすればよいですか? Golang データベース接続用の接続プールを構成するにはどうすればよいですか? Jun 06, 2024 am 11:21 AM

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

Golang 単体テストのアサーションに gomega を使用するにはどうすればよいですか? Golang 単体テストのアサーションに gomega を使用するにはどうすればよいですか? Jun 05, 2024 pm 10:48 PM

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 フレームワーク: 内部アーキテクチャと外部機能の比較 Jun 06, 2024 pm 12:37 PM

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

GolangでJSONデータをデータベースに保存するにはどうすればよいですか? GolangでJSONデータをデータベースに保存するにはどうすればよいですか? Jun 06, 2024 am 11:24 AM

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

Golang フレームワークでのエラー処理のベスト プラクティスは何ですか? Golang フレームワークでのエラー処理のベスト プラクティスは何ですか? Jun 05, 2024 pm 10:39 PM

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

golang フレームワークでよくあるセキュリティ問題を解決するにはどうすればよいですか? golang フレームワークでよくあるセキュリティ問題を解決するにはどうすればよいですか? Jun 05, 2024 pm 10:38 PM

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

Golang の正規表現に一致する最初の部分文字列を見つけるにはどうすればよいですか? Golang の正規表現に一致する最初の部分文字列を見つけるにはどうすればよいですか? Jun 06, 2024 am 10:51 AM

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

See all articles