CategoryResourceRepost/极客时间专栏/从0开始学架构/高可用架构模式/31 | 如何应对接口级的故障?.md
louzefeng d3828a7aee mod
2024-07-11 05:50:32 +00:00

113 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<audio id="audio" title="31 | 如何应对接口级的故障?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/4a/cc/4ac67798692625f187af5d6488d420cc.mp3"></audio>
异地多活方案主要应对系统级的故障,例如,机器宕机、机房故障、网络故障等问题,这些系统级的故障虽然影响很大,但发生概率较小。在实际业务运行过程中,还有另外一种故障影响可能没有系统级那么大,但发生的概率较高,这就是今天我要与你聊的如何应对接口级的故障。
接口级故障的典型表现就是系统并没有宕机,网络也没有中断,但业务却出现问题了。例如,业务响应缓慢、大量访问超时、大量访问出现异常(给用户弹出提示“无法连接数据库”),这类问题的主要原因在于系统压力太大、负载太高,导致无法快速处理业务请求,由此引发更多的后续问题。例如,最常见的数据库慢查询将数据库的服务器资源耗尽,导致读写超时,业务读写数据库时要么无法连接数据库、要么超时,最终用户看到的现象就是访问很慢,一会访问抛出异常,一会访问又是正常结果。
导致接口级故障的原因一般有下面几种:
- 内部原因
程序bug导致死循环某个接口导致数据库慢查询程序逻辑不完善导致耗尽内存等。
- 外部原因
黑客攻击、促销或者抢购引入了超出平时几倍甚至几十倍的用户,第三方系统大量请求,第三方系统响应缓慢等。
解决接口级故障的核心思想和异地多活基本类似:**优先保证核心业务**和**优先保证绝大部分用户**。
## 降级
降级指系统将某些业务或者接口的功能降低可以是只提供部分功能也可以是完全停掉所有功能。例如论坛可以降级为只能看帖子不能发帖子也可以降级为只能看帖子和评论不能发评论而App的日志上传接口可以完全停掉一段时间这段时间内App都不能上传日志。
降级的核心思想就是丢车保帅优先保证核心业务。例如对于论坛来说90%的流量是看帖子那我们就优先保证看帖的功能对于一个App来说日志上传接口只是一个辅助的功能故障时完全可以停掉。
常见的实现降级的方式有:
- 系统后门降级
简单来说就是系统预留了后门用于降级操作。例如系统提供一个降级URL当访问这个URL时就相当于执行降级指令具体的降级指令通过URL的参数传入即可。这种方案有一定的安全隐患所以也会在URL中加入密码这类安全措施。
系统后门降级的方式实现成本低,但主要缺点是如果服务器数量多,需要一台一台去操作,效率比较低,这在故障处理争分夺秒的场景下是比较浪费时间的。
- 独立降级系统
为了解决系统后门降级方式的缺点,将降级操作独立到一个单独的系统中,可以实现复杂的权限管理、批量操作等功能。其基本架构如下:
<img src="https://static001.geekbang.org/resource/image/1b/63/1b38f4a954d60546dd254c8cefd94463.jpg" alt="">
## 熔断
熔断和降级是两个比较容易混淆的概念,因为单纯从名字上看好像都有禁止某个功能的意思,但其实内在含义是不同的,原因在于降级的目的是应对系统自身的故障,而熔断的目的是应对依赖的外部系统故障的情况。
假设一个这样的场景A服务的X功能依赖B服务的某个接口当B服务的接口响应很慢的时候A服务的X功能响应肯定也会被拖慢进一步导致A服务的线程都被卡在X功能处理上此时A服务的其他功能都会被卡住或者响应非常慢。这时就需要熔断机制了A服务不再请求B服务的这个接口A服务内部只要发现是请求B服务的这个接口就立即返回错误从而避免A服务整个被拖慢甚至拖死。
熔断机制实现的关键是需要有一个统一的API调用层由API调用层来进行采样或者统计如果接口调用散落在代码各处就没法进行统一处理了。
熔断机制实现的另外一个关键是阈值的设计例如1分钟内30%的请求响应时间超过1秒就熔断这个策略中的“1分钟”“30%”“1秒”都对最终的熔断效果有影响。实践中一般都是先根据分析确定阈值然后上线观察效果再进行调优。
## 限流
降级是从系统功能优先级的角度考虑如何应对故障,而限流则是从用户访问压力的角度来考虑如何应对故障。限流指只允许系统能够承受的访问量进来,超出系统访问能力的请求将被丢弃。
虽然“丢弃”这个词听起来让人不太舒服,但保证一部分请求能够正常响应,总比全部请求都不能响应要好得多。
限流一般都是系统内实现的,常见的限流方式可以分为两类:基于请求限流和基于资源限流。
- 基于请求限流
基于请求限流指从外部访问的请求角度考虑限流,常见的方式有:限制总量、限制时间量。
限制总量的方式是限制**某个指标的累积上限**常见的是限制当前系统服务的用户总量例如某个直播间限制总用户数上限为100万超过100万后新的用户无法进入某个抢购活动商品数量只有100个限制参与抢购的用户上限为1万个1万以后的用户直接拒绝。限制时间量指限制**一段时间内某个指标的上限**例如1分钟内只允许10000个用户访问每秒请求峰值最高为10万。
无论是限制总量还是限制时间量共同的特点都是实现简单但在实践中面临的主要问题是比较难以找到合适的阈值例如系统设定了1分钟10000个用户但实际上6000个用户的时候系统就扛不住了也可能达到1分钟10000用户后其实系统压力还不大但此时已经开始丢弃用户访问了。
即使找到了合适的阈值基于请求限流还面临硬件相关的问题。例如一台32核的机器和64核的机器处理能力差别很大阈值是不同的可能有的技术人员以为简单根据硬件指标进行数学运算就可以得出来实际上这样是不可行的64核的机器比32核的机器业务处理性能并不是2倍的关系可能是1.5倍甚至可能是1.1倍。
为了找到合理的阈值,通常情况下可以采用性能压测来确定阈值,但性能压测也存在覆盖场景有限的问题,可能出现某个性能压测没有覆盖的功能导致系统压力很大;另外一种方式是逐步优化,即:先设定一个阈值然后上线观察运行情况,发现不合理就调整阈值。
基于上述的分析,根据阈值来限制访问量的方式更多的适应于业务功能比较简单的系统,例如负载均衡系统、网关系统、抢购系统等。
- 基于资源限流
基于请求限流是从系统外部考虑的,而基于资源限流是从系统内部考虑的,即:找到系统内部影响性能的关键资源,对其使用上限进行限制。常见的内部资源有:连接数、文件句柄、线程数、请求队列等。
例如采用Netty来实现服务器每个进来的请求都先放入一个队列业务线程再从队列读取请求进行处理队列长度最大值为10000队列满了就拒绝后面的请求也可以根据CPU的负载或者占用率进行限流当CPU的占用率超过80%的时候就开始拒绝新的请求。
基于资源限流相比基于请求限流能够更加有效地反映当前系统的压力,但实践中设计也面临两个主要的难点:如何确定关键资源,如何确定关键资源的阈值。通常情况下,这也是一个逐步调优的过程,即:设计的时候先根据推断选择某个关键资源和阈值,然后测试验证,再上线观察,如果发现不合理,再进行优化。
## 排队
排队实际上是限流的一个变种限流是直接拒绝用户排队是让用户等待一段时间全世界最有名的排队当属12306网站排队了。排队虽然没有直接拒绝用户但用户等了很长时间后进入系统体验并不一定比限流好。
由于排队需要临时缓存大量的业务请求单个系统内部无法缓存这么多数据一般情况下排队需要用独立的系统去实现例如使用Kafka这类消息队列来缓存用户请求。
下面是1号店的“双11”秒杀排队系统架构
<img src="https://static001.geekbang.org/resource/image/f2/2a/f207dbbb5eee122yy592f7d015553e2a.jpg" alt="">
其基本实现摘录如下:
>
<p>【排队模块】<br>
负责接收用户的抢购请求,将请求以先入先出的方式保存下来。每一个参加秒杀活动的商品保存一个队列,队列的大小可以根据参与秒杀的商品数量(或加点余量)自行定义。<br>
&nbsp;<br>
【调度模块】<br>
负责排队模块到服务模块的动态调度,不断检查服务模块,一旦处理能力有空闲,就从排队队列头上把用户访问请求调入服务模块,并负责向服务模块分发请求。这里调度模块扮演一个中介的角色,但不只是传递请求而已,它还担负着调节系统处理能力的重任。我们可以根据服务模块的实际处理能力,动态调节向排队系统拉取请求的速度。<br>
&nbsp;<br>
【服务模块】<br>
负责调用真正业务来处理服务,并返回处理结果,调用排队模块的接口回写业务处理结果。</p>
## 小结
今天我为你讲了接口级故障的四种应对方法,分别是降级、熔断、限流和排队,希望对你有所帮助。
这就是今天的全部内容,留一道思考题给你吧,如果你来设计一个整点限量秒杀系统,包括登录、抢购、支付(依赖支付宝)等功能,你会如何设计接口级的故障应对手段?
欢迎你把答案写到留言区,和我一起讨论。相信经过深度思考的回答,也会让你对知识的理解更加深刻。(编辑乱入:精彩的留言有机会获得丰厚福利哦!)