ホームページ >バックエンド開発 >Golang >Go アプリのサーキット ブレーカー

Go アプリのサーキット ブレーカー

王林
王林オリジナル
2024-09-03 14:15:111064ブラウズ

今日、特にマイクロサービス環境で動作する場合、アプリケーションにいくつかの依存関係があることが一般的です。アプリがエラーを報告し、1 つの依存関係がダウンしていることが判明することは珍しくありません。

回復力を向上させるための良い習慣の 1 つは、正常に動作していないアプリとの通信をシャットダウンすることです。他の分野に目を向けると、故障が発生するとスイッチがオフになる回路ブレーカーの概念を電気工学から学びました。ブラジルでは、電力網が不安定になると自動的に停止するスイッチがすべての家にあります。

コンピューターサイエンスでは、サーキットブレーカーは中間状態も持つため、もう少し複雑です。以下の図は、その仕組みを詳しく説明しています:

Circuit Breaker in Go apps

簡単に言うと、考えられる状態は次のとおりです:

  • open: アプリ間の通信はありません。この状態に達すると、タイマーが開始され、依存関係が再確立されるようになります。タイマーが終了すると半開状態に移行します。
  • クローズ済み: アプリ間で通信が行われています。リクエストが失敗して完了するたびに、カウンターが更新されます。障害しきい値に達すると、回路がオープンに移行します。
  • 半開き:通常通りに仕事ができるようになるまでの治癒状態です。実行中に成功のしきい値に達すると、クローズに移行します。リクエストが失敗し続ける場合は、オープンに戻ります。

かなりクールですね?コンセプトをよりよく説明するには、コンセプトを作成してみてはいかがでしょうか?

まず、サービス A を構築しましょう。サービス A はすべてのリクエストを受信する責任を負います。つまり、メイン アプリが依存するサービスになります。簡略化するために、2 つのエンドポイントを公開します。1 つは常に 200 で応答する /success で、もう 1 つは常に 500 で応答する /failure です。

package main

import (
    "fmt"
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/success", func(w http.ResponseWriter, r *http.Request) { 
    w.WriteHeader(http.StatusOK) })
    http.HandleFunc("/failure", func(w http.ResponseWriter, r *http.Request) { 
    w.WriteHeader(http.StatusInternalServerError) })

    fmt.Println("Server is running at http://localhost:8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

サービス B はサービス A を呼び出す責任を負い、サーキット ブレーカーを構築します。 Go コミュニティには、パターンを実装した lib gobreak がすでにあります。まず最初に、ブレーカーのプロパティを定義します。

var st gobreaker.Settings
st.Name = "Circuit Breaker PoC"
st.Timeout = time.Second * 5
st.MaxRequests = 2
st.ReadyToTrip = func(counts gobreaker.Counts) bool {
    return counts.ConsecutiveFailures >= 1
}

このライブラリではさらに多くのプロパティをカスタマイズできますが、ここでは次の 3 つのみに焦点を当てます。

  • タイムアウト: オープン状態になる時間。この例では、5 秒を選択します。
  • MaxRequests: クローズされるまでに成功したリクエストの数。この例では、2 つのリクエストを決定しました。
  • ReadyToTrip: クローズからオープンに移行する条件を定義します。単純化すると、失敗は 1 回で十分です。

ここで、ブレーカーを初期化してリクエストを送信します。

cb := gobreaker.NewCircuitBreaker[int](st)

url := "http://localhost:8080/success"
cb.Execute(func() (int, error) { return Get(url) })
fmt.Println("Circuit Breaker state:", cb.State()) // closed!

url = "http://localhost:8080/failure"
cb.Execute(func() (int, error) { return Get(url) })
fmt.Println("Circuit Breaker state:", cb.State()) // open!

time.Sleep(time.Second * 6)
url = "http://localhost:8080/success"
cb.Execute(func() (int, error) { return Get(url) })
fmt.Println("Circuit Breaker state:", cb.State()) // half-open!

url = "http://localhost:8080/success"
cb.Execute(func() (int, error) { return Get(url) })
fmt.Println("Circuit Breaker state:", cb.State()) // closed!

gobreak が関数のラッパーのように動作することがわかります。関数がエラーを返した場合は失敗カウンターが増加し、そうでない場合は成功カウンターが増加します。その関数を定義しましょう:

func Get(url string) (int, error) {
    r, _ := http.Get(url)

    if r.StatusCode != http.StatusOK {
        return r.StatusCode, fmt.Errorf("failed to get %s", url)
    }

    return r.StatusCode, nil
}

これで、サーキットブレーカーを備えた Go アプリを作成できるようになりました。このパターンを使用すると、依存関係による障害に対するアプリの耐性が高まり、アプリの復元力を高めることができます。また、このライブラリを使用すると複雑さのほとんどが解消され、日常のアプリにこのパターンを採用しやすくなりました。この概念実証のコードを確認したい場合は、ここで確認してください。

他の回復力パターンについてまだ興味がある場合は、Elton Minetto がそれに関する素晴らしいブログ投稿を公開しています!

この記事や他の投稿は私の個人ブログでもご覧いただけます。このブログ投稿についてのご意見と 1 つの質問をコメント欄でお聞かせください。回路ブレーカーを使用したことがありますか?

以上がGo アプリのサーキット ブレーカーの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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