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

Go 应用程序中的断路器

Sep 03, 2024 pm 02:15 PM

如今,我们的应用程序具有多个依赖项是很常见的,尤其是在微服务环境中工作时。当我们的应用程序报告错误时,我们发现一个依赖项已关闭,这种情况并不罕见。

提高我们恢复能力的一个好习惯是关闭与那些表现不佳的应用程序的通信。看看其他领域,我们从电气工程中学到了断路器的概念,即当发生故障时开关会关闭。在巴西,所有房屋都有这些开关,如果我们的电网不稳定,这些开关会自动关闭。

在计算机科学中,我们的断路器有点复杂,因为它也有一个中间状态。下图详细解释了其工作原理:

Circuit Breaker in Go apps

简而言之,可能的状态有:

  • 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 社区已经拥有已经实现了该模式的 lib 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
}
登录后复制

即使该库允许我们自定义更多属性,我们也只会关注三个:

  • 超时:处于打开状态的时间长度。在此示例中,我们选择五秒。
  • MaxRequests:关闭之前有多少个成功请求。在此示例中,我们决定了两个请求。
  • 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

热门文章

仓库:如何复兴队友
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 周前 By 尊渡假赌尊渡假赌尊渡假赌

热门文章

仓库:如何复兴队友
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 周前 By 尊渡假赌尊渡假赌尊渡假赌

热门文章标签

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

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

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

Go语言包导入:带下划线和不带下划线的区别是什么? Go语言包导入:带下划线和不带下划线的区别是什么? Mar 03, 2025 pm 05:17 PM

Go语言包导入:带下划线和不带下划线的区别是什么?

Beego框架中NewFlash()函数如何实现页面间短暂信息传递? Beego框架中NewFlash()函数如何实现页面间短暂信息传递? Mar 03, 2025 pm 05:22 PM

Beego框架中NewFlash()函数如何实现页面间短暂信息传递?

如何编写模拟对象和存根以进行测试? 如何编写模拟对象和存根以进行测试? Mar 10, 2025 pm 05:38 PM

如何编写模拟对象和存根以进行测试?

如何使用跟踪工具了解GO应用程序的执行流? 如何使用跟踪工具了解GO应用程序的执行流? Mar 10, 2025 pm 05:36 PM

如何使用跟踪工具了解GO应用程序的执行流?

Go语言中如何将MySQL查询结果List转换为自定义结构体切片? Go语言中如何将MySQL查询结果List转换为自定义结构体切片? Mar 03, 2025 pm 05:18 PM

Go语言中如何将MySQL查询结果List转换为自定义结构体切片?

如何定义GO中仿制药的自定义类型约束? 如何定义GO中仿制药的自定义类型约束? Mar 10, 2025 pm 03:20 PM

如何定义GO中仿制药的自定义类型约束?

Go语言如何便捷地写入文件? Go语言如何便捷地写入文件? Mar 03, 2025 pm 05:15 PM

Go语言如何便捷地写入文件?

我如何使用衬里和静态分析工具来提高GO代码的质量和可维护性? 我如何使用衬里和静态分析工具来提高GO代码的质量和可维护性? Mar 10, 2025 pm 05:38 PM

我如何使用衬里和静态分析工具来提高GO代码的质量和可维护性?

See all articles