分布式之超时和重试

一、超时和重试概述

在当下分布式系统的设计中,随着业务的复杂度和规模的不断扩大,服务之间的依赖日益紧密,使得超时和重试机制尤为突出。合理配置超时时间和重试策略成为维护系统稳定性的重中之重。

二、超时问题

服务的外部请求处理依赖于线程资源。以常用的内嵌Tomcat为例,通过开启多线程来处理外部的HTTP等请求。每次当有新的HTTP请求时,系统会分配一个线程专门处理该请求。其中每个请求都会与一个线程关联,这个线程负责对请求进行处理。合理配置超时机制,对于维护线程资源和系统整体性能只管重要。如下图:

1 超时时间过长的影响

当用户发起请求,服务A与服务B进行调用时,如果超时时间设置不当(设置过高10秒或不设置),在极端情况下,服务B发生故障,服务A的每个请求都需要等待10秒才能得到响应。这意味着每个处理线程都会被阻塞10秒,无法释放线程。那么此时,系统的处理能力将受到严重影响,导致线程池资源迅速耗尽。

如下图:

红色线程长时间阻塞被占用,无法处理新的请求,进而影响整个系统的性能和可用性。

那么如何处理超时时间设置过长问题。在服务之间进行调用时,设置合理的超时间非常重要。我们可以将超时时间设置300毫秒 ,如果300毫秒内没有收到响应结果,系统会触发异常立即返回 。这样的设定可以有效的防止线程长时间阻塞而导致线程资源耗尽的情况。

超时时间设置:

超时时间设置需要我们综合考虑多因素。基于对接口性能的深入理解,接口响应时间的分布TP99和TP999等指标,结合下游服务进行综合评估。科学的配置超时时间,既满足高可用,又不过度消耗系统资源。

例如:A服务设置过大的超时时间如设置10秒,看似预留了足够的缓冲时间,但如果B服务日常TP99通常在1秒内返回。实际这样A服务这样配置存在巨大的风险隐患。一旦下游服务出现故障,将导致大量的线程阻塞,严重影响业务的正常运行

针对这种场景,我们可以将A服务的10秒超时时间改为1秒,这是基于下游服务接口的性能指标(TP99、TP999)以及其他因素综合考量的。并可以设置接口失败重试1次(需要谨慎,对于写操作要考虑幂等性问题)

2.超时时间过短影响

另一种极端情况,超时时间设置过短。如我们将超时时间设置为40毫秒,可能会带来新的问题。在某些特定时期,如大促导致流量暴增,依赖的服务系统会有较大压力,导致CPU负载升高。

在这种情况下,原本只需要20-30毫秒内可以完成的请求处理,可能会因为系统性能延长到50~60毫秒。这个延长会触及到我们设置的40毫秒超时的阈值 ,导致大量请求在即将处理完成并返回结果时,因为触发超时阈值而触发异常抛出。这样会对用户体验以及系统的稳定性造成严重的影响。

超时时间设置:

前面提过,超时设置需要考虑多因素。如我们将超时时间设置为40毫秒,日常可用率稳定。我们可以结合TP99、TP999的日常行为分析,对超时策略进行调整。我们可以将超时时间合理延长 至60毫秒,以适应大促等活动期间更高的性能要求 ,保证系统在大流量下的可靠和稳定 。具体设置需要根据自己的实际业务和服务性能以及预测流量进行设置。

3 超时漏斗

线上连锁故障有一种常见的情形:服务器在消耗大量资源处理实际上早已超出调用端超时限制的请求。这种情况下,服务端所消耗的资源没有产生任何实际的价值。大多数情况下,继续在服务端处理这些请求是不明智的,因为没有任何结果。所以放弃这些请求,对于资源分配和系统稳定至关重要。

例如:服务A调用服务B设置超时为100ms,服务B调用服务C设置的超时时间为200ms,这样的设计明显是有问题的,违背了超时漏斗的原则。如下图:

当用户发送请求后,服务B等待服务C响应时,如果在100毫秒内没有得到结果,服务A就会因超时而触发重试机制。由于服务B的线程池可能因为等待服务C的响应而被占用,这种不合理的设计会导致服务B的线程池迅速耗尽,进而拒绝新的请求。会引发连锁反应。

(1)重试风暴 :因服务A的超时重试,进一步加剧服务B的压力,形成重试风暴。

(2)资源耗尽 :因服务B的线程池被大量占用,导致服务响应能力下降。

(3)性能下降 :因服务B无法及时处理服务A的新请求,导致整个系统性能下降。

(4)雪崩效应 :服务C的问题无法及时处理,连锁反应会蔓延到其他服务,最终引发雪崩效应。

所以合理的设置超时时间,对分布式系统的稳定性至关重要。

4 超时时间传递策略

这是一种复杂的超时时间策略 ,这里简单介绍一下。故名思意,这种策略采用以各种超时时间传递取消传递 的策略。通过这种策略,超时时间可以在服务调用链路的起点统一设定 (例如服务A)。这样,由初始请求触发的整个RPC调用链路都能共享相同的绝对超时时间。例如,服务器A设定了10秒的截止时间,花费2秒处理请求,然后向服务B发送RPC,那么从A到B的RPC将拥有8秒的截止时间。如果服务器B又花费4秒处理请求并继续向服务器C发送请求,从B到C的RPC则会有4秒的截止时间,依此类推。

三、重试问题

