go-kit微服务框架,熔断器(四)

简介

一般在微服架构中,有一个组件角色叫熔断器。顾名思义,熔断器起的作用就是在特定的场景下关掉当前的通路,从而起到保护整个系统的效果。

在微服务架构中,一般我们的独立服务是比较多的,每个独立服务之间划分责任边界,并通过约定协议接口来进行通信。当我们的调用链路复杂依赖多时,很可能会发生雪崩效应。

假设有这么一个场景,有A, B, C, D四个独立服务,A会依赖B,C,D;当D发生负载过高或网络异常等导致响应过慢或超时时,很可能A会因此堆积过多的等待链接,从而导致A的状态也转为异常,后面依赖到A的其他服务跟着发生链式反应,这将会导致大面积的服务不可用,即使本来是一些没有依赖到B,C,D的服务。如下图所示:

这不是我们希望看到的结果,所以这个时候熔断器可以派上用场。最简单的做法,我们为每个依赖服务配置一个熔断器开关,正常情况下是关闭的,也就是可以正常发起请求;当请求失败(超时或者其他异常)次数超过预设值时,熔断器自动打开,这时所有经过这个熔断器的请求都会直接返回失败,并没有真正到达所依赖的服务上。这时服务A本身仍然是能正常服务的。

那么熔断器具体又是怎么工作的呢?来看下,一个拥有基本功能的熔断器的状态机大体是这样子的:

三种状态

  • 关闭状态

当熔断器处于关闭状态时,请求是可以被放行的;

当熔断器统计的失败次数触发开关时,转为打开状态。

  • 打开状态

当熔断器处于打开状态时,所有请求都是不被放行的,直接返回失败;

只有在经过一个设定的时间窗口周期后,熔断器才会转换到半开状态

  • 半开状态

当熔断器处于半开状态时,当前只能有一个请求被放行;

这个被放行的请求获得远端服务的响应后,假如是成功的,熔断器转换为关闭状态,否则转换到打开状态。

熔断器hystrix-go

本质:隔离远程服务请求,防止级联故障

获取

go get github.com/afex/hystrix-go

创建一个熔断器

	//熔断器配置
	config := hystrix.CommandConfig{
		Timeout:                1000*5,
	}
	//根据配置设置熔断器,并起个名字
	hystrix.ConfigureCommand("testhystrix",config)

其中熔断器配置共有5个参数

  • Timeout 请求超时时间 (默认1000毫秒)
  • MaxConcurrentRequests 最大并发请求数 (默认10)
  • RequestVolumeThreshold 请求闸值 ,在当前请求数内,错误率达到ErrorPercentThreshold ,则熔断器进入打开状态 (默认20)
  • ErrorPercentThreshold 错误百分比 (默认50)
  • SleepWindow 熔断器变为打开状态后,持续时长,(默认5000毫秒)

同步使用

		//Do方法为同步执行,
		//参数一:指定熔断器
		//参数二:处理任务方法
		//参数三:当处理方法失败后需要执行的方法,一般为降级服务
		err := hystrix.Do("testhystrix",func()error{
			//执行任务
			//TODO
			fmt.Println(getName())
			return nil
		},func(e error)error{
			//执行降级服务
			fmt.Println(defaultName())
			return nil
		})
		if err!=nil{
			fmt.Println(err)
		}

异步使用

		//Go为异步方法,数据和错误传输借助于管道
		err := hystrix.Go("testhystrix",func()error{
			testchan<-getName()
			return nil
		},func(e error)error{
			testchan<-defaultName()
			return nil
		})
		select {
		case res := <- testchan:
			fmt.Println(res)
		case r := <-err:
			fmt.Println(r.Error())
		}

实战

这里搭配gin框架使用,至于gin和go-kit如何搭配,之后会出文章详解
首先创建配置熔断器

//初始化的时候执行
func InitHystrix(){
	//熔断器配置,根据实际来配置,每个子服务搭配一个熔断器,
	//我只有一个子服务,声明了一个全局熔断器
	config := hystrix.CommandConfig{
		Timeout:                1000*10,
		MaxConcurrentRequests:  100,
		RequestVolumeThreshold: 100,
		ErrorPercentThreshold:  20,
	}
	//根据配置设置熔断器,并起个名字
	hystrix.ConfigureCommand("globalhystrix",config)
}

//将熔断器封装一下
func DecorationGlobal(f func()error,e func(error)error)error{
	return hystrix.Do("globalhystrix",f,e)
}

使用熔断器

//首先声明一个创建一个endpoint
userserver := http.NewServer(epoint.GetUserEnpoint(new(service.UserService)),transport.DecodeUserRequest,transport.EncodeUserResponse)
//将endpoint添加到gin路由上
g.GET("/user",func(c * gin.Context){
	//第一个函数是正常执行的方法
	//第二个函数是错误处理方法
	err := middle.DecorationGlobal(func()error{
		userserver.ServeHTTP(c.Writer,c.Request)
		return nil
	}, func(err error) error {
		c.Status(500)
		return nil
	})
	if err!=nil{
		fmt.Println(err)
	}
})

猜你喜欢

转载自blog.csdn.net/qq_25490573/article/details/106836067