导语:
作为程序员可能都知道在一个项目的维护周期中可能会出现各种问题。有的是历史遗留原因,有的可能是和需求及方案的变更有关系,有的可能是个人的编码习惯导致的。这里我就总结一次支付回调中的性能问题,以及解决问题的思路,望与诸君共勉。
问题概述
状态修改不及时,比如说订单状态,支付成功后会跳转到订单详情,这时候订单状态有可能是待支付,并且是概率性事件。过一段时间刷新订单详情,这时候订单状态变成已支付。
统计数不准确,订单支付成功会修改统计数,但是统计数也可能不准确。比如说订单详情是三个订单,统计数是显示两个,导致数据不一致问题。
原因分析
响应太长:结合上述的现象,判断是延迟导致的。然后查看日志,发现接口的响应时间平均在4-5s,最长的有10s多,这就印证了响应延迟的现象。如下图1:
数据脏读:这是在事物并发时常见的问题,两个事物并行执行时,当第一个事物修改数据还没有提交,这时候第二个事物去查询数据,就会拿到修改之前的数。系统之前没有处理过这方面的问题。
事务太大:分析代码会发现一个事物里面处理的业务过多,这样一个事物的执行周期过长。这样会增加脏读的概率,因为在第一个事物长时间没提交的时候,其他事物很有可能去读取某个被修改的数据。
业务冗余:业务没有具体分析设计方案,所有的业务都放在同步方法里面。比如消息发送,推送海报,数据统计,这些业务会造成阻塞等待,从而大大增加的执行时间
决解方案
解耦业务:支付回调会处理多个业务,比如说商品购买和活动报名,每个业务需要处理的数据完全不一样。由于历史原因所有的业务都写在一起,这样会导致很多问题,代码耦和可读性差,逻辑复杂,可能增加不必要的查询。采取的优化方案是使用工厂模式把业务分开,没个业务都只关心和处理自己的事。
重构接口:之前因为版本迭代及代码缺少整理的原因,代码中有很多同样一个查询可能会在多个地方查询多次的情况,这务必会增加系统的IO,这也是导致执行时间过长的主要原因之一。解决方案就是重构接口,把可以共用的查询采用参数的方式传导来达到减少查询的目的。
优化事物:上文分析过,事务过大对脏读产生的几率是有影响的。就算锁住,如果事务过大导致线程等待也会导致系统阻塞。所以保证事务的简洁是优化的一个层次。这边优化的思路是提取主要业务做事务,比如订单表,订单流水表,这些业务有一个共同特点就是数据强一致性。
异步处理:除了主业务放在事物控制,其他的附属业务如消息推送,海报推送,数据统计都放在线程池异步处理。这样会大大减少方法的执行时间,这些业务有一个共同的特点,不管是网络IO,内存IO,数据库IO都是非常耗性能,同时这些业务都没有实时性的要求。
分布式锁:锁是解决统计数准确,也就是解决脏读的必要手段,有人可能选择数据库的乐观锁。我这边因为项目是集群部署,所以选择的是分布式锁。锁是加在事物的方法上,这样能保证一个事物处理完成,另外一个事物才会进来。当然如果并发量大的话会有锁等待的问题,但是这应该是从另外一个维度解决并发的问题,目前我们没有这么大的并发。
测试效果
改版前的效果,可以看到接口的响应时间在10s左右。
改版后的效果,可以看到响应时间在0.1s。
压力测试还没有做,效果还要看在压测下的报告。
欢迎大家提出不同的意见与见解,以留言的方式给我到。
作者:把代码写成诗
版权所有,转载请注明出处
欢迎关注,沟通交流 https://github.com/githubweili
网友评论