”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > Go 应用程序中的断路器

Go 应用程序中的断路器

发布于2024-11-07
浏览:485

如今,我们的应用程序依赖其他应用程序是很常见的,特别是当我们在微服务环境中工作时。我们的应用程序开始报告错误是很常见的,在调查时,我们注意到合作伙伴团队或供应商的某些 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 发表了一篇关于该主题的精彩文章!

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

版本声明 本文转载于:https://dev.to/mfbmina/circuit-breaker-em-aplicacoes-go-4hnn?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • PHP阵列键值异常:了解07和08的好奇情况
    PHP阵列键值异常:了解07和08的好奇情况
    PHP数组键值问题,使用07&08 在给定数月的数组中,键值07和08呈现令人困惑的行为时,就会出现一个不寻常的问题。运行print_r($月份)返回意外结果:键“ 07”丢失,而键“ 08”分配给了9月的值。此问题源于PHP对领先零的解释。当一个数字带有0(例如07或08)的前缀时,PHP将...
    编程 发布于2025-04-13
  • 对象拟合:IE和Edge中的封面失败,如何修复?
    对象拟合:IE和Edge中的封面失败,如何修复?
    To resolve this issue, we employ a clever CSS solution that solves the problem:position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%)...
    编程 发布于2025-04-13
  • 在PHP中如何高效检测空数组?
    在PHP中如何高效检测空数组?
    在PHP 中检查一个空数组可以通过各种方法在PHP中确定一个空数组。如果需要验证任何数组元素的存在,则PHP的松散键入允许对数组本身进行直接评估:一种更严格的方法涉及使用count()函数: if(count(count($ playerList)=== 0){ //列表为空。 } 对...
    编程 发布于2025-04-13
  • Android如何向PHP服务器发送POST数据?
    Android如何向PHP服务器发送POST数据?
    在android apache httpclient(已弃用) httpclient httpclient = new defaulthttpclient(); httppost httppost = new httppost(“ http://www.yoursite.com/script.p...
    编程 发布于2025-04-13
  • 如何将来自三个MySQL表的数据组合到新表中?
    如何将来自三个MySQL表的数据组合到新表中?
    mysql:从三个表和列的新表创建新表 答案:为了实现这一目标,您可以利用一个3-way Join。 选择p。*,d.content作为年龄 来自人为p的人 加入d.person_id = p.id上的d的详细信息 加入T.Id = d.detail_id的分类法 其中t.taxonomy =...
    编程 发布于2025-04-13
  • Python高效去除文本中HTML标签方法
    Python高效去除文本中HTML标签方法
    在Python中剥离HTML标签,以获取原始的文本表示Achieving Text-Only Extraction with Python's MLStripperTo streamline the stripping process, the Python standard librar...
    编程 发布于2025-04-13
  • 如何使用Python的请求和假用户代理绕过网站块?
    如何使用Python的请求和假用户代理绕过网站块?
    如何使用Python的请求模拟浏览器行为,以及伪造的用户代理提供了一个用户 - 代理标头一个有效方法是提供有效的用户式header,以提供有效的用户 - 设置,该标题可以通过browser和Acterner Systems the equestersystermery和操作系统。通过模仿像Chro...
    编程 发布于2025-04-13
  • FastAPI自定义404页面创建指南
    FastAPI自定义404页面创建指南
    response = await call_next(request) if response.status_code == 404: return RedirectResponse("https://fastapi.tiangolo.com") else: ...
    编程 发布于2025-04-13
  • 为什么使用Firefox后退按钮时JavaScript执行停止?
    为什么使用Firefox后退按钮时JavaScript执行停止?
    导航历史记录问题:JavaScript使用Firefox Back Back 此行为是由浏览器缓存JavaScript资源引起的。要解决此问题并确保在后续页面访问中执行脚本,Firefox用户应设置一个空功能。 警报'); }; alert('inline Alert')...
    编程 发布于2025-04-13
  • 如何在其容器中为DIV创建平滑的左右CSS动画?
    如何在其容器中为DIV创建平滑的左右CSS动画?
    通用CSS动画,用于左右运动 ,我们将探索创建一个通用的CSS动画,以向左和右移动DIV,从而到达其容器的边缘。该动画可以应用于具有绝对定位的任何div,无论其未知长度如何。问题:使用左直接导致瞬时消失 更加流畅的解决方案:混合转换和左 [并实现平稳的,线性的运动,我们介绍了线性的转换。这...
    编程 发布于2025-04-13
  • 可以在纯CS中将多个粘性元素彼此堆叠在一起吗?
    可以在纯CS中将多个粘性元素彼此堆叠在一起吗?
    [2这里: https://webthemez.com/demo/sticky-multi-header-scroll/index.html </main> <section> { display:grid; grid-template-...
    编程 发布于2025-04-13
  • \“(1)vs.(;;):编译器优化是否消除了性能差异?\”
    \“(1)vs.(;;):编译器优化是否消除了性能差异?\”
    答案: 在大多数现代编译器中,while(1)和(1)和(;;)之间没有性能差异。编译器: perl: 1 输入 - > 2 2 NextState(Main 2 -E:1)V-> 3 9 Leaveloop VK/2-> A 3 toterloop(next-> 8 last-> 9 ...
    编程 发布于2025-04-13
  • 使用LINQ获取基于CarCode的不同Car对象方法
    使用LINQ获取基于CarCode的不同Car对象方法
    [2 使用linq基于carcode 提取唯一的汽车对象 挑战: 假设您有一个解决方案: Linq的分组和选择功能提供了简洁的解决方案: 详细说明:[2 方法将原始列表组织为组,由[ property分类。 每个组都包含汽车共享相同的。。 随后,选择方法通过这些组迭代,从每个组中选择第一个对象...
    编程 发布于2025-04-13
  • 在C++和C中,布尔值转换为整数时是否总是0或1?
    在C++和C中,布尔值转换为整数时是否总是0或1?
    在c和c之类的编程语言中,BOOL为0或1? 实际示例在代码中说明此行为: bool b = a; int c = 3 b; // 4 在此示例中,Bool变量B初始化为Int A(2)的值(2),但是由于BOOL值存储为0或1,B为1。随后添加3个结果C中分配了值4。这证实了Bool将BOOL...
    编程 发布于2025-04-13
  • 如何在php中使用卷发发送原始帖子请求?
    如何在php中使用卷发发送原始帖子请求?
    如何使用php 创建请求来发送原始帖子请求,开始使用curl_init()开始初始化curl session。然后,配置以下选项: curlopt_url:请求 [要发送的原始数据指定内容类型,为原始的帖子请求指定身体的内容类型很重要。在这种情况下,它是文本/平原。要执行此操作,请使用包含以下标头...
    编程 发布于2025-04-13

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3