为什么要重试,因为请求失败后再次尝试相同的请求,通常会使得请求成功 。这是因为我们构建的系统类型通常不会作为一个整体失败。恰恰相反,他们会遭到部分故障 或者瞬态故障 。部分故障是指一定百分比的请求成功。瞬态故障是指请求在短时间内失败。重试是允许客户端通过再次发送相同的请求来避免这些随机的部分和瞬态故障 。当让了重试并非是完全安全 的。如果系统是因为过载、资源耗尽等故障,那么重试只会增加被调用系统的负载

1.重试策略

1.1重试机制的设计

除了调整我们上面讲过了超时时间以外,我们还应该考虑另外一项重要的配置:重试机制 。重试机制的核心在于,远程过程调用遭遇失败时,系统可以根据重试策略自动的进行自定义重试次数的尝试 。这样可以提升系统的稳定性 和请求的成功率

1.2重试策略种类

重试策略,常见几种方式:
(1)固定间隔 :每次重试的时间间隔时固定的。如每隔1秒进行一次尝试。这种方法简单直观。但可能出现连续失败导致请求高峰的情况。
(2)指数退避 :每次失败,重试时间间隔成倍增加(如MQ的失败重试规则),这种方式逐步增加重试等待时间,分散失败导致的高峰情况。给予系统更多的回复机会。
(3)抖动重试 :在固定检核和指数退避的基础上增加随机性,可以避免多客户端同时重试造成的峰值负载。

通过精心设计的重试策略,我们可以在不牺牲用户体验的前提下,显著提高系统的整体可用性和稳定性。

2.重试风暴

在微服务架构中,必须要警惕重试风暴的发生 ,这是由于重试策略配置不当所导致的系统性能急剧下降的现象。
什么时重试风暴?

例如,当基础组件(如数据库Mysql)面临高压力导致出现超时,如果此时每个服务请求都盲目的进行重试 ,那么一次业务请求,对数据库的访问次数将可能呈几何倍增长 。这种情况下,基础组件的压力会急剧增加,最终可能会引发服务的雪崩

规避策略

(1)可以把重试册数配置小(如1次)或者使用指数递增+随机化。

(2)系统服务调用方考虑熔断和降级策略,下游服务设定好限流策略。

(3)可以借鉴谷歌的Google SRE的做法。使用明确的返回状态码,详细的考虑每个错误模式的处理方式。

四、超时与重试策略设置

超时时间和重试次数的设置,是一个平衡多种因素的决策过程。需要考虑到服务器的配置性能、系统稳定性、请求响应时间、资源分配使用和用户的体验等多种方面的因素。不合理的设置不仅无法解决问题,反而会带来很多新的风险,对系统稳定性构成极大的威胁。

1.超时设置

对所有的远程i奥永都应该设置超时时间。
保守策略 :可以将超时时间设置在响应时间TP99的基础上(对于核心性能要求极高的场景可参考TP999/TP9999),加上一定的缓冲时间。缓冲时间可以根据日常对系统请求监控和分析来定。如下游接口的TP99为100ms,超时时间可是设置为150ms左右。
请求服务调用最长时间计算:例如A服务调用服务B的超时时间为100ms,重试次数为1.正常调用平均耗时为20ms。根据以上场景情况下,A服务在重试情况下的最长时间为:乐观情况120ms(网络抖动),悲观情况200ms(服务故障)。

2.重试设置

客户端在重试时,是通过花费更多服务器时间换取成功几率的过程 。如果是由于部分故障和瞬态故障引起的重试,并不会有问题。因为重试请求总量很小,并且增加表面可用性的权衡效果也很好。但是如果故障是服务过载引起的,那么重试反而会增加负载,导致情况更加恶化。所以重试要谨慎配置。遗憾的是,在分布式系统中,几乎无法在所有客户端之间进行协调以实现正确的重试次数。
安全重试 :具有写操作的API必须要提供幂等性才可以保证重试安全性,无论重试多少次,写只会发生一次。通常只读API是幂等的。
重试策略:根据实际的业务场景和资源环境以及下游接口的稳定性,合理的设置重试次数。通常,重试次数不宜过多,建议1-2次,以减轻服务负担。可以使用指数递增+随机化重试策略。避免因为一个小故障导致重试请求同时出现,而影响系统的稳定性。

在黄金链路系统超时情况下,应该考虑系统熔断和降级,下游的服务做好限流策略,加固系统的稳定性。

在实际生产过程中,业务需求不断迭代,加上系统架构的升级。需要我们根据接口指标和相关信息,定期评估超时时间和重试策略对系统的影响,根据实际情况调整响应的策略,以保证正确的使用。

相关推荐
程序员 小柴4 小时前
RabbitMQ的工作模式
分布式·rabbitmq·ruby
蒋星熠4 小时前
在VMware下Hadoop分布式集群环境的配置--基于Yarn模式的一个Master节点、两个Slaver(Worker)节点的配置
大数据·linux·hadoop·分布式·ubuntu·docker
小样vvv5 小时前
【分布式】微服务系统中基于 Hystrix 的熔断实现方案
分布式·hystrix·微服务
清风19818 小时前
kafka消息可靠性传输语义
数据库·分布式·kafka
小诸葛的博客8 小时前
Kafka、RocketMQ、Pulsar对比
分布式·kafka·rocketmq
数据智能老司机10 小时前
CockroachDB权威指南——SQL调优
数据库·分布式·架构
数据智能老司机10 小时前
CockroachDB权威指南——应用设计与实现
数据库·分布式·架构
数据智能老司机10 小时前
CockroachDB权威指南——CockroachDB 模式设计
数据库·分布式·架构
数据智能老司机1 天前
CockroachDB权威指南——CockroachDB SQL
数据库·分布式·架构