复杂业务流程拆解

复杂业务流程拆解

摘要

如果系统各个模块还没有拆分,这时对于一些很复杂的业务,其中任何一个业务流程可能会多次操作数据库,尤其是当业务流程中多次出现update 或者insert的时候,如果事务处理不好就会影响性能。以下针对我们业务系统中的一个案例分析一些解决方法。

问题描述

当时系统使用事务管理器是:org.springframework.jdbc.datasource.DataSource TransactionManager。默认的事务传播特性是PROPAGATION_REQUIRED 。使用的事务隔离级别也是mysql默认的隔离级别REPEATABLE-READ。但是业务流程都没有显示用注解@Transactional配置事务的隔离级别,和传播特性。
当时执行完一个复杂的业务流程后,查看mysql 执行日志看到很多SQL 在执行过程都是同一个事务ID,如下图截取了一部分。仔细分析发现整个业务流程是同一个事务ID。这表示要等到业务流程全部执行完事务才会commit,如果并发量比较大的化,会出现大量事务未提交的情况,降低MySQL执行性能,这时只能将业务流程拆分成多个事务来执行。
在这里插入图片描述

解决方法

首先梳理并拆解业务流程,包括以下几个部分:
在这里插入图片描述
(1) 快速解决问题–同步拆分
每个功能都单独放到一个service 类中,并且设置事务传播特性为PROPAGATION_REQUIRED_NEW。隔离级别仍然使用mysql默认的隔离级别REPEATABLE-READ。把功能拆分以后,为了保证数据得完整性和一致性,就需要加上异常处理机制。其中扣费和订单比较紧密,还是需要放到一个事务中的。最终实现方式如下图:
在这里插入图片描述

(2) 根本解决问题–异步拆分
通过消息队列将各个功能模块解耦,同时添加异常处理机制,保证数据的完整性和一致性。最终是要通过微服务拆分,采用分布式的方式来处理这个问题。
在这里插入图片描述

(3)容错机制
所有update 接口和insert 接口都设计为幂等接口,接口规范要注重定义请求消息的一致性。实现了一种faileback方式,不依赖dubbo 框架的failback 机制。可以利用RocketMq ACK机制, 使用 Retry队列,也可以将异常消息存储到tokuDB中,设置一个定时任务,定时处理 失败消息。系统目前采用的策略是尽最大努力一次性提交(失败概率较小),然后手动处理异常消息,同时所有流程都设计成快速失败的。

遗留问题

在功能优化后,系统的性能有所提升,但是容错机制不够完善。系统使用的是dubbo 微服务框架,需要考虑重试机制,以及雪崩的情况。有重试机制,就必须将各个接口都做成幂等。雪崩的情况,需要调整dubbo超时时间和使用熔断机制。
后面会讨论这些问题。

猜你喜欢

转载自blog.csdn.net/wenyushu/article/details/90085165