微服务的熔断、限流和降级

1

服务问题

系统的运行是避免不了问题的产生,而服务问题可以从如下两个角度来分析:

  1. 服务系统问题:如机器宕机、网络、机房故障,虽然这个是有问题但概率很小,在面试的时候简单提即可。

  2. 服务程序问题:如业务响应慢、大量的超时等现象,这些问题主要是因服务程序在执行中因压力、负载过大而导致无法快速处理业务,产生的问题,但在微服务下也不排除是某一个服务因系服务程序异常而停止服务的情况导致的问题。

2

限流

限流在系统业务中大家听到的话题是最多的,无论是否为微服务项目基本上都会或多或少的谈论这个话题,特别在面试中如何应对高并发场景的问题。

限流要解决的问题主要是:

系统在对外提供服务的时候,在一定时间范围内它只能承受一定量的访问压力,可如果超过这个访问量则系统就会存在问题,比如一些请求就出现超时问题。

此时在系统服务中设置限流机制,只允许能够承受的访问量的请求进入,而超出的则采取提示稍后再试。

限流的实现方式:在业界中的限流方式有

  • 基于nginx实现限流;

  • 服务端采用令牌桶、漏斗等算法限流;

3

熔断

熔断是一种思想保护机制,在生活中的例子就如保险丝,当电器存在短路或者电流不稳时,保险丝自动的断开保护电器。

在微服务中亦是如此,当服务A需要服务B中的接口,但因服务B的接口响应慢或存在错误,导致服务A的任务会卡在对B服务调度的业务中,从而影响到A服务中的其他功能。这时我们就可以用到熔断机制熔断A与B的连接,当涉及到服务A请求服务B的请求的时候就会直接返回错误。

这里需要注意熔断的两个关键点:

开启熔断

在固定时间窗口内,接口调用超时比率达到一个阈值,会开启熔断。进入熔断状态后,后续对该服务接口的调用不再经过网络,直接执行本地的默认方法,达到服务降级的效果。

熔断恢复

熔断不可能是永久的。当经过了规定时间之后,服务将从熔断状态回复过来,再次接受调用方的远程调用。

4

降级

降级如其字面意思一样降低级别,而在系统服务中的降级也可以这么理解,在上一节点的内容中已经提到如果服务存在异常会被熔断直接返回出错误,那么思考一下针对这种情况有没有更好地处理方式呢,而不是直接就返回错误。

从程序的执行角度来说,如果流程中存在错误则会终止程序的执行,因此此时就可能用户请求都是错误的可能。为了解决这个问题,在业界中采用降级来优雅的处理,服务存在问题的情况。

降级一般与熔断一起使用,当请求的服务被熔断会返回错误,那么此时我们可以让程序获取缓存的数据或者写死的数据直接返回给客户端。

降级分类:

  1. 超时降级:主要配置好超时时间和超时重试次数和机制,并使用异步机制探测回复情况

  2. 失败次数降级:主要是一些不稳定的api,当失败调用次数达到一定阀值自动降级,同样要使用异步机制探测回复情况

  3. 故障降级:比如要调用的远程服务挂掉了(网络故障、DNS故障、http服务返回错误的状态码、rpc服务抛出异常),则可以直接降级。降级后的处理方案有:默认值(比如库存服务挂了,返回默认现货)、兜底数据(比如广告挂了,返回提前准备好的一些静态页面)、缓存(之前暂存的一些缓存数据)

  4. 限流降级:秒杀或者抢购一些限购商品时,此时可能会因为访问量太大而导致系统崩溃,此时会使用限流来进行限制访问量,当达到限流阀值,后续请求会被降级;降级后的处理方案可以是:排队页面(将用户导流到排队页面等一会重试)、无货(直接告知用户没货了)、错误页(如活动太火爆了,稍后重试)。

5

熔断机制

经过前面的课程学习了解熔断机制的作用,熔断机制主要的作用是调用方自我保护的机制(客观上也能保护被调用方),但在go-zero中实际上服务端与客户端均有引用,目的在于对不稳定的服务依赖进行熔断降级,暂时切断不稳定的服务调用,避免局部不稳定因素导致整个分布式系统的雪崩。

