Seata分布式事务大并发下容易出现timeout的情况优化使用
本文作者:FUNKYE(陈健斌),杭州某互联网公司主程。
前言
Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。
Seata AT 模式:
一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
二阶段:提交异步化,非常快速地完成。回滚通过一阶段的回滚日志进行反向补偿
Seata 官网使用介绍:
通过以下代码改造实践.
模拟场景
1.首先我们改造一下官网的代码,成为一个商品下单的代码
1 |
|
我们可以看到,这种情况下线程不安全,会出现脏读写,并发下商品库存会变为负数的可能.
2.改造代码上锁,保证线程安全
1 |
|
这时候这段代码是可以正常使用了.但是之后再压测后发现,容易出现事务超时的异常,如图:
可以看到出现异常后回滚超时等情况了.
分析原因
1.我们可以按照以上的代码看到,官网的介绍比较多的都是注解形势,api提及比较少,我们首先分析刚才代码
服务调用->发现注解->创建事务->等待锁->获取锁->业务处理
可以发现优先创建了事务,这时候如果再大并发下,一直等待抢不到锁的话……这时候会引发上图所示的各种超时异常.
解决方案
1.再来看下流程:服务调用->发现注解->创建事务->等待锁->获取锁->业务处理
2.发现问题所在了不?只要我们能把等待锁获取锁的操作放在创建事务前,这个问题迎刃而解.
用户请求->等待锁->获取锁->服务调用->发现注解->创建事务->业务处理
1 | "purchase") (value = |
3.如果有人说,因为是分布式锁不是本地锁,或者我加锁的地方就是要在service内咋办?
没关系,seata还有提供一套事务的api创建方式.
1 | public void purchase(String userId, String commodityCode, int orderCount) { |
改为上述代码,使用api进行提交跟回滚操作即可,这样保证了抢到锁后才进行事务的创建.
总结
耐心的寻找问题发生的原因,过程是如何,你能更精确,更有效的去解决问题.