Maison  >  Article  >  développement back-end  >  Que sont la limitation de courant et la fusion ? Explication détaillée de la dégradation du fusible limiteur de courant Sentinel

Que sont la limitation de courant et la fusion ? Explication détaillée de la dégradation du fusible limiteur de courant Sentinel

藏色散人
藏色散人avant
2022-11-13 16:37:402770parcourir

Cet article vous est présenté par la rubrique tutoriel golang sur la limitation de courant Sentinel et la dégradation des disjoncteurs. Le contenu comprend une introduction à la limitation de courant et au disjoncteur, ainsi que Sentinel open source alibaba, l'installation et une introduction pratique. j'espère que cela sera utile à des amis dans le besoin !

Que sont la limitation de courant et la fusion ? Explication détaillée de la dégradation du fusible limiteur de courant Sentinel

Déclassement du disjoncteur limiteur de courant sentinelle

Qu'est-ce que le déclassement du disjoncteur limiteur de courant

Limitation de courant : dans notre système acquis, si une grande quantité de trafic entre soudainement ce jour-là, notre service ne peut que le faire ? gérer un maximum de 2 000 requêtes en même temps, et soudainement 5 000 requêtes sont arrivées. N'est-ce pas une pression terrible sur le serveur ? Cela peut directement provoquer une panne et un crash du serveur, empêchant le volume de traitement 2K d'origine de fonctionner ? À ce stade, nous devons limiter le flux. La fonction de la limite de flux est de maintenir le nombre de visites sur le serveur au plus haut niveau et de ne pas traiter les requêtes redondantes. En comparaison, c'est bien mieux que le serveur. raccroche directement. Par exemple, pendant Double Eleven, lorsque nous souhaitons passer une commande, nous verrons quelque chose comme "La demande est occupée, veuillez réessayer plus tard !".

Fusible : Je pense que tout le monde connaît le disjoncteur. Il équivaut à un interrupteur, qui peut empêcher la circulation lorsqu'il est ouvert. Par exemple, un fusible sautera lorsque le courant est trop important pour éviter d'endommager les composants.

Le disjoncteur de service signifie que l'appelant accède au service via un disjoncteur en tant que proxy. Le disjoncteur continuera à observer l'état de réussite et d'échec renvoyé par le service.

Lorsque la panne dépasse le seuil défini, le disjoncteur. est ouvert et la demande ne peut pas être authentifiée. Le service est accessible localement.

Scénarios d'utilisation

Lorsque le service échoue ou est mis à niveau, laissez le client échouer rapidement

La logique de traitement des échecs est facile à définir

    La réponse prend beaucoup de temps et le délai de lecture défini par le client sera plus long. Empêcher la libération des connexions et des ressources de thread en raison d'un grand nombre de demandes de nouvelle tentative du client
  • * Dégrader* : la rétrogradation du service est basée sur l'état de charge de l'ensemble du système. la charge est relativement élevée, afin d'éviter que certaines fonctions (scénarios métier
  • ) soient surchargées ou répondent lentement, les requêtes pour certaines interfaces et données non essentielles soient temporairement abandonnées en interne, et une

  • erreur de repli (retraite) préparée les informations de traitement sont directement renvoyées. De cette manière, même s’il fournit un service avec perte, il garantit la stabilité et la disponibilité de l’ensemble du système.
  • Qu'est-ce que Sentinel

Sentinel est un projet open source d'Alibaba. Il fournit plusieurs dimensions telles que le contrôle de flux, la dégradation du disjoncteur et la protection de la charge du système pour garantir la stabilité des services.

Site officiel : github.com/alibaba/Sentinel/wiki

Sentinel est né à Alibaba en 2012, et son objectif principal est le contrôle du trafic. De 2013 à 2017, Sentinel s'est développé rapidement et est devenu un composant de base de tous les microservices Alibaba. Il est utilisé dans plus de 6 000 applications, couvrant presque tous les principaux scénarios de commerce électronique. En 2018, Sentinel est devenu un projet open source. En 2020, Sentinel Golang est sorti.

Caractéristiques :

Scénarios d'application riches : Sentinel a entrepris les scénarios de base de la promotion du trafic Double Eleven d'Alibaba au cours des 10 dernières années, tels que les ventes flash (c'est-à-dire que le trafic en rafale est contrôlé dans la plage que la capacité du système peut supporter) , messagerie Élimination des pics et remplissage des vallées, contrôle du flux des clusters, fusion en temps réel des applications indisponibles en aval, etc.

Surveillance complète en temps réel : Sentinel fournit également des fonctions de surveillance en temps réel. Vous pouvez voir les données de deuxième niveau d'une seule machine connectée à l'application dans la console, et même le résumé de l'état de fonctionnement d'un cluster de moins de 500 machines.

*Large Ecology*

Histoire de Sentinel

En 2012, Sentinel est née, dont la fonction principale est le contrôle du débit d'entrée.

De 2013 à 2017, Sentinel s'est développé rapidement au sein du groupe Alibaba et est devenu un module technologique de base, couvrant tous les scénarios de base. Sentinel a ainsi accumulé un grand nombre de scénarios de consolidation de trafic et de pratiques de production.

En 2018, Sentinel était open source et continue d'évoluer.

    En 2019, Sentinel a continué à explorer la direction de l'expansion multilingue, en lançant une version native C++, et a également lancé la prise en charge du contrôle de flux de cluster Envoy pour les scénarios Service Mesh afin de résoudre le problème de limitation de courant multilingue dans le cadre du service. Architecture maillée.
  • En 2020, la version Sentinel Go a été lancée et continue d'évoluer vers une direction cloud native.
  • En 2021, Sentinel évolue vers le composant de centre de décision haute disponibilité cloud natif 2.0 en même temps que la version native de Sentinel Rust est lancée ; Dans le même temps, nous avons également exploré des scénarios tels que l'extension Envoy WASM et l'extension eBPF dans la communauté Rust.
  • En 2022, la marque Sentinel sera mise à niveau vers la gestion du trafic, couvrant le routage/planification du trafic, la coloration du trafic, la dégradation du contrôle de flux, la protection contre les surcharges/suppression d'instances, etc. en même temps, la communauté extraira la gestion du trafic ; normes associées dans la norme OpenSergo, et Sentinel servira de mise en œuvre des normes de gestion du trafic.
  • Installation de Sentinel-go

  • Adresse open source de Sentinel-go : https://github.com/alibaba/sentinel-golang
  • Documentation officielle du site Web

    Installation :go get github.com/alibaba/sentinel-golang/api

    Go current limiting practice

    qps current limiting

    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()
            }
        }
    }

    Imprimer les résultats :

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

    Thrnotting

    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
    }

    Résultat d'impression : atteint progressivement 1k, au Position 1k Fluctue de haut en bas

    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

    Allez au combat réel du disjoncteur

    Ici, nous introduisons un numéro incorrect, visualisons le mécanisme détaillé du disjoncteur

    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
    }

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer