(微服务)服务治理:熔断器介绍以及hystrix-go的使用
一、什么是熔断器
要理解熔断器,可以先看看电路中使用的保险丝。
保险丝(fuse)也被称为电流保险丝,IEC127 标准将它定义为“熔断体(fuse-link)”。保险丝是一种保证电路安全运行的电子元器件,作用就是在电流异常升高到一定的高度和热度的时候,自身熔断切断电流,这样可以保护电路安全运行。
保险丝是一种自我保护装置,保护整个电路线路安全。保护整个电路线路安全是说一户家庭用户用电太高或异常保险丝烧断,只影响这家用户用电情况,不会影响线路上的其它家庭用电情况。

- 那微服务治理中的熔断器呢?
它也是一种保护装置,用来保护服务,在流量过高时,保护其它服务能安全运行。
在微服务架构中,系统是由很多服务组成的,一个服务功能可能依赖多个服务,如下简图,服务 C 依赖服务 E 和 服务 F,服务 B 也依赖服务 E。这还是一个小例子图。看看 Uber 的微服务依赖全图,依赖关系更加复杂,相互依赖关系密密麻麻。

当一个服务遇到访问异常流量时,影响的不仅是自身服务,还会影响到与之依赖的服务,依赖的服务又影响它依赖的服务,子子孙孙无穷匮,这样有可能引起系统崩溃,这就是雪崩效应。
要怎么办?
可以使用熔断器为微服务调用提供保护机制。熔断器像“保险丝”一样,它作为一个开关,遇到异常流量,可以打开熔断器断开服务;服务恢复后,又可以关闭熔断器,重新调用服务。
- 服务治理中熔断器:
服务熔断是指调用方访问服务时,通过熔断器做代理来进行访问,熔断器会持续观察服务返回的成功、失败的状态,当失败次数超过设置的阙值时,熔断器断开,请求就不能访问到下游服务了。

它的作用:1. 当所依赖的服务不稳定时,能够起到快速失败的目的
2. 快速失败后,能够用一定的算法动态探测所依赖对象是否恢复
二、熔断器的3种状态
熔断器实现主要是设置一个阙值,这个阙值可以是最大并发数,请求错误率百分比等,超过这个阙值就进行熔断。还会设置一个尝试恢复时间。
熔断器有3种状态:
- CLOSED:默认状态。熔断器计算数(最大请求数、请求错误百分比等)没有达到设置的阙值,熔断器就认为被代理服务状态良好。
- OPEN:熔断器计算数计算数(最大请求数、请求错误百分比等)已经达到阙值,熔断器就认为被代理的服务已经故障了,打开熔断器开关,请求不再代理服务,而是快速失败。
- HALF OPEN:熔断器打开后,为了能自动恢复被代理服务的访问,会切换到半开放状态,去尝试请求被代理服务以查看服务故障是否已经恢复了。如果恢复了,会转为 CLOSED 状态;否则转到 OPEN 状态。

