首页 后端开发 Golang Go 应用程序中的断路器

Go 应用程序中的断路器

Aug 27, 2024 pm 09:31 PM

如今,我们的应用程序依赖其他应用程序是很常见的,特别是当我们在微服务环境中工作时。我们的应用程序开始报告错误是很常见的,在调查时,我们注意到合作伙伴团队或供应商的某些 API 已关闭。

提高应用程序弹性的一个好做法是切断与那些处于弃用状态的应用程序的通信。观察其他领域,我们吸收了电气工程中断路器的概念。其中放置了一个设备或断路器,如果发生故障,它会自动关闭。这在我们的家里很常见,如果电网开始变得不稳定,断路器会自动关闭。

在计算中,我们的断路器稍微复杂一些,因为我们还定义了一个中间状态。下图更好地解释了断路器的工作原理:

Circuit Breaker em aplicações Go

最后,这些州是:

  • open:应用程序之间没有通信。达到此状态后,计时器开始为重置服务留出时间。在计时器结束时,我们过渡到半开。
  • 关闭:应用程序之间存在通信。对于每个失败的请求,都会更新计数器。如果达到故障极限,我们会将电路切换为开路。
  • half-open:恢复状态,直到通信完全畅通为止。其中,成功计数器会根据每个请求进行更新。如果达到理想的成功次数,我们会将电路移至闭合状态。如果请求失败,我们将恢复开放状态。

很酷,对吧?但为了更好地体现这个概念,我们在实践中如何做呢?

首先,我们来构建我们的服务A,它将负责接收请求,也就是说,它将是我们的应用程序所依赖的服务,供应商的服务等。为了方便起见,我们将公开两个端点,一个始终返回 200 的 /success 和一个始终返回 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 社区已经有了实现该模式的 gobreaker 库!首先,我们定义断路器的属性:

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
}

虽然该库允许我们定制更多的东西,但我们将重点关注三个:

  • 超时:电路保持开路状态的时间。在我们的例子中,时间设置为 5 秒。
  • MaxRequests:关闭前成功请求的数量。在我们的示例中,我们将其设置为 2 个请求。
  • ReadyToTrip:定义从关闭过渡到打开的条件。为了方便起见,我们假设一次失败就足够了。

然后我们可以初始化断路器并发出请求:

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!

我们可以注意到 gobreaker 作为函数的包装器。如果函数返回错误,则会增加错误数量,如果没有,则会增加成功数量。那么让我们定义这个函数:

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 发表了一篇关于该主题的精彩文章!

请在评论中告诉我你对这篇文章的看法,这里有一个问题:你以前使用过断路器吗?哦,你也可以在我的个人博客找到我!

以上是Go 应用程序中的断路器的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Stock Market GPT

Stock Market GPT

人工智能驱动投资研究,做出更明智的决策

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

您如何与Golang的环境变量合作? 您如何与Golang的环境变量合作? Aug 19, 2025 pm 02:06 PM

Goprovidesbuilt-insupportforhandlingenvironmentvariablesviatheospackage,enablingdeveloperstoread,set,andmanageenvironmentdatasecurelyandefficiently.Toreadavariable,useos.Getenv("KEY"),whichreturnsanemptystringifthekeyisnotset,orcombineos.Lo

如何管理Go中的软件包和进口? 如何管理Go中的软件包和进口? Sep 01, 2025 am 02:10 AM

UseGomodulesbyrunninggomodinittocreateago.modfile,whichmanagesdependenciesandversions.2.Organizecodeintopackageswhereeachdirectoryisapackagewithaconsistentpackagename,preferablymatchingthedirectoryname,andstructureimportsbasedonthemodulepath.3.Import

如何在GO中实现通用LRU缓存 如何在GO中实现通用LRU缓存 Aug 18, 2025 am 08:31 AM

使用Go泛型和container/list可实现线程安全的LRU缓存;2.核心组件包括map、双向链表和互斥锁;3.Get和Add操作均通过锁保证并发安全,时间复杂度为O(1);4.当缓存满时自动淘汰最久未使用的条目;5.示例中容量为3的缓存添加4个元素后成功淘汰最久未使用的"b"。该实现完整支持泛型、高效且可扩展。

如何在GO中创建和使用自定义错误类型 如何在GO中创建和使用自定义错误类型 Aug 11, 2025 pm 11:08 PM

在Go中,创建和使用自定义错误类型能提升错误处理的表达力和可调试性,答案是通过定义实现Error()方法的结构体来创建自定义错误,例如ValidationError包含Field和Message字段并返回格式化错误信息,随后可在函数中返回该错误,通过类型断言或errors.As检测具体错误类型以执行不同逻辑,还可为自定义错误添加行为方法如IsCritical,适用于需结构化数据、差异化处理、库导出或API集成的场景,而简单情况可用errors.New,预定义错误如ErrNotFound可用于可比

如何在GO中创建自定义构建标签 如何在GO中创建自定义构建标签 Aug 27, 2025 am 04:37 AM

customBuildTagsingoallowConditionalCompilationBasedOneNennvironment,架构,orcustomscenariosbyusing // go:buildtagsatthetopoffiles,watheretheneeneeneeneenabledviagobuild-tags“ tagname”

您如何处理GO应用程序中的信号? 您如何处理GO应用程序中的信号? Aug 11, 2025 pm 08:01 PM

Go应用中处理信号的正确方式是使用os/signal包监听信号并执行优雅关闭,1.使用signal.Notify将SIGINT、SIGTERM等信号发送到通道;2.在goroutine中运行主服务并阻塞等待信号;3.收到信号后通过context.WithTimeout执行带超时的优雅关闭;4.清理资源如关闭数据库连接、停止后台goroutine;5.必要时用signal.Reset恢复默认信号行为,确保程序在Kubernetes等环境中能可靠终止。

如何在Go中处理恐慌 如何在Go中处理恐慌 Aug 24, 2025 am 01:55 AM

Tohandlepanicsingoroutines,usedeferwithrecoverinsidethegoroutinetocatchandmanagethemlocally.2.Whenapanicisrecovered,logitmeaningfully—preferablywithastacktraceusingruntime/debug.PrintStack—fordebuggingandmonitoring.3.Onlyrecoverfrompanicswhenyoucanta

Go语言中IEEE 754浮点数负零的识别与处理 Go语言中IEEE 754浮点数负零的识别与处理 Aug 11, 2025 pm 05:06 PM

本文深入探讨了Go语言中如何区分IEEE 754标准浮点数中的正零( 0)和负零(-0)。通过分析math包中的Signbit函数,并结合实际代码示例,详细阐述了识别负零的正确方法。文章旨在帮助开发者理解浮点数零值的特性,并掌握在Go语言中精确处理这些特殊数值的技巧,确保在序列化或特定计算场景下符号信息的完整性。

See all articles