而在熔断机制中最为关键的就是 【熔断的状态】

关闭:默认状态,请求能被到达目标服务,同时统计在窗口时间成功和失败次数,如果达到错误率阈值将会进入断开状态。

断开:此状态下将会直接返回错误,如果有 fallback 配置则直接调用 fallback 方法。

半断开:进行断开状态会维护一个超市时间,到达超时时间开始进入 半断开 状态,尝试允许一部门请求正常通过并统计成功数量,如果请求正常则认为此时目标服务已恢复进入 关闭 状态,否则进入 断开 状态。半断开状态存在的目的在于实现了自我修复,同时防止正在恢复的服务再次被大量打垮。而在熔断中的关键的因素点有:

开启熔断

在固定时间窗口内,接口调用超时比率达到一个阈值,会开启熔断。进入熔断状态后,后续对该服务接口的调用不再经过网络,直接执行本地的默认方法,达到服务降级的效果。

熔断恢复

熔断不可能是永久的。当经过了规定时间之后,服务将从熔断状态回复过来,再次接受调用方的远程调用。

因此根据如上的特点,可构思如下执行流程:

相关的熔断组件:

  1. hystrix circuit breaker(不再维护)

  2. hystrix-go(推荐)

  3. resilience4j(推荐)

  4. sentinel(推荐)

6

源码分析

6.1 自适应算法

根据前面的内容分析可以,熔断机制实现的关键上是【状态】【阚值】

  • 关闭、开放、半开放

  • 错误量与阚值

  • 熔断多久

对系统而言熔断本身对用户来说是有损失的,而如上的参数值在实际工作中并没有明确的合理范围,因此多少合适这个问题说不准,因此就有了自适应熔断。

核心思想通过与googlesre提供的自适应熔断算法来计算丢弃请求的概率。

算法参数:

  1. requests: 一定时间内的请求总数;

  2. accepts:正常请求数量;

  3. K:敏感度,K 越小越容易丢请求,一般推荐 1.5-2 之间;

公式的理解:

  1. 根据公式如果求得的结果 p 大于 0 则开启熔断;

  2. 正常情况:request == accepts,因此整体公式是的结果p是为负数

  3. 存在异常情况时会导致accepts越来越小、request一直增加,此时根据公式requests-K*requests ≥ 0 则程序会根据概率丢弃请求。

  4. 但当程序开始稳定的时候,request与accepts逐渐平衡,此时当概率 p == 0的时候就关闭熔断;

6.2 具体代码

如下是go-zero中熔断器的核心对象结构

Breaker接口:对外表示熔断器功能的接口,如果自己扩展则实际实现这个接口即可

throtte与internalThrottle接口:throttle与internalThrottle接口本身功能是具有相似的,都是执行具体请求及熔断处理,而在go-zero中定义loggedThrottle实现throttle主要目的是记录熔断请求执行中的异常处理,最终熔断的核心实现在GoogleBreaker中。

进入googleBreaker中,在doReq执行流程中:

在代码的执行流程中与之前分析的流程路线是基本一样的过程,但存在不同之处在于具体实现中是不涉及到状态而是通过算法实现。

注意googleBreaker的参数:

自适应熔断算法实现:

7

限流的实现方案

7.1 限流指标

限流的实现是需要依据于参数指标而定比如一定时间内的请求数、任务处理量等等,常用的指标有如下:

  1. QPS(Queries Per Second):每秒请求数,表示每秒钟能够处理的请求量。

  2. 并发数:同时处理的请求数量,表示服务端能够同时处理的请求数。

  3. 响应时间:请求到达服务端后从开始处理到返回响应的时间,表示服务端的处理效率。

  4. hps(Hits Per Second)指每秒用户在页面中点击链接、按钮的总和

  5. TPS(Transactions Per Second)是指一定时间内事务处理完成的总和

7.2 限流层级

