首页 > 其他分享 >(微服务)服务治理:熔断器介绍以及hystrix-go的使用

(微服务)服务治理:熔断器介绍以及hystrix-go的使用

时间:2023-04-17 20:35:52浏览次数:50  
标签:服务 hystrix err 熔断器 阙值 go

一、什么是熔断器

要理解熔断器,可以先看看电路中使用的保险丝。

保险丝(fuse)也被称为电流保险丝,IEC127 标准将它定义为“熔断体(fuse-link)”。保险丝是一种保证电路安全运行的电子元器件,作用就是在电流异常升高到一定的高度和热度的时候,自身熔断切断电流,这样可以保护电路安全运行。

保险丝是一种自我保护装置,保护整个电路线路安全。保护整个电路线路安全是说一户家庭用户用电太高或异常保险丝烧断,只影响这家用户用电情况,不会影响线路上的其它家庭用电情况。

image-20230415234256720

  • 那微服务治理中的熔断器呢?

它也是一种保护装置,用来保护服务,在流量过高时,保护其它服务能安全运行。

在微服务架构中,系统是由很多服务组成的,一个服务功能可能依赖多个服务,如下简图,服务 C 依赖服务 E 和 服务 F,服务 B 也依赖服务 E。这还是一个小例子图。看看 Uber 的微服务依赖全图,依赖关系更加复杂,相互依赖关系密密麻麻。

image-20230416005724668

当一个服务遇到访问异常流量时,影响的不仅是自身服务,还会影响到与之依赖的服务,依赖的服务又影响它依赖的服务,子子孙孙无穷匮,这样有可能引起系统崩溃,这就是雪崩效应

要怎么办?

可以使用熔断器为微服务调用提供保护机制。熔断器像“保险丝”一样,它作为一个开关,遇到异常流量,可以打开熔断器断开服务;服务恢复后,又可以关闭熔断器,重新调用服务。

  • 服务治理中熔断器:

服务熔断是指调用方访问服务时,通过熔断器做代理来进行访问,熔断器会持续观察服务返回的成功、失败的状态,当失败次数超过设置的阙值时,熔断器断开,请求就不能访问到下游服务了。

image-20230416022203606

它的作用:1. 当所依赖的服务不稳定时,能够起到快速失败的目的

​ 2. 快速失败后,能够用一定的算法动态探测所依赖对象是否恢复

二、熔断器的3种状态

熔断器实现主要是设置一个阙值,这个阙值可以是最大并发数,请求错误率百分比等,超过这个阙值就进行熔断。还会设置一个尝试恢复时间。

熔断器有3种状态:

  • CLOSED:默认状态。熔断器计算数(最大请求数、请求错误百分比等)没有达到设置的阙值,熔断器就认为被代理服务状态良好。
  • OPEN:熔断器计算数计算数(最大请求数、请求错误百分比等)已经达到阙值,熔断器就认为被代理的服务已经故障了,打开熔断器开关,请求不再代理服务,而是快速失败。
  • HALF OPEN:熔断器打开后,为了能自动恢复被代理服务的访问,会切换到半开放状态,去尝试请求被代理服务以查看服务故障是否已经恢复了。如果恢复了,会转为 CLOSED 状态;否则转到 OPEN 状态。

image-20230416035122513

熔断器需要考虑的一些问题:

  • 熔断时长的设置,超过这个时长后切换到 HALF OPEN 进行重试。
  • 重试时,要注意业务是否允许这样做。
  • 不同的异常,需要定义熔断后不同处理逻辑。
  • 记录请求失败日志,供以后人工处理使用。

三、熔断框架 hystrix-go

hystrix-go 介绍

hystrix-go 是一个用 Go 语言开发的熔断框架。

https://github.com/afex/hystrix-go

hystrix-go 是一个延迟和容错的库,作用是隔离系统调用、服务和第三方调用等,阻止级联故障,并在故障不可避免的复杂分布式系统中能够实现恢复的能力。它是基于 Netflix 的同名项目:https://github.com/Netflix/Hystrix

