Maison  >  Article  >  développement back-end  >  Comment utiliser le contexte pour implémenter un disjoncteur de demande dans Go

Comment utiliser le contexte pour implémenter un disjoncteur de demande dans Go

WBOY
WBOYoriginal
2023-07-25 09:04:541328parcourir

Comment utiliser le contexte pour implémenter un disjoncteur de requête dans Go

Avec la popularité de l'architecture des microservices, la communication entre les différents services est devenue de plus en plus fréquente. Dans la communication interservices, la chaîne d'appels peut être très longue, et l'échec ou l'expiration d'une demande peut entraîner l'échec de l'ensemble de la chaîne d'appels, affectant ainsi la disponibilité de l'ensemble du système. Afin de protéger l'ensemble du système contre la panne d'un seul service, nous pouvons utiliser la coupure de circuit sur demande pour contrôler et limiter l'accès à un certain service. Cet article explique comment utiliser le contexte pour implémenter un disjoncteur de demande dans Go.

Qu'est-ce qu'un disjoncteur demandé ?

La demande de coupure de circuit est une stratégie utilisée pour protéger l'ensemble du système. Lorsque le taux d'échec des requêtes d'un service dépasse un seuil prédéterminé, le disjoncteur de requêtes refusera rapidement l'accès au service, évitant ainsi l'apparition de pannes en cascade. Le mode de demande de disjoncteur est généralement utilisé en combinaison avec le modèle de disjoncteur (Circuit Breaker Pattern). Lorsqu'une demande échoue, le disjoncteur s'ouvre rapidement, rejetant ainsi les demandes de service et empêchant un grand nombre de demandes de s'accumuler et de s'accumuler. provoquant l'épuisement des ressources du système.

L'exemple de code pour utiliser le contexte pour implémenter un disjoncteur de demande dans Go est le suivant :

package main

import (
    "context"
    "fmt"
    "sync"
    "time"
)

type CircuitBreaker struct {
    context    context.Context
    cancel     context.CancelFunc
    maxFail    int
    fail       int
    breaker    bool
    resetTime  time.Duration
    breakerMux sync.Mutex
}

func NewCircuitBreaker(maxFail int, resetTime time.Duration) *CircuitBreaker {
    ctx, cancel := context.WithCancel(context.Background())

    circuitBreaker := &CircuitBreaker{
        context:    ctx,
        cancel:     cancel,
        maxFail:    maxFail,
        fail:       0,
        breaker:    false,
        resetTime:  resetTime,
        breakerMux: sync.Mutex{},
    }

    return circuitBreaker
}

func (c *CircuitBreaker) Do(req func() error) error {
    select {
    case <-c.context.Done():
        return fmt.Errorf("circuit breaker is open")
    default:
        if !c.breaker {
            err := req()
            if err == nil {
                c.reset()
            } else {
                c.fail++
                if c.fail >= c.maxFail {
                    c.breakerMux.Lock()
                    c.breaker = true
                    c.breakerMux.Unlock()
                    go time.AfterFunc(c.resetTime, c.reset)
                }
            }
            return err
        } else {
            return fmt.Errorf("circuit breaker is open") 
        }
    }
}

func (c *CircuitBreaker) reset() {
    c.fail = 0
    c.breakerMux.Lock()
    c.breaker = false
    c.breakerMux.Unlock()
    c.cancel()
}

func main() {
    circuitBreaker := NewCircuitBreaker(3, 2*time.Minute)

    // 进行模拟请求
    for i := 0; i < 10; i++ {
        err := circuitBreaker.Do(func() error {
            // 这里执行实际的请求操作,此处只是模拟
            fmt.Println("执行请求...")
            if i%5 == 0 {
                return fmt.Errorf("request failed")
            }
            return nil
        })

        if err != nil {
            fmt.Printf("请求失败: %v
", err)
        } else {
            fmt.Println("请求成功")
        }
    }
}

Dans l'exemple de code ci-dessus, nous avons implémenté un simple disjoncteur de demande via la structure CircuitBreaker. La structure CircuitBreaker a les attributs suivants :

  • contexte et annulation : utilisé pour contrôler le cycle de vie du disjoncteur de demande. Une fois le fusible ouvert, la demande sera rejetée.
  • maxFail : définissez le nombre maximum de pannes. Lorsque le nombre de pannes dépasse la valeur définie, le fusible s'ouvre.
  • échec : enregistrez le nombre de demandes ayant échoué.
  • disjoncteur : enregistrez l'état du fusible. Lorsque cela est vrai, cela signifie que le fusible est ouvert.
  • resetTime : temps de réinitialisation du fusible. Après avoir ouvert le fusible, après cette période de temps, le fusible se refermera.

Des opérations de requête spécifiques peuvent être effectuées via la méthode Do. Si la requête réussit, le nombre d'échecs sera réinitialisé et zéro sera renvoyé. Si la demande échoue, le nombre de défaillances sera incrémenté et lorsque le nombre de défaillances atteindra la valeur définie, le fusible sera ouvert.
Il convient de noter que lorsque le fusible est ouvert, les nouvelles requêtes renverront immédiatement des informations d'erreur.

Dans la fonction principale, nous avons créé un exemple de CircuitBreaker et simulé 10 requêtes. Lorsque le nombre de pannes atteint la valeur définie, le fusible s'ouvrira et les nouvelles demandes seront rejetées.

En utilisant le package de contexte et la structure CircuitBreaker personnalisée, nous pouvons facilement implémenter la fonction de disjoncteur de requête dans Go. L'utilisation d'un disjoncteur sur demande peut protéger efficacement l'ensemble du système contre l'impact d'une seule panne de service et améliorer la disponibilité et la stabilité du système.

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:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn