ホームページ >バックエンド開発 >Golang >電流制限と溶断とは何ですか? Sentinel 電流制限ヒューズの劣化の詳細な説明

電流制限と溶断とは何ですか? Sentinel 電流制限ヒューズの劣化の詳細な説明

藏色散人
藏色散人転載
2022-11-13 16:37:402816ブラウズ

この記事は、Sentinel の電流制限とサーキット ブレーカーのダウングレードに関する golang チュートリアル コラムによって紹介されており、その内容には、電流制限とサーキット ブレーカーの概要、および alibaba オープン ソース Sentinel、インストールが含まれています、そして実践的な紹介ですので、困っている友達のお役に立てれば幸いです。

電流制限と溶断とは何ですか? Sentinel 電流制限ヒューズの劣化の詳細な説明

#Sentinel 電流制限サーキット ブレーカーのダウングレード

電流制限/サーキット ブレーカー/ダウングレードとは

現在の制限: 当社が取得したシステムでは、その日に大量のトラフィックが突然入った場合、当社のサービスは同時に 2,000 のリクエストしか処理できません。突然 5,000 のリクエストが来ます。これは

です。サーバーへの負荷がひどくないですか? これは直接サーバーのシャットダウンやクラッシュを引き起こし、本来の 2K の処理量を処理できなくなる可能性があります。このとき、電流を制限する必要があります。電流制限機能訪問数がサーバー上の最高レベルに達した場合、サーバーを直接ハングアップするよりも、冗長なリクエスト

を処理しない方がはるかに優れています。たとえば、ダブルイレブン中に注文しようとすると、「リクエストがビジーです。後でもう一度お試しください。」というようなメッセージが表示されます。

ヒューズ: サーキットブレーカーは皆さんご存知かと思いますが、交通の通過を阻止するスイッチに相当します。たとえば、電流が高すぎるとヒューズが飛び、コンポーネントへの損傷を防ぎます。

サービス サーキット ブレーカーとは、プロキシとしてサーキット ブレーカーを介してサービスにアクセスする呼び出し元を指します。サーキット ブレーカーは、サービスから返される成功と失敗のステータスを監視し続けます。

障害が発生したとき設定されたしきい値を超えています サーキット ブレーカーが開いていると、リクエストは実際にはサービスにアクセスできません。

#使用シナリオ

サービスが失敗するかアップグレードされる場合は、クライアントをすぐに失敗させます

Failure 処理ロジックの定義は簡単です

  • 応答には長い時間がかかり、クライアントが大量の再試行を防ぐためにクライアントによって設定された読み取りタイムアウトは比較的長くなります。

  • * ダウングレード*: サービスのダウングレードは、システム全体の負荷状態に基づいて行われます。負荷が比較的高い状況によっては、 、特定の機能を防ぐため (ビジネス

  • シナリオ) 過負荷または応答遅延が発生した場合、一部の非コア インターフェイスとデータに対するリクエストは内部で一時的に破棄され、
  • 用意されたフォールバック エラー処理情報が直接返されます。このようにして、損失の多いサービスを提供しますが、システム全体の安定性と可用性が保証されます。

Sentinel とは

Sentinel は Alibaba のオープン ソース プロジェクトであり、フロー制御、サーキット ブレーカーの劣化、システム負荷保護などの複数の側面を提供して、サービスの安定性、セックス。

公式 Web サイト: github.com/alibaba/Sentinel/wiki

Sentinel は 2012 年に Alibaba で誕生し、その主な目的はトラフィック制御です。 2013 年から 2017 年にかけて、Sentinel は急速に発展し、すべての Alibaba マイクロサービスの基本コンポーネントになりました。 6,000 を超えるアプリケーションで使用されており、ほぼすべての主要な電子商取引シナリオをカバーしています。 2018 年に、Sentinel はオープンソース プロジェクトに進化しました。 2020 年に Sentinel Golang がリリースされました。

機能:豊富なアプリケーション シナリオ: Sentinel は、フラッシュ セール (つまり

バースト トラフィックなど) など、過去 10 年間にアリババのダブル イレブン プロモーション トラフィックの中核となるシナリオを担当してきました。 (システム容量が耐えられる範囲内での制御)、メッセージのピークシェービングとバレーフィリング、クラスタートラフィック制御、ダウンストリームの利用できないアプリケーションのリアルタイム融合など。