可以看看 Netflix 的 Hystrix 是如何工作,对了解 hystrix-go 有很大帮助,https://github.com/Netflix/Hystrix/wiki/How-it-Works

  1. Construct a HystrixCommand or HystrixObservableCommand Object
  2. Execute the Command
  3. Is the Response Cached?
  4. Is the Circuit Open?
  5. Is the Thread Pool/Queue/Semaphore Full?
  6. HystrixObservableCommand.construct() or HystrixCommand.run()
  7. Calculate Circuit Health
  8. Get the Fallback
  9. 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,err,熔断器,阙值,go
From: https://www.cnblogs.com/jiujuan/p/17327387.html

相关文章

  • vue加goframe使用AES加解密(记录)
    vue加goframe使用AES加解密首先,需要在前端使用Vue的crypto-js库来进行AES加解密,可以使用以下命令进行安装:npminstallcrypto-js然后在需要加解密的组件中引入该库:importCryptoJSfrom'crypto-js'对于加密,可以使用以下代码:constkey=CryptoJS.enc.Utf8.parse('1234567......
  • IE和Google浏览器事件传递参数不同
    左键标示,IE里面是1,Google里面是0,右键都是2.判断为左键,0或1都是<!DOCTYPEhtmlPUBLIC"-//W3C//DTDXHTML1.0Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><spanid="t-p"οnmοusedοwn="whichButtonDown(e......
  • 连接MongoDB+Docker安装MongoDB
    一、连接MongoDB工具:studio3T下载:https://studio3t.com/download-thank-you/?OS=win641、无设置密码最终成功页面2、设置了密码后续同1二、安装MongoDB版本:5.0.5参考:https://www.cnblogs.com/cwp-bg/p/10403327.htmlhttps://blog.csdn.net/weixin_4......
  • log4j的additivity和category使用
    1log4j.rootCategory是对根类的设置,如不说明,以下的子类都要继承这些设置 log4j.category.*是对自定义类的设置,可以对类、包和工程单独设置Category的家族关系是通过“.”来说明的,比如x是x.y的父类。默认情况下,子类要继承父类的全部设置,比如:log4j.rootCategory=INFO,dest1log4j.ca......
  • Gorm的使用 增删改查
     packagemainimport("fmt""gorm.io/driver/mysql""gorm.io/gorm")typeProductstruct{gorm.ModelCodestringPriceuint}funcmain(){dsn:="root:root@tcp(127.0.0.1:3306)/test_lc......
  • ABAP 数据库表 Size Category 字段的准确含义
    有朋友在我这篇教程文章里留言:14.如何创建最简单的ABAP数据库表,以及编码从数据库表中读取数据(上)这位朋友的问题是想咨询ABAP数据库表TechnicalSettings里这个SizeCategory,如果开发人员当时设置了一个比较小的值,比如选择的0,对应的记录数是0到1000.那么随着应用......
  • fgo2023卡池顺序国服介绍 命运冠位指定必抽卡池推荐_fgo2021卡池
    首先先说呵呵,《fgo(宿命玄应选定)》是这款厨力手机游戏,讨厌的配角不管再怎么菜深入细致培育也是能出场的,必须抽的配角就那几个,所以玩者们能根据自己的喜爱选择配角。对于崭新的2023年,相信FGO的玩者最关心的,就是2023年配角卡池的轮换次序,以及有哪些崭新的配角卡池,这样就能进行宝石的......
  • Java中的goto
    Java中的goto关键字在C/C++中,goto常被用于跳出多重循环。但goto语句的使用往往会使程序的可读性降低,所以Java不允许goto跳转。实际上,自从“goto有害论”提出后,软件开发就不建议使用goto了,但是Java中依然保留了goto这个关键字留作备用,但这个关键字没有任何作用,只是为了将来......
  • go mod 替换不可用包
    require(xxxxxxxv0.0.0-incompatible)replace(xxxxx=>xxxx分支)以上文件中的xxxxxx代码仓库修改为以上格式,然会使用replace命令替换 仓库到分支,使用gomodtidy命令修复后会自动引用这个分支上合适的版本号......
  • 【go语言】错误处理
    1.sentinelerror预定义的特定错误,我们叫为sentinelerror,这个名字来源于计算机编程中使用一个特定值来表示不可能进行进一步处理的做法。所以对于Go,我们使用特定的值来表示错误。iferr==ErrSomething{…}类似的io.EOF,更底层的syscall.ENOENT。使用sentinel值是最不......