高可用如何设计-超时与重试

简介: 《高可用》系列

由于网络问题、系统或者服务内部的 Bug、服务器宕机、操作系统崩溃等问题的不确定性,我们的系统或者服务永远不可能保证时刻都是可用的状态。

为了最大限度的减小系统或者服务出现故障之后带来的影响,我们需要用到的 超时(Timeout) 和 重试(Retry) 机制。

想要把超时和重试机制讲清楚其实很简单,因为它俩本身就不是什么高深的概念。

虽然超时和重试机制的思想很简单,但是它俩是真的非常实用。你平时接触到的绝大部分涉及到远程调用的系统或者服务都会应用超时和重试机制。尤其是对于微服务系统来说,正确设置超时和重试非常重要。单体服务通常只涉及数据库、缓存、第三方 API、中间件等的网络调用,而微服务系统内部各个服务之间还存在着网络调用。


超时机制

什么是超时机制?

超时机制说的是当一个请求超过指定的时间(比如 1s)还没有被处理的话,这个请求就会直接被取消并抛出指定的异常或者错误(比如 504 Gateway Timeout)。

我们平时接触到的超时可以简单分为下面 2 种:

  • 连接超时(ConnectTimeout) :客户端与服务端建立连接的最长等待时间。
  • 读取超时(ReadTimeout) :客户端和服务端已经建立连接,客户端等待服务端处理完请求的最长时间。实际项目中,我们关注比较多的还是读取超时。

一些连接池客户端框架中可能还会有获取连接超时和空闲连接清理超时。

如果没有设置超时的话,就可能会导致服务端连接数爆炸和大量请求堆积的问题。

这些堆积的连接和请求会消耗系统资源,影响新收到的请求的处理。严重的情况下,甚至会拖垮整个系统或者服务。

我之前在实际项目就遇到过类似的问题,整个网站无法正常处理请求,服务器负载直接快被拉满。后面发现原因是项目超时设置错误加上客户端请求处理异常,导致服务端连接数直接接近 40w+,这么多堆积的连接直接把系统干趴了。


超时时间应该如何设置?

超时到底设置多长时间是一个难题!超时值设置太高或者太低都有风险。如果设置太高的话,会降低超时机制的有效性,比如你设置超时为 10s 的话,那设置超时就没啥意义了,系统依然可能会出现大量慢请求堆积的问题。如果设置太低的话,就可能会导致在系统或者服务在某些处理请求速度变慢的情况下(比如请求突然增多),大量请求重试(超时通常会结合重试)继续加重系统或者服务的压力,进而导致整个系统或者服务被拖垮的问题。

通常情况下,我们建议读取超时设置为 1500ms ,这是一个比较普适的值。如果你的系统或者服务对于延迟比较敏感的话,那读取超时值可以适当在 1500ms 的基础上进行缩短。反之,读取超时值也可以在 1500ms 的基础上进行加长,不过,尽量还是不要超过 1500ms 。连接超时可以适当设置长一些,建议在 1000ms ~ 5000ms 之内。

没有银弹!超时值具体该设置多大,还是要根据实际项目的需求和情况慢慢调整优化得到。

更上一层,参考美团的Java线程池参数动态配置open in new window思想,我们也可以将超时弄成可配置化的参数而不是固定的,比较简单的一种办法就是将超时的值放在配置中心中。这样的话,我们就可以根据系统或者服务的状态动态调整超时值了。


重试机制

什么是重试机制?

重试机制一般配合超时机制一起使用,指的是多次发送相同的请求来避免瞬态故障和偶然性故障。

瞬态故障可以简单理解为某一瞬间系统偶然出现的故障,并不会持久。偶然性故障可以理解为哪些在某些情况下偶尔出现的故障,频率通常较低。

重试的核心思想是通过消耗服务器的资源来尽可能获得请求更大概率被成功处理。由于瞬态故障和偶然性故障是很少发生的,因此,重试对于服务器的资源消耗几乎是可以被忽略的。

重试的次数如何设置?

重试的次数不宜过多,否则依然会对系统负载造成比较大的压力。