完全なリアルタイム監視: Sentinel はリアルタイム監視機能も提供します。コンソールでは、アプリケーションに接続されている 1 台のマシンの第 2 レベルのデータや、マシン数が 500 未満のクラスターの運用ステータスの概要も確認できます。

* 幅広いエコロジー*

Sentinel の歴史

2012 年に Sentinel が誕生しました。その主な機能は入口の流れです。コントロール 。

2013 年から 2017 年にかけて、Sentinel はアリババ グループ内で急速に発展し、すべてのコア シナリオをカバーする基本テクノロジー モジュールになりました。このように Sentinel は、トラフィック統合のシナリオと運用実践を多数蓄積してきました。

2018 年に Sentinel はオープンソース化され、進化し続けています。

  • 2019 年、Sentinel は多言語拡張の方向性を模索し続け、C ネイティブ バージョンをリリースし、同時にサービス メッシュ シナリオ向けの Envoy クラスター フロー制御サポートも開始しました。 Service Mesh アーキテクチャの問題を解決する 多言語の電流制限の問題を解決する

  • 2020 年に Sentinel Go バージョンがリリースされ、クラウド ネイティブに向けて進化し続けています。

  • 2021 年、Sentinel は 2.0 クラウドネイティブの高可用性デシジョン センター コンポーネントに向けて進化しており、同時に Sentinel Rust ネイティブ バージョンがリリースされます。同時に、Rust コミュニティで Envoy WASM 拡張機能や eBPF 拡張機能などのシナリオも検討しました。

  • 2022 年に、Sentinel ブランドはトラフィック管理にアップグレードされ、トラフィック ルーティング/スケジューリング、トラフィック ダイイング、フロー制御の低下、過負荷保護/インスタンスの削除などをカバーします。コミュニティは、トラフィック管理の関連標準を開発する予定です。OpenSergo 標準に抽出された Sentinel は、トラフィック管理標準として実装されます。

  • Sentinel-go のインストール
  • Sentinel-go オープンソース アドレス: https://github.com/alibaba/sentinel-golang

    公式 Web サイトのドキュメント

    インストール:github.com/alibaba/sentinel-golang/api を入手してください

    電流制限の実践を進めてください

    qps 現在の制限

    package main
    
    import (
        "fmt"
        "log"
    
        sentinel "github.com/alibaba/sentinel-golang/api"
        "github.com/alibaba/sentinel-golang/core/base"
        "github.com/alibaba/sentinel-golang/core/flow"
    )
    
    func main() {
        //基于sentinel的qps限流
        //必须初始化
        err := sentinel.InitDefault()
        if err != nil {
            log.Fatalf("Unexpected error: %+v", err)
        }
    
        //配置限流规则:1秒内通过10次
        _, err = flow.LoadRules([]*flow.Rule{
            {
                Resource:               "some_test",
                TokenCalculateStrategy: flow.Direct,
                ControlBehavior:        flow.Reject, //超过直接拒绝
                Threshold:              10,          //请求次数
                StatIntervalInMs:       1000,        //允许时间内
            },
        })
    
        if err != nil {
            log.Fatalf("Unexpected error: %+v", err)
            return
        }
    
        for i := 0; i < 12; i++ {
            e, b := sentinel.Entry("some_test", sentinel.WithTrafficType(base.Inbound))
            if b != nil {
                fmt.Println("限流了")
            } else {
                fmt.Println("检查通过")
                e.Exit()
            }
        }
    }

    印刷結果:

    检查通过
    检查通过
    检查通过
    检查通过
    检查通过
    检查通过
    检查通过
    检查通过
    检查通过
    检查通过
    限流了
    限流了

    Thrnottting

    package main
    
    import (
        "fmt"
        "log"
        "time"
    
        sentinel "github.com/alibaba/sentinel-golang/api"
        "github.com/alibaba/sentinel-golang/core/base"
        "github.com/alibaba/sentinel-golang/core/flow"
    )
    
    func main() {
        //基于sentinel的qps限流
        //必须初始化
        err := sentinel.InitDefault()
        if err != nil {
            log.Fatalf("Unexpected error: %+v", err)
        }
    
        //配置限流规则
        _, err = flow.LoadRules([]*flow.Rule{
            {
                Resource:               "some_test",
                TokenCalculateStrategy: flow.Direct,
                ControlBehavior:        flow.Throttling, //匀速通过
                Threshold:              10,              //请求次数
                StatIntervalInMs:       1000,            //允许时间内
            },
        })
    
        if err != nil {
            log.Fatalf("Unexpected error: %+v", err)
            return
        }
    
        for i := 0; i < 12; i++ {
            e, b := sentinel.Entry("some_test", sentinel.WithTrafficType(base.Inbound))
            if b != nil {
                fmt.Println("限流了")
            } else {
                fmt.Println("检查通过")
                e.Exit()
            }
            time.Sleep(time.Millisecond * 100)
        }
    }
    检查通过
    检查通过
    检查通过
    检查通过
    检查通过
    检查通过
    检查通过
    检查通过
    检查通过
    检查通过
    检查通过
    检查通过

    Warrm_up

    package main
    
    import (
        "fmt"
        "log"
        "math/rand"
        "time"
    
        sentinel "github.com/alibaba/sentinel-golang/api"
        "github.com/alibaba/sentinel-golang/core/base"
        "github.com/alibaba/sentinel-golang/core/flow"
    )
    
    func main() {
        //先初始化sentinel
        err := sentinel.InitDefault()
        if err != nil {
            log.Fatalf("初始化sentinel 异常: %v", err)
        }
    
        var globalTotal int
        var passTotal int
        var blockTotal int
        ch := make(chan struct{})
    
        //配置限流规则
        _, err = flow.LoadRules([]*flow.Rule{
            {
                Resource:               "some-test",
                TokenCalculateStrategy: flow.WarmUp, //冷启动策略
                ControlBehavior:        flow.Reject, //直接拒绝
                Threshold:              1000,
                WarmUpPeriodSec:        30,
            },
        })
    
        if err != nil {
            log.Fatalf("加载规则失败: %v", err)
        }
    
        //我会在每一秒统计一次,这一秒只能 你通过了多少,总共有多少, block了多少, 每一秒会产生很多的block
        for i := 0; i < 100; i++ {
            go func() {
                for {
                    globalTotal++
                    e, b := sentinel.Entry("some-test", sentinel.WithTrafficType(base.Inbound))
                    if b != nil {
                        //fmt.Println("限流了")
                        blockTotal++
                        time.Sleep(time.Duration(rand.Uint64()%10) * time.Millisecond)
                    } else {
                        passTotal++
                        time.Sleep(time.Duration(rand.Uint64()%10) * time.Millisecond)
                        e.Exit()
                    }
                }
            }()
        }
    
        go func() {
            var oldTotal int //过去1s总共有多少个
            var oldPass int  //过去1s总共pass多少个
            var oldBlock int //过去1s总共block多少个
            for {
                oneSecondTotal := globalTotal - oldTotal
                oldTotal = globalTotal
    
                oneSecondPass := passTotal - oldPass
                oldPass = passTotal
    
                oneSecondBlock := blockTotal - oldBlock
                oldBlock = blockTotal
    
                time.Sleep(time.Second)
                fmt.Printf("total:%d, pass:%d, block:%d\n", oneSecondTotal, oneSecondPass, oneSecondBlock)
            }
        }()
    
        <-ch
    }

    印刷結果:徐々に 1k に到達し、1k の位置で上下に変動します

    total:11, pass:9, block:0
    total:21966, pass:488, block:21420
    total:21793, pass:339, block:21414
    total:21699, pass:390, block:21255
    total:21104, pass:393, block:20654
    total:21363, pass:453, block:20831
    total:21619, pass:491, block:21052
    total:21986, pass:533, block:21415
    total:21789, pass:594, block:21123
    total:21561, pass:685, block:20820
    total:21663, pass:873, block:20717
    total:20904, pass:988, block:19831
    total:21500, pass:996, block:20423
    total:21769, pass:1014, block:20682
    total:20893, pass:1019, block:19837
    total:21561, pass:973, block:20524
    total:21601, pass:1014, block:20517
    total:21475, pass:993, block:20420
    total:21457, pass:983, block:20418
    total:21397, pass:1024, block:20320
    total:21690, pass:996, block:20641
    total:21526, pass:991, block:20457
    total:21779, pass:1036, block:20677

    サーキット ブレーカーの練習を行ってください

    ここでは間違った数値が紹介されています。サーキット ブレーカーのメカニズムの詳細をご覧ください

    error_count
    package main
    
    import (
        "errors"
        "fmt"
        "log"
        "math/rand"
        "time"
    
        sentinel "github.com/alibaba/sentinel-golang/api"
        "github.com/alibaba/sentinel-golang/core/circuitbreaker"
        "github.com/alibaba/sentinel-golang/core/config"
        "github.com/alibaba/sentinel-golang/logging"
        "github.com/alibaba/sentinel-golang/util"
    )
    
    type stateChangeTestListener struct {
    }
    
    func (s *stateChangeTestListener) OnTransformToClosed(prev circuitbreaker.State, rule circuitbreaker.Rule) {
        fmt.Printf("rule.steategy: %+v, From %s to Closed, time: %d\n", rule.Strategy, prev.String(), util.CurrentTimeMillis())
    }
    
    func (s *stateChangeTestListener) OnTransformToOpen(prev circuitbreaker.State, rule circuitbreaker.Rule, snapshot interface{}) {
        fmt.Printf("rule.steategy: %+v, From %s to Open, snapshot: %d, time: %d\n", rule.Strategy, prev.String(), snapshot, util.CurrentTimeMillis())
    }
    
    func (s *stateChangeTestListener) OnTransformToHalfOpen(prev circuitbreaker.State, rule circuitbreaker.Rule) {
        fmt.Printf("rule.steategy: %+v, From %s to Half-Open, time: %d\n", rule.Strategy, prev.String(), util.CurrentTimeMillis())
    }
    
    func main() {
        //基于连接数的降级模式
        total := 0
        totalPass := 0
        totalBlock := 0
        totalErr := 0
        conf := config.NewDefaultConfig()
        // for testing, logging output to console
        conf.Sentinel.Log.Logger = logging.NewConsoleLogger()
        err := sentinel.InitWithConfig(conf)
        if err != nil {
            log.Fatal(err)
        }
        ch := make(chan struct{})
        // Register a state change listener so that we could observer the state change of the internal circuit breaker.
        circuitbreaker.RegisterStateChangeListeners(&stateChangeTestListener{})
    
        _, err = circuitbreaker.LoadRules([]*circuitbreaker.Rule{
            // Statistic time span=10s, recoveryTimeout=3s, maxErrorCount=50
            {
                Resource:         "abc",
                Strategy:         circuitbreaker.ErrorCount,
                RetryTimeoutMs:   3000, //3s只有尝试回复
                MinRequestAmount: 10,   //静默数
                StatIntervalMs:   5000,
                Threshold:        50,
            },
        })
        if err != nil {
            log.Fatal(err)
        }
    
        logging.Info("[CircuitBreaker ErrorCount] Sentinel Go circuit breaking demo is running. You may see the pass/block metric in the metric log.")
        go func() {
            for {
                total++
                e, b := sentinel.Entry("abc")
                if b != nil {
                    // g1 blocked
                    totalBlock++
                    fmt.Println("协程熔断了")
                    time.Sleep(time.Duration(rand.Uint64()%20) * time.Millisecond)
                } else {
                    totalPass++
                    if rand.Uint64()%20 > 9 {
                        totalErr++
                        // Record current invocation as error.
                        sentinel.TraceError(e, errors.New("biz error"))
                    }
                    // g1 passed
                    time.Sleep(time.Duration(rand.Uint64()%20+10) * time.Millisecond)
                    e.Exit()
                }
            }
        }()
        go func() {
            for {
                total++
                e, b := sentinel.Entry("abc")
                if b != nil {
                    // g2 blocked
                    totalBlock++
                    time.Sleep(time.Duration(rand.Uint64()%20) * time.Millisecond)
                } else {
                    // g2 passed
                    totalPass++
                    time.Sleep(time.Duration(rand.Uint64()%80) * time.Millisecond)
                    e.Exit()
                }
            }
        }()
    
        go func() {
            for {
                time.Sleep(time.Second)
                fmt.Println(totalErr)
            }
        }()
        <-ch
    }

以上が電流制限と溶断とは何ですか? Sentinel 電流制限ヒューズの劣化の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はlearnku.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。