在应用中用户从页面请求到服务,基本上都有设置相关的限流处理

界面:验证码、ip黑名单、防爬等

接入:nginx中有limit模块限流一是控制速率、二是控制并发连接数

服务端:在服务端中通过限流算法实现,如令牌桶

7.3 限流方案

7.3.1 nginx限流

nginx的限流实现是需要先引入好limit模块,而限流方案就只有两种1是根据控制速率方案、2是控制并发连接数

控制速率方案

它是根据ip进行控制,在上面的示例中rate=2r/s表示每个请求ip每秒只能请求两次, 其中burst表示每个ip最多有120个突发请求,如果ip在1s内超过2个则会将后多出的请求放在burst队列中等待被处理,如果burst满了则拒绝请求。

控制并发连接数

该方式是是根据并发数控制:

limit_conn perip 10 作用的key 是 $binary_remote_addr,表示限制单个IP同时最多能持有10个连接。

limit_conn perserver 100 作用的key是 $server_name,表示虚拟主机(server) 同时能处理并发连接的总数。

7.3.2 令牌桶

在令牌桶算法中有一个程序以某种恒定的速度生成令牌,并存入令牌桶中,而每个请求需要先获取令牌才能执行,如果没有获取到令牌的请求可以选择等待或者放弃执行。

简要实现示例:

这个示例包含了一个 TokenBucket 结构体,其中定义了令牌桶的参数和状态,以及两个方法:NewTokenBucket 和 Allow。NewTokenBucket 用于创建一个新的令牌桶,并返回指向该令牌桶的指针;Allow 用于检查是否有足够数量的令牌来满足一个请求,并在必要时更新令牌桶的状态。

顶层示例通过将令牌桶填充满10个令牌,然后连续发出11个请求来演示了示例的使用。输出表明,前10个请求被允许通过,但第11个请求被拒绝,因为令牌桶现在已经没有剩余令牌了。

7.3.3 滑动窗口计数

滑动窗口计数器(Sliding Window)算法限流解决固定窗口临界值的问题。它将单位时间周期分为n个小周期,分别记录每个小周期内接口的访问次数,并且根据时间滑动删除过期的小周期。

一张图解释滑动窗口算法,如下:

假设单位时间还是1s,滑动窗口算法把它划分为5个小周期,也就是滑动窗口(单位时间)被划分为5个小格子。每格表示0.2s。每过0.2s,时间窗口就会往右滑动一格。然后呢,每个小周期,都有自己独立的计数器,如果请求是0.83s到达的,0.8~1.0s对应的计数器就会加1。

我们来看下滑动窗口是如何解决临界问题的?

假设我们1s内的限流阀值还是5个请求,0.81.0s内(比如0.9s的时候)来了5个请求,落在黄色格子里。时间过了1.0s这个点之后,又来5个请求,落在紫色格子里。如果**是固定窗口算法,是不会被限流的**,但是**滑动窗口的话,每过一个小周期,它会右移一个小格**。过了1.0s这个点后,会右移一小格,当前的单位时间段是0.21.2s,这个区域的请求已经超过限定的5了,已触发限流啦,实际上,紫色格子的请求都被拒绝啦。

代码示例:

代码说明

数据结构:SlidingWindow 结构体中包含一个时间戳切片 window,用于存储请求的时间。

windowSize 表示滑动窗口的大小(时间范围),maxRequest 表示在该时间范围内允许的最大请求数。

请求处理

在 AllowRequest 方法中,首先锁定互斥锁以保证线程安全。

然后获取当前的时间戳,并清理掉过期的请求(即在当前时间减去窗口大小之前的请求)。

如果当前窗口中的请求数小于最大请求数,则允许请求,并将当前时间戳添加到窗口中;否则,拒绝请求。

8

降级在架构中的类型有哪些

8.1 示例

比如在之前课程的例子中,如果客户端请求api服务到rpc服务,如果存在异常此时在api服务中就可以对请求进行降级,而降级的处理可以是实现定义好的数据信息。

8.2 降级类型与事项

