如今,我们的应用程序具有多个依赖项是很常见的,尤其是在微服务环境中工作时。当我们的应用程序报告错误时,我们发现一个依赖项已关闭,这种情况并不罕见。
提高我们恢复能力的一个好习惯是关闭与那些表现不佳的应用程序的通信。看看其他领域,我们从电气工程中学到了断路器的概念,即当发生故障时开关会关闭。在巴西,所有房屋都有这些开关,如果我们的电网不稳定,这些开关会自动关闭。
在计算机科学中,我们的断路器有点复杂,因为它也有一个中间状态。下图详细解释了其工作原理:
简而言之,可能的状态有:
很酷,对吧?为了更好地解释这个概念,为什么不创建一个呢?
首先,让我们构建我们的服务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 }
即使该库允许我们自定义更多属性,我们也只会关注三个:
现在我们只需启动断路器并发送请求:
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中文网其他相关文章!