熔断器需要考虑的一些问题:
- 熔断时长的设置,超过这个时长后切换到 HALF OPEN 进行重试。
- 重试时,要注意业务是否允许这样做。
- 不同的异常,需要定义熔断后不同处理逻辑。
- 记录请求失败日志,供以后人工处理使用。
三、熔断框架 hystrix-go
hystrix-go 介绍
hystrix-go 是一个用 Go 语言开发的熔断框架。
hystrix-go 是一个延迟和容错的库,作用是隔离系统调用、服务和第三方调用等,阻止级联故障,并在故障不可避免的复杂分布式系统中能够实现恢复的能力。它是基于 Netflix 的同名项目:https://github.com/Netflix/Hystrix 。
可以看看 Netflix 的 Hystrix 是如何工作,对了解 hystrix-go 有很大帮助,https://github.com/Netflix/Hystrix/wiki/How-it-Works :
- Construct a
HystrixCommandorHystrixObservableCommandObject- Execute the Command
- Is the Response Cached?
- Is the Circuit Open?
- Is the Thread Pool/Queue/Semaphore Full?
HystrixObservableCommand.construct()orHystrixCommand.run()- Calculate Circuit Health
- Get the Fallback
- Return the Successful Response
使用方法介绍
hystrix-go 的调用方法有 2 个:
- Do:同步调用
func Do(name string, run runFunc, fallback fallbackFunc)
- Go:异步调用
func Go(name string, run runFunc, fallback fallbackFunc)
- 将代码作为 hystrix-go 的命令执行
hystrix.Go("my_command", func() error {
// talk to other services
return nil
}, nil)
定义一个依赖外部系统的应用程序逻辑,然后将这个函数传递给 Go。当系统没有问题时,将会执行这个程序逻辑。
- 定义失败后执行的业务逻辑
hystrix.Go("my_command", func() error {
// talk to other services
return nil
}, func(err error) error {
// do this when services are down,调用服务失败后,可以在这里执行一些逻辑
return nil
})
如果想在服务中断期间执行一些业务逻辑,可以传入第三个参数,这个参数也是一个匿名函数。这第三个参数作用就是在第二个参数(匿名函数)的代码调用服务返回错误时,执行的一些业务逻辑。
hystrix.Go(
"my_command",
func() error {
// talk to other services
_, err := http.Get("https://google.com")
if err != nil {
fmt.Println("Get baidu err: %v", err)
return err
}
return nil
},
func(err error) error {
// do this when services are down
fmt.Println("上面匿名函数中代码调用服务错误时,运行这里的代码")
return nil
},
)
- 等待输出
可以选择监控的输出,如下:
output := make(chan bool, 1)
errors := hystrix.Go("my_command", func() error {
// talk to other services
output <- true
return nil
}, nil)
select {
case out := <-output:
// success
case err := <-errors:
// failure
}
- 配置设置
func Configure(cmds map[string]CommandConfig)
func ConfigureCommand(name string, config CommandConfig)
Configure 方法内部也是调用的 ConfigureCommand 方法。
hystrix-go 有一个默认配置。
也可以设置配置,如下:
hystrix.ConfigureCommand(
"my_command", // 熔断器的名字,一个名字对应一个熔断器
hystrix.CommandConfig{
Timeout: 1000, //超时时间,单位毫秒 ms。默认 1000ms
MaxConcurrentRequests: 100, // 最大并发数,超过这个设置就返回错误。默认 10
ErrorPercentThreshold: 25, // 设置错误数量统计百分比阙值,超过这个阙值,就开启熔断。默认 50
RequestVolumeThreshold: 4, // 一个窗口10秒内请求的数量阙值,达到这个阙值就开启熔断
SleepWindow: 1000, // 熔断器被激活后,多久重试服务是否可用,单位毫秒。默认 5000ms
})
- RequestVolumeThreshold:一个窗口10秒内请求的数量阙值,判断熔断开关的条件之一。请求数量大于等于这个设置的数量阙值后,且错误百分比也达到设置的阙值,就开启熔断
- ErrorPercentThreshold:错误数量统计百分比阙值,判断熔断开关的条件之一。请求数量大于等于 RequestVolumeThreshold 并且错误百分比达到这个百分比后就会开启熔断
- 在dashboard中显示hystrix上报信息
main.go 程序中,在 http 的一个端口上注册一个事件流并且在 goroutine 中启动它,就可以在这个http端口上查看这个上报流。如果你在 Hystrix Dashboard 配置了这个事件流,那么事件信息就可以自动显示在 dashboard 上。
hystrixStreamHandler := hystrix.NewStreamHandler()
hystrixStreamHandler.Start()
go http.ListenAndServe(net.JoinHostPort("", "81"), hystrixStreamHandler)
上面的代码开启了 dashboard,在 http 端口 81 上可以查看 hystrix 上报的信息,http://localhost:81。
- 可以向 Statsd 发送 circuit metric
c, err := plugins.InitializeStatsdCollector(&plugins.StatsdCollectorConfig{
StatsdAddr: "localhost:8125",
Prefix: "myapp.hystrix",
})
if err != nil {
log.Fatalf("could not initialize statsd client: %v", err)
}
metricCollector.Registry.Register(c.NewStatsdCollector)
代码示例
一个简单使用 hystrix-go 示例代码:
package main
import (
"fmt"
"net/http"
"github.com/afex/hystrix-go/hystrix"
)
func main() {
hystrix.ConfigureCommand("my_command_name", hystrix.CommandConfig{
Timeout: 1000, // 超时时间1000ms
MaxConcurrentRequests: 40, // 最大并发数40
RequestVolumeThreshold: 20, // 请求数量阙值20,达到这个阙值才可能触发熔断
ErrorPercentThreshold: 20, // 错误百分比例阙值 20%
})
client := http.Client{}
doRequest := func() error {
req, err := http.NewRequest("GET", "https://www.bin.com", nil)
if err != nil {
return err
}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
fmt.Println("doRequest: ", resp.Status)
return nil
}
err := hystrix.Do("my_command_name", func() error {
return doRequest()
}, nil)
if err != nil {
fmt.Println("end: ", err)
}
}
创建一个 http 客户端,封装一个 doRequest 请求函数。
然后调用 hystrix.Do 函数,把封装好的 doRequest 函数放在 Do 函数的第二个参数中执行,Do 函数会监视请求的执行情况,会根据超时时间、并发数、错误百分比阙值等来判断是否允许请求执行,当达到某个阙值时,将会触发熔断器,并执行熔断器的错误执行逻辑,也就是 Do 函数第三个参数,在这段代码中直接设置为 nil ,没有编写错误逻辑代码,也就不执行。
也可以到我的公众号 九卷技术录:(微服务)服务治理:熔断器介绍以及hystrix-go的使用 继续讨论
四、参考
(微服务)服务治理:熔断器介绍以及hystrix-go的使用的更多相关文章
- Spring Cloud 微服务四:熔断器Spring cloud hystrix
前言:在微服务架构中,一般都是进程间通信,有可能调用链都比较长,当有底层某服务出现问题时,比如宕机,会导致调用方的服务失败,这样就会发生一连串的反映,造成系统资源被阻塞,最终可能造成雪崩.在sprin ...
- 分布式服务防雪崩熔断器(Hystrix),实现服务降级
Hystrix是什么? hystrix对应的中文名字是“豪猪”,豪猪周身长满了刺,能保护自己不受天敌的伤害,代表了一种防御机制,这与hystrix本身的功能不谋而合,因此Netflix团队将该框架命名 ...
- 分布式服务防雪崩熔断器,Hystrix理论+实战。
Hystrix是什么? hystrix对应的中文名字是"豪猪",豪猪周身长满了刺,能保护自己不受天敌的伤害,代表了一种防御机制,这与hystrix本身的功能不谋而合,因此Netfl ...
- .Net微服务实践(五)[服务发现]:Consul介绍和环境搭建
目录 介绍 服务发现 健康检查.键值存储和数据中心 架构 Consul模式 环境安装 HTTP API 和Command CLI 示例API介绍 最后 在上篇.Net微服务实践(四)[网关]:Ocel ...
- 基于.NET CORE微服务框架 -surging的介绍和简单示例 (开源)
一.前言 至今为止编程开发已经11个年头,从 VB6.0,ASP时代到ASP.NET再到MVC, 从中见证了.NET技术发展,从无畏无知的懵懂少年,到现在的中年大叔,从中的酸甜苦辣也只有本人自知.随着 ...
- springcloud微服务实战:Eureka+Zuul+Feign/Ribbon+Hystrix Turbine+SpringConfig+sleuth+zipkin
相信现在已经有很多小伙伴已经或者准备使用springcloud微服务了,接下来为大家搭建一个微服务框架,后期可以自己进行扩展.会提供一个小案例: 服务提供者和服务消费者 ,消费者会调用提供者的服务,新 ...
- 微服务:Eureka+Zuul+Ribbon+Feign+Hystrix构建微服务架构
原文地址:http://blog.csdn.net/qq_18675693/article/details/53282031 本案例将打架一个微服务框架,参考来源官方参考文档 微服务:是什么?网上有一 ...
- [转帖]微服务框架Spring Cloud介绍 Part1: 使用事件和消息队列实现分布式事务
微服务框架Spring Cloud介绍 Part1: 使用事件和消息队列实现分布式事务 http://skaka.me/blog/2016/04/21/springcloud1/ APR 21ST, ...
- 第五章 服务容错保护:Spring Cloud Hystrix
在微服务架构中,我们将系统拆分为很多个服务,各个服务之间通过注册与订阅的方式相互依赖,由于各个服务都是在各自的进程中运行,就有可能由于网络原因或者服务自身的问题导致调用故障或延迟,随着服务的积压,可能 ...
- 三、安装cmake,安装resin ,tars服务,mysql 安装介绍,安装jdk,安装maven,c++ 开发环境安装
三.安装cmake,安装resin 2018年07月01日 21:32:05 youz1976 阅读数:308 开发环境说明: centos7.2 ,最低配置:1核cpu,2G内存,1M带宽 1. ...
随机推荐
- [转帖]KingbaseES wal(xlog) 日志清理故障恢复案例
https://www.cnblogs.com/kingbase/p/16266365.html 案例说明:在通过sys_archivecleanup工具手工清理wal日志时,在control文件中查 ...
- minio性能测试
minio性能测试 minio的使用 前期使用了s3fs 但是想验证一下性能相关, 所以使用今天简单验证了一下, 其实也可以使用一下fio 但是s3fs 是对象存储 没有修改 只有上传, 所以感觉还是 ...
- [转帖]CentOS7安装笔记:minio分布式集群搭建
文章目录 准备机器 部署(所有机器均执行) 创建挂载磁盘路径 挂载磁盘路径到文件系统 创建minio目录 下载minio安装包 创建启动脚本 创建启动服务 启动测试(所有机器执行) 重新加载服务的配置 ...
- [转帖]Kubernetes-18:Dashboard安装及使用
https://www.cnblogs.com/v-fan/p/13950268.html Helm安装Dashboard 简介 Dashboard 是 kubernetes 的图形化管理工具,可直观 ...
- [转帖]Traefik中诡异的502和504问题
https://zhuanlan.zhihu.com/p/156138704 我们都知道在 Kubernetes 集群中通常会使用 Ingress 方案来统一代理集群内部的流量,而常用的 Ingres ...
- Docker镜像的基本操作总结
摘要 容器化是上个十年比较火的技术. 现在看起来在进行总计有点晚了. 不过linux是三十年前的,我依旧没有总结好 道理是一样的. 技术不在于新旧, 重要的是学习到原理. Docker的重要概念 Re ...
- vue如何在render函数中使用判断(2)
h函数的三个参数 第一个参数是必须的. 类型:{String | Object | Function} 一个 HTML 标签名.一个组件.一个异步组件.或一个函数式组件. 是要渲染的html标签. 第 ...
- 正则表达式match方法和search方法
正则表达式, //match() 方法可在字符串内检索指定的值 找到返回相关数据,找不到返回null var part = /Box/ig; var str = "this is box,i ...
- css 宽度分离原则
我们想设计一个w=180px:h=100px的div; .demo1 { width: 180px; height: 100px; background: pink; padding: 10px; b ...
- 【小测试】rust中的无符号整数溢出
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 1.在编译阶段就可以识别出来的溢出 fn main(){ ...