重试的次数通常建议设为 3 次。并且,我们通常还会设置重试的间隔,比如说我们要重试 3 次的话,第 1 次请求失败后,等待 1 秒再进行重试,第 2 次请求失败后,等待 2 秒再进行重试,第 3 次请求失败后,等待 3 秒再进行重试。

重试幂等

超时和重试机制在实际项目中使用的话,需要注意保证同一个请求没有被多次执行。

什么情况下会出现一个请求被多次执行呢?客户端等待服务端完成请求完成超时但此时服务端已经执行了请求,只是由于短暂的网络波动导致响应在发送给客户端的过程中延迟了。

举个例子:用户支付购买某个课程,结果用户支付的请求由于重试的问题导致用户购买同一门课程支付了两次。对于这种情况,我们在执行用户购买课程的请求的时候需要判断一下用户是否已经购买过。这样的话,就不会因为重试的问题导致重复购买了。


参考

相关文章
|
XML 域名解析 JSON
【RESTful】RESTful API 接口设计规范 | 示例
【RESTful】RESTful API 接口设计规范 | 示例
13083 0
【RESTful】RESTful API 接口设计规范 | 示例
|
1月前
|
监控 算法 开发工具
用户说“App 卡死了”,你却查不到原因?可能是监控方式错了
iOS 卡顿难复现?传统监控抓不到根因?本文深入剖析 iOS 主流卡顿监控方案,重点揭秘生产级可用的 RunLoop 监控实现:如何在不影响性能的前提下,精准捕获主线程阻塞、提取耗时堆栈,并通过退火算法避免重复上报——现已集成于阿里云 ARMS iOS SDK。
|
缓存 Linux 开发工具
CentOS 7- 配置阿里镜像源
阿里镜像官方地址http://mirrors.aliyun.com/ 1、点击官方提供的相应系统的帮助 :2、查看不同版本的系统操作: 下载源1、安装wget yum install -y wget2、下载CentOS 7的repo文件wget -O /etc/yum.
261957 0
|
3月前
|
机器学习/深度学习 存储 供应链
SmoothQuant: 大型语言模型的精确高效后训练量化——论文阅读
SmoothQuant是一种高效的大型语言模型后训练量化方法,通过平滑激活值中的异常值,有效降低量化误差。该方法在保持模型精度的同时,显著减少内存占用并加速推理过程,适用于从数十亿到数千亿参数的模型,已在OPT-175B和MT-NLG 530B等超大规模模型上验证其有效性。
228 1
|
算法 安全 数据安全/隐私保护
Crypto++库支持多种加密算法
【10月更文挑战第29天】Crypto++库支持多种加密算法
527 4
|
8月前
|
监控 前端开发 小程序
陪练,代练,护航,代打小程序源码/前端UNIAPP-VUE2.0开发 后端Thinkphp6管理/具备家政服务的综合型平台
这款APP通过技术创新,将代练、家政、娱乐社交等场景融合,打造“全能型生活服务生态圈”。以代练为切入点,提供模块化代码支持快速搭建平台,结合智能匹配与技能审核机制,拓展家政服务和商业管理功能。技术架构具备高安全性和扩展性,支持多业务复用,如押金冻结、录屏监控等功能跨领域应用。商业模式多元,包括交易抽成、增值服务及广告联名,同时设计跨领域积分体系提升用户粘性,实现生态共生与B端赋能。
785 12
|
XML JSON 分布式计算
如何设计财务对账系统 —— 从0到1搭建对账中心实战
卡拉云快速搭建企业内部对账系统
12210 3
如何设计财务对账系统 —— 从0到1搭建对账中心实战
|
消息中间件 测试技术 领域建模
DDD - 一文读懂DDD领域驱动设计
DDD - 一文读懂DDD领域驱动设计
44723 6
|
消息中间件 RocketMQ 索引
RocketMQ消费者如何实现重平衡
RocketMQ消费者如何实现重平衡
782 0
|
机器学习/深度学习 移动开发 数据可视化
贝叶斯优化实战(一)(4)
贝叶斯优化实战(一)
563 0

热门文章

最新文章