微服务的重试与弹性设计

本文是开源工作流引擎Camunda联合创始人Rücker对微服务调用进行弹性设计的改进建议,类似谷歌的gRPC和阿里的Dubbo都可以看成是RPC微服务,Spring提供了REST服务,这些服务虽然形式不同,本质都是同步调用。这种同步调用在生产环境可能遭遇各种意外情况发生堵塞延迟,怎么办?下面他提出了几种设计方案。


以简单的网络购物为案例:

客户端 ---->支付微服务 ---->信用卡微服务

这种简单的调用链非常普遍,以它为案例阐述有状态的弹性模式。

假设信用卡服务变得疯狂,也就是说它虽然还能响应,但非常缓慢。那么支付服务调用信用卡服务会被阻塞在这里,因为支付服务一直等待信用卡响应,而信用卡服务延迟响应了。由于延迟过程需要很长时间,所有从支付服务出发的线程都会被堵塞在这里,支付服务最终会超时出错。在你的系统中出现这样一个很微小的故障可能会瘫痪整个系统,这是一种没有弹性的设计。

下面是改进设计演进版本:

快速失败fail fast
这里可以应用一个快速失败模式,比如使用断路器。在这个例子中,使用了Netflix Hystrix断路器。如果信用卡服务响应减慢,断路器就会立即中断支付服务的调用并且让支付服务马上发生故障。这样,即使功能无法实现了(我无法向信用卡充值),但仍然可以确保整个系统可响应。

快速失败是不够的
但快速失败是不够的。在信用卡服务被修复后,经常会进行重试。此重试需要具有状态性,不仅可以立即重试,而且可以在几分钟,几小时甚至几天内重试。对信用卡服务进行有状态的重试,也就是重试带着信用卡服务的输入参数。

保持同步响应
在这种情况下,通常不需要异步处理,只要信用卡服务可用,就可以很好地返回同步响应,但只有在不能同步时才切换到异步。

区分能否同步响应,使用HTTP返回码来支持(200 OK意味着所有OK,202 ACCEPTED意味着同步失败)。

没有消息的异步工作分配
相比同步调用服务的另一种方法是异步通信。默认是使用消息。

但是异步不一定使用消息,可以使用工作流引擎作为工作分配,表现得像一个队列。工作流引擎会提供一个支付是否完成的查询,如果没有,会让客户更换另外一张信用卡,然后再次调用支付服务,这个过程只要指定流程后,流程会负责重试。


使用补偿的业务交易
在分布式系统中,ACID事务不适用(或者至少不能很好地扩展)。使用补偿是另一种选择 - 这意味着如果以后发生失败时可以撤​​销已执行的工作。

在这个案例中,基于上面的流程重试,重试几次后就不再无限次重试了,而是作为支付失败处理,然后将支付之前的流程进行回退,调用回退环节的各个回退方法执行补偿,最终将状态恢复到这次支付活动没有发生以前的状态。

flowing-retail/payment-rest at master · flowing/fl

[该贴被admin于2018-03-27 10:39修改过]