我目前所在的公司采用的是微服务体系架构,微服务之间存在一些依赖调用的关系。
由于公司推行 RESTful,微服务一般会对外暴露接口,所以,在公司内部最常见的就是不同微服务之间的 HTTP 请求调用了。
读完本文,你将收获 Web 应用错误处理的常见手段,以及相关系统设计概念和原则。
这个问题,我们需要从客户端和服务端两个点进行切入。
对于客户端来说,我们是希望进行重试并且期望下一次请求时不再出现错误。
重试是个很好的办法,但是我们仍然需要慎重选择是否重试以及重试相关的策略,来避免让情况恶化。
客户端重试
客户端向服务端发起请求,如果存在异常或者错误,一般会返回 4xx 或者 5xx 的 HTTP 状态码,分别代表客户端错误和服务端错误。对于这两种异常状态码,我们选择的策略也不同:
- 客户端错误,不进行重试。
如果是前端应用,客户端可以界面提示用户,或将错误记录给服务器做日志采集供进一步分析
- 服务端错误,慎重地进行重试
重试策略
通常,我们有如下重试策略可供选择:
- 取消重试:这种情况下,客户端选择放弃重试而取消这次请求
- 立即重试:客户端立即重新发送请求
- 固定间隔:在失败请求和重试请求之间等待固定的时间间隔
- 增加间隔:客户端在第一次请求失败时,快速地进行重试,之后的重试会逐步增加间隔
- 指数退避算法:重试的等待间隔指数级增加(如 。比如,当请求第一次失败,等待 1 秒后进行重试;如果第二次请求也失败,则在重试之前,等待 2 秒;如果第三次请求仍然失败,则等待 4 秒后再进行重试。
- 指数退避抖动算法:如果所有失败的请求在同一时间回退,它们在重试时又会引起争用或过载。抖动给回退增加了一定的随机性,以分散重试。
重试的弊端
对于客户端来说,重试没有什么负担,但是从整体来看,它可能会引起一些问题,如系统过载,多次执行相同的操作,并且发送大量的请求会将这个问题放大。
因此,我们需要在服务端使用限流器和熔断器来避免服务过载。
服务端
对于服务端来说,我们不能保证每个客户端都选择友好的重试策略,从保护系统服务的角度来说,我们同样需要做一些防范措施来进行流量控制,比如:增加限流器和熔断器,同时使用监控告警、错误日志等方式记录或通知。
限流器
主要用来限制请求频率,有令牌桶、漏斗、时间窗口等算法。限流我已经在之前的 blog 中进行了对应的分享,感兴趣可以参考
系统设计概念:限流(Rate Limiting)
熔断器
在错误请求超过阈值时马上切断流量。
经过一定时间后,先放开部分流量,如果一切正常,再放开所有流量。
参考
常见服务端错误
- 500 → Internal service error
- 503 → Service unavailable
- 504 → Gateway timeout
常见客户端错误
- 400 → Bad request
- 403 → Forbidden
- 404 → Not found
- 429 → Rate exceeded
.png?table=block&id=72b0fede-8536-41e4-8b99-e7b33fa05e0c&cache=v2)

