以前在公司里,有个牛人对俺说:
事务就是个垃圾,能不用就尽量不用。
当时我刚从传统行业切换到互联网行业,对这个牛人说的这句话是嗤之以鼻的,怎么可能不用事务呢?后来随着开发了多个高并发应用后,才知道这个牛人说的是对的。下面说两个亲身经历的案例来说明这个问题。
当时我们有个业务,在购物车阶段的时候,就开始占用库存了,这个库存占用接口的流量非常大。当时我开发完这个接口后,测试人员的压测结果是
2500/TPS
我觉得低了,就开始怀疑测试人员是否不够专业,测试用的服务端应用服务器和数据库是否不给力,发起请求的压测客户端机器是否给力,jmeter用的是否正确。全部检查完后,发现测试手法是完全OK的。
于是仔细的检查代码,也没发现啥。后来灵光一闪,想起那个牛人说过得的话,就尝试把事务去掉。我们用的是Spring的 @Transactional(rollbackFor = Exception.class)
的开启事务的。我把这行代码删除掉后,压测结果是:
3700/QPS
提高了蛮多,这个压测结果已经能满足线上流量要求了。开了事务为啥性能差这么多,底层原因目前还没仔细去研究。但是从压测结果来看,去掉事务后,性能有提升。
这里部分网友可能有疑问,如果线程操作的是多张表的写入和更新操作,如果不用事务的话,一致性怎么保证? 好问题。当时我是使用 逻辑回滚
的手段来保证数据的一致性,是需要自己写代码进行数据回滚的。因为当时要操作的表只有两张,代码写起来还好些。
如果很多张表的话,用逻辑回滚就比较麻烦了。对于这种很多张表的,而流量又不是很大那种的话,还是使用事务方便一些。
当时有个输出商品的接口,读取逻辑如下:
先从memcache读取,如果没有读取到,则从DB读取。
开发完这个接口后,做压测时,我先预热一些数据到memcache上,想看看memcache的读取性能。压测结果不太理想。当时找了很久都没找到原因,后来我用top命令观察了一下,发现只要一压测,应用还是会跟mysql有交互。理论上是不会的,因为数据都在memcache上,一旦命中就走了,不会去读取数据库。
最后面发现原来用了Spring的
@Transactional(readOnly = true)
只要你在接口上面加了这个注解,Spring还是会跟Mysql打交道的。并发的量一旦大了,就开始影响性能了。