如何避免分布式事务

未匹配的标注

如何避免分布式事务

最近,有朋友和我交流分布式事务的实践心得,而我的建议是:尽量避免分布式事务

这里的避免并非完全的不要使用,毕竟像金融场景中,这还是一个必要的特性。但对于绝大多数系统,分布式事务带来的复杂度是非常高的,也需要很高的维护成本与理解成本,远超其收益,我不太建议大家刻意地使用这个技术。

举一个简单的case - 用户下了一个订单,经过如下步骤:

  1. 订单服务生成订单
  2. 库存服务扣去库存
  3. 付费服务完成扣款
  4. 用户积分服务增加积分

这时,最直观的解法是要有一套成熟的分布式事务的方案。但事实上,我更推荐在工程上采用下面两种解决方案,而其中的关键词就是 - 补偿

在MQ中重试

我们经常会利用MQ来解耦服务,那么自然会用它来驱动大量的消息。

例如,我们将扣款请求放到MQ里,扣款服务处理成功后通过另一个MQ通知成功。而当扣款服务出现问题时、也就是扣款失败,常见的有2种选择:

  1. 如果要求是必须成功的,消费时就不要返回成功,在服务中反复重试,即便MQ积压产生告警、再人工恢复;
  2. 如果允许失败,那就设置一个最大重试次数,超过最大重试次数则通知给对应的补偿服务;

利用trace-id+ELK

trace-id是分布式链路追踪的关键信息,用于串联信息;而ELK又通过日志收集系统,将这块收集到了一个系统。

我们可以在生成订单时,同时记录这个关键性的trace-id,然后调用各个服务。有任何一个服务失败,我们就将订单状态修改为失败或超时;而数据不一致的问题,就由对应的补偿服务,根据这些有问题的订单的trace-id去分析。

其实可以从这个方案延伸出类似的,比如直接将错误通过trace-id+信息发送给补偿服务,统一收集。

注意点

  1. 补偿不代表只能手动,我们可以在补偿服务内根据错误码,实现一定的自动化;
  2. 补偿更多体现的是一种最终一致性的思想,会有延时,我们要保证中间状态的数据不会污染系统;

在微服务+云原生时代,我们非常提倡 面向错误编程,正是为了能更好地面对各种不确定的异常case。分布式事务带来了大量的复杂度,目前也没有一套跨语言、跨组件的通用解决方案,目前主流几个方案对应用的侵入性很强,所以我不太建议大部分朋友在生产环境使用,而花更多时间学习相关理论、应付面试就行了。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~