本文首发在 技术成长之道 博客,访问 hechen0.com 查看更多,或者微信搜索「技术成长之道」关注我的公众号,或者扫描下方二维码关注 公众号获得第一时间更新通知!
如今的互联网服务早已不是单体应用,而是由若干个模块组成的微服务,每个模块可以进行单独的扩容、缩容,独立上线部署等等;模块与模块之间通过网络进行联通。我们的应用必须对网络错误进行妥善的处理。从发生时长上而言,网络错误可以分为两类:
而重试是应对短时故障利器,简单却异常有效。
在任何环节下应用都会有可能产生短时故障。即使是在没有网络参与的应用里,软件 bug 或硬件故障或一次意外断电都会造成短时故障。短时故障是常态,想做到高可用不是靠避免这些故障的发生,而是去思考短时故障发生之后的应对策略。
就互联网公司的服务而言,通过冗余,各种切换等已经极大提高了整体应用的可用性,但其内部的短时故障却是连绵不断,原因有这么几个:
短时故障处理以下两点挑战
gRPC 有自己一套类似 HTTP status code 的错误码,每个错误码都是个字符串,如 INTERNAL 、ABORTED 、UNAVAILABLE 。
对于哪些错误可以重试是可配置的。通常而言,只有那些明确标识对端没有接收处理请求的错误才需要被重试,比如对端返回一个 UNAVAILABLE 错误,这代表对端的服务目前处于不可用状态。但也可以配置一个更加激进的重试策略,但关键是需要保证这些被重试的 gRPC 请求是幂等的,这个需要服务使用者和提供者共同协商出一个可以被重试的错误集合。
gRPC 的重试策略分为两类
先说下重试策略
gPRC 用了上面我们提到的 指数避退+随机间隔 组合起来的方式进行重试,详见这里
/* 伪码 */
ConnectWithBackoff()
current_backoff = INITIAL_BACKOFF
current_deadline = now() + INITIAL_BACKOFF
while (TryConnect(Max(current_deadline, now() + MIN_CONNECT_TIMEOUT))
!= SUCCESS)
SleepUntil(current_deadline)
current_backoff = Min(current_backoff * MULTIPLIER, MAX_BACKOFF)
current_deadline = now() + current_backoff +
UniformRandom(-JITTER * current_backoff, JITTER * current_backoff)
上面的算法里有这么几个关键的参数
通过指数的增加每次重试间隔,gRPC 在考虑对端服务和快速故障处理中间找到了一个平衡点。
上面的算法里面没有关于次数的限制,gRPC 中的最大重试次数是可配置的,硬限制的最大值为5 次,设置这个硬限制的目的我想主要还是出于对对端服务的保护,避免一些人为的错误。
再说下对冲策略
对冲策略里面,请求是按照如下逻辑发出的:
次数和上面重试是一样的限制,都是 5 次。
当然不能一直重试,对于重试失败,gRPC 有以下的策略以顾全大局,对于每个 server,客户端都可配置一个针对该 server 的限制策略如下:
"retryThrottling": {
"maxTokens": 10,
"tokenRatio": 0.1
}
对于每个 server,gRPC 的客户端都维护了一个 token_count 变量,变量初始值为配置的 maxTokens 值,每次 RPC 请求都会影响这个 token_count 变量值:
如果 token_count <= (maxTokens / 2),那么后续发出的请求即使失败也不会进行重试了,但是正常的请求还是会发出去,直到这个 token_count > (maxTokens / 2) 才又恢复对失败请求的重试。这种策略可以有效的处理长时间故障。
当然重试失败还能更进一步,比如 Netflix 出品的hytrix能对故障进行熔断&降级处理,感兴趣的读者可以进一步了解。
本文从问题出发,介绍『重试』这种简单而又有效的故障处理手段,希望能对大家有所帮助,有任何问题欢迎在评论区留言交流,或扫描二维码 /微信搜索『技术成长之道』关注公众号后留言私信。
1
xuanbg 2020-03-28 23:10:12 +08:00
这种重试机制必须是同步的且只适用于很短时间内的网络波动造成的没有响应。时间稍微长一点的话,上游调用者都因为超时失败了,你重试成功反而有问题了。
如果真需要重试机制,还是用异步模式去处理比较好,譬如用一个延时队列进行重试。 |
2
feelinglucky 2020-03-30 11:46:09 +08:00
@xuanbg 如果是原子化的操作使用楼主的方法是没有问题的,但有可能造成重试阻塞
|