在重试设计中比较优雅的做法:
- 要确定什么样的错误下需要重试;
- 重试的时间和重试的次数。这种在不同的情况下要有不同的考量。有时候,而对一些不是很重要的问题时,我们应该更快失败而不是重试一段时间若干次。比如一个前端的交互需要用到后端的服务。这种情况下,在面对错误的时候,应该快速失败报错(比如:网络错误请重试)。而面对其它的一些错误,比如流控,那么应该使用指数退避的方式,以避免造成更多的流量。
- 如果超过重试次数,或是一段时间,那么重试就没有意义了。这个时候,说明这个错误不是一个短暂的错误,那么对于新来的请求,就没有必要再进行重试了,这个时候对新的请求直接返回错误,并进行熔断设计。
- 重试还需要考虑被调用方是否有幂等的设计。如果没有,那么重试是不安全的,可能会导致一个相同的操作被执行多次。
- 重试的代码比较简单也比较通用,完全可以不用侵入到业务代码中。这里有两个模式。一个是代码级的,像 Java 那样可以使用 Annotation 的方式(在 Spring 中可以用到这样的注解),如果没有注解也可以包装在底层库或是 SDK 库中不需要让上层业务感知到。另外一种是走 Service Mesh 的方式(关于 Service Mesh 的方式)。
- 对于有事务相关的操作。可能会希望能重试成功,而不至于走业务补偿那样的复杂的回退流程。对此可能需要一个比较长的时间来做重试,但是需要保存请求的上下文,这可能对程序的运行有比较大的开销,因此,有一些设计会先把这样的上下文暂存在本机或是数据库中,然后腾出资源来做别的事,过一会再回来把之前的请求从存储中捞出来重试。
此文章为3月Day27学习笔记,内容来源于极客时间《左耳听风》,强烈推荐该课程!