1.中间件的意义
- 避免成为if狂魔
- 提高复用、隔离业务
- 调用清晰、组合随意
2.实现原理
- 中间件一般都封装在路由上,路由是URL请求分发的管理器
- 中间件选型
- 基于链表构建中间件
- 基于责任链的实现
- 缺点:实现复杂,调用方式不灵活
- 使用数组构建中间件
- 控制灵活方便,推荐使用
- gin采用的方式
- 可以进行中间件的跳跃
- 基于链表构建中间件
3.使用方法数组构建中间件—实现思路
- 方法组装
- 构建中间件URL路由
- 构建URL的中间件方法数组
- 使用use方法整合路由与方法数组
- 方法调用
- 构建方法请求逻辑
- 封装http.Handler接口与http.Server整合
请求从路由进来后会先调用方法1、方法2等中间件,最后才会调用反向代理、业务方法。
将路由器注册到服务器中
4.中间件的代码实现
链接: 详见中间件代码的实现与详解
5. 限流与熔断降级
- 高并发系统三大利器:缓存、降级、限流
- 缓存:提升系统访问速度和增大处理容量,为响应业务增加缓存
- 降级:当服务器压力剧增时,根据业务策略降级,以释放服务资源保证业务正常
- 熔断降级原理
- 网关集成熔断与降级
- 限流:通过对并发限速,以达到拒绝服务、排队或等待、降级等处理
- 限流原理
- 网关集成限流
5.1 限流的分类
- 漏桶限流
- 每次请求时计算桶流量,超过阈值则降级请求
- 令牌桶限流
- 每次请求时从令牌桶里取令牌,取不到则降级请求
链接: Go令牌桶详解
- 每次请求时从令牌桶里取令牌,取不到则降级请求
5.2 网关集成限流功能
将其作为中间件插入到某个路由路径上即可。
func RateLimiter() func(c *SliceRouterContext) {l := rate.NewLimiter(1, 2)return func(c *SliceRouterContext) {if !l.Allow() {c.Rw.Write([]byte(fmt.Sprintf("rate limit:%v,%v", l.Limit(), l.Burst())))c.Abort()return}c.Next()}
}
使用代码如下:
package mainimport ("github.com/e421083458/gateway_demo/proxy/middleware""github.com/e421083458/gateway_demo/proxy/proxy""log""net/http""net/url"
)var addr = "127.0.0.1:2002"// 熔断方案
func main() {coreFunc := func(c *middleware.SliceRouterContext) http.Handler {rs1 := "http://127.0.0.1:2003/base"url1, err1 := url.Parse(rs1)if err1 != nil {log.Println(err1)}rs2 := "http://127.0.0.1:2004/base"url2, err2 := url.Parse(rs2)if err2 != nil {log.Println(err2)}urls := []*url.URL{url1, url2}return proxy.NewMultipleHostsReverseProxy(c, urls)}log.Println("Starting httpserver at " + addr)sliceRouter := middleware.NewSliceRouter()sliceRouter.Group("/").Use(middleware.RateLimiter())routerHandler := middleware.NewSliceRouterHandler(coreFunc, sliceRouter)log.Fatal(http.ListenAndServe(addr, routerHandler))
}
5.3 熔断与降级的意义
- 熔断意义
- 熔断器是当依赖的服务已经出现故障时,为了保证自身服务的正常运行不再访问依赖的服务,防止雪崩效用
- 降级意义
- 当服务器压力剧增时,根据业务策略降级,以此释放服务资源保证业务正常
- 当业务出现了熔断时,我们需要降级服务(搭配使用)
熔断器的三种状态
- 关闭状态
- 服务正常,维护失败率统计,达到失败率阈值时,转到开启状态
- 开启状态
- 服务异常,调用fallback函数,一段时间后,进入半开启状态
- 半开启状态
- 尝试恢复服务,失败率高于阈值,进入开启状态,低于阈值,进入关闭状态
5.4 熔断器的原理
5.5 hystrix-go类库
链接: hystrix-go类库的基本使用