当整个微服务架构整体的负载超出了预设的上限阈值或即将到来的流量预计将会超过预设的阈值时,为了保证重要或基本的服务能正常运行,可以将一些 不重要 或 不紧急 的服务或任务进行服务的 延迟使用 或 暂停使用。

8.2.0 降级注意事项
  1. 什么时候降级

  2. 那些业务需要降级

  3. 降级后在正常情况下又如何恢复

8.2.1 自动降级

1)超时降级:主要配置好超时时间和超时重试次数和机制,并使用异步机制探测回复情况

2)失败次数降级:主要是一些不稳定的api,当失败调用次数达到一定阀值自动降级,同样要使用异步机制探测回复情况

3)故障降级:比如要调用的远程服务挂掉了(网络故障、DNS故障、http服务返回错误的状态码、rpc服务抛出异常),则可以直接降级。降级后的处理方案有:默认值(比如库存服务挂了,返回默认现货)、兜底数据(比如广告挂了,返回提前准备好的一些静态页面)、缓存(之前暂存的一些缓存数据)

4)限流降级:秒杀或者抢购一些限购商品时,此时可能会因为访问量太大而导致系统崩溃,此时会使用限流来进行限制访问量,当达到限流阀值,后续请求会被降级;降级后的处理方案可以是:排队页面(将用户导流到排队页面等一会重试)、无货(直接告知用户没货了)、错误页(如活动太火爆了,稍后重试)。

8.2.2 降级处理

页面降级--禁用点击按钮;

延迟处理--将任务至于消息队列中延迟处理;

读写降级--禁止相关读写请求;

缓存降级--读处理的另一种处理方式,原从数据库读取降级为缓存方式来处理

抛出异常/空;

依据层级降级--比如在特殊时期减少不重要服务的资源,集中于对重要的支持等。


推荐阅读:

Ozone的元数据系统架构演进和优化

云舟观测:Arkit数据解析插件详解

iOS屏幕共享技术实践

更多技术和产品文章,请关注👆

如果您对哪个产品感兴趣,欢迎留言给我们,我们会定向邀文~

go 复制代码
360智汇云是以"汇聚数据价值,助力智能未来"为目标的企业应用开放服务平台,融合360丰富的产品、技术力量,为客户提供平台服务。
目前,智汇云提供数据库、中间件、存储、大数据、人工智能、计算、网络、视联物联与通信等多种产品服务以及一站式解决方案,助力客户降本增效,累计服务业务1000+。
智汇云致力于为各行各业的业务及应用提供强有力的产品、技术服务,帮助企业和业务实现更大的商业价值。
官网:https://zyun.360.cn 或搜索"360智汇云"
客服电话:4000052360
相关推荐
Karoku0661 小时前
【k8s集群应用】kubeadm1.20高可用部署(3master)
运维·docker·云原生·容器·kubernetes
Yvemil71 小时前
《开启微服务之旅:Spring Boot Web开发举例》(一)
前端·spring boot·微服务
小蜗牛慢慢爬行2 小时前
Hibernate、JPA、Spring DATA JPA、Hibernate 代理和架构
java·架构·hibernate
思忖小下3 小时前
梳理你的思路(从OOP到架构设计)_简介设计模式
设计模式·架构·eit
Yvemil75 小时前
《开启微服务之旅:Spring Boot Web开发》(二)
前端·spring boot·微服务
维李设论5 小时前
Node.js的Web服务在Nacos中的实践
前端·spring cloud·微服务·eureka·nacos·node.js·express
探索云原生6 小时前
在 K8S 中创建 Pod 是如何使用到 GPU 的: nvidia device plugin 源码分析
ai·云原生·kubernetes·go·gpu
启明真纳6 小时前
elasticache备份
运维·elasticsearch·云原生·kubernetes
jwolf28 小时前
基于K8S的微服务:一、服务发现,负载均衡测试(附calico网络问题解决)
微服务·kubernetes·服务发现
Yvemil79 小时前
《开启微服务之旅:Spring Boot Web开发举例》(二)
前端·spring boot·微服务