1.3.3版本更新
1。修改消费队列的消费形式,修改前消费者全力消费消息,并堆积在了queue任务中,修改后将根据任务的消费能力消费消 息,来不及消费的消息将堆积在mq中
2。修改消费队列任务线程池满负荷时继续提交任务抛出拒绝任务异常导致任务整体退出的bug,现对线程池抛出拒绝异常做了 处理
3。合入了tcc相关的代码
4。完成了redis由单机到集群的迁移,现有代码已由支持单机redis转为支持redis-cluster集群
1.3.3测试:
测试环境介绍:
service服务:10.8.59.158(gen8,12cpu),10.8.59.179(gen9,12cpu),10.8.59.170(gen8,12cpu)
tomcat,zookeeper单机,dobbo-monitor,mycat-eye:10.8.59.169(gen8,12cpu)
activemq单机:10.8.59.179
redis-cluster(三主三从):10.8.59.208(gen9,16cpu)
mycat:10.8.59.176(gen9,12cpu)
account表(未分表):10.8.59.168(gen9,16cpu)
point表(未分表):10.8.59.176
order表(水平拆成5份):order1主从(10.8.59.176),order2主从和order3主从(10.8.59.206 ,gen9,12cpu),order4主从和order4主从(10.8.59.208)
base_message_accounting:10.8.59.169
task与队列消费任务:10.8.59.73(pc机,4cpu)
请求产生:10.8.59.74(pc机,4cpu)
共计8台服务器与两台pc机
本次测试共使用了五个不同的压力进行测试:
1.18:30-18:50,使用test模块单线程产生支付请求,共5W条
2.18:55-19:10,使用test模块30个线程并发产生支付请求,共60W条
3.19:10-19:30,使用test模块50个线程并发产生支付请求,共100W条
4.19:30-20:00,使用test模块70个线程并发产生支付请求,共140W条
5.20:00-20:40,使用test模块100个线程并发产生支付请求,共200W条
以下是调用时的所有截图
链接:https://pan.baidu.com/s/1SACI_NsM8tcrSNnse3EBeQ 密码:1ai7
测试结果dubbo调用情况部分截图:
从以上的服务的调用情况,可以分析出以下几点
1.现有的部署环境在50线程并发生成支付请求时,系统消化请求的能力差不多到了顶点,大约为850笔/秒,继续增大并发请求的线程数,并没有增大系统的吞吐量。而一个完整的支付流程调用服务的过程大致为:initDirectScanPay(创建order与record)->saveAndSendMessage(银行通知本次交易成功时调用)->directSendMessage(银行通知本次交易成功时调用)->completeScanPay(该方法内部会调用creditToAccountTcc与creditToPointAccountTcc),结合以上的调用图,发现在50线程的基础上继续增加请求线程,耗时显著增加的是saveAndSendMessage与directSendMessage方法,说明当下的瓶颈是在支付的产生阶段,而不是核心的completeScanPay对应的tcc完成支付阶段。继续分析saveAndSendMessage与directSendMessage方法,发现saveAndSendMessage与directSendMessage方法消耗的时间大致相同,而它们各自的业务为:
saveAndSendMessage
1.先保存消息至redis
2.后向mq发送消息
directSendMessage
只是直接向mq发送消息,
因此可以判定是在发送mq消息的时候出现了问题。对应现有的代码,可以发现现有的消息发送为同步发送,方法一直阻塞,直至向mq发送消息成功返回。而这两个方法都是本系统中可靠消息子系统的服务,先分析saveAndSendMessage。saveAndSendMessage方法只要确保步骤1执行成功,即使步骤2失败,可靠消息子系统的定时任务也能保证该条消息会被重发,顾可以将saveAndSendMessage修改为同步执行步骤1(确保消息数据成功保存至redis),步骤2可以异步进行,甚至无需关系步骤2是否成功。而directSendMessage方法对应的业务本身就是最大努力通知型,即无需确保消息一定被发送,顾该方法中的发送消息步骤也可以使用异步。
2.directSendMessage方法对应的业务为最大努力通知型,故在dubbo调用时可以设为异步调用,甚至无需等待返回。
3.dubbo方法的调用延时随着压力的增大也在慢慢增加,从极小压力时的2ms延时上升到了大压力下的5ms左右,虽未有大的影响,但将来也是一个调优的点。
接下来我们分析一下50并发时,各个服务器的压力情况,以下是服务器的top状态截图:
可以看到运行service服务的158,170,179三台服务器的cpu消耗徘徊在40%左右,负载在7-9之间,可以说压力已经不小了,之后系统的吞吐量若继续上升,必须对service服务进行调优或直接添加service服务器。
而运行着mycat与三个mysql实例的176服务器,cpu消耗也不低达到了40%,负载更是到了9,处于一个高压力的状态,下次环境若调整,可以考虑将压力较大的point数据库迁移至别的机器。
169服务器运行着tomcat与一些监控程序和一个MySQL实例,总体压力较小,可以考虑增加一些负载,比如运行少量的service服务
206与208作为order表分片的运行服务器,总的来看压力还不是很大,查询了一下硬盘的io使用率也不是很高(抱歉未截图),可以迎接更大的压力。
168应该是现在最空闲的服务器,现在只运行了一个account库的mysql实例,后续将会迁移一点压力至168。
对现有的tcc支付核心的一些更改计划:
1.根据上面的dubbo调用图可以看到,随着压力的增加,其实completeScanPay核心方法的耗时也上升了不少,以最后一段的测试为例,provider消耗的时间上升到了85ms左右,查看其执行的业务逻辑后可以看出,一次completeScanPay完整流程,需要同步的调用两次creditToAccountTcc与两次creditToPointAccountTcc,第一次是completeSuccessOrder中,在完成trade-order与trade-record的处理后,同步的方式先后调用了creditToAccountTcc与creditToPointAccountTcc,之后的confirm或cancel阶段也一样。而creditToAccountTcc与creditToPointAccountTcc中的业务逻辑并无关联,没必要同步执行,完全可以异步执行。在此设计下大致可以节省两次creditToAccountTcc的调用时间(creditToAccountTcc与creditToPointAccountTcc的调用时间差不多),即保持现有压力下估计可以节省30ms左右。(如此修改是结合了本系统具体业务的,即子事务间的业务无关联,若子事务间业务有关联,则必须同步执行,例如B子事务依赖A子事务的结果,那么A就必须在B前执行,只能依靠同步来确保业务的执行顺序)
1.3.4的修改需求与方向
1.将mq信息的发送改为异步发送
2.directSendMessage方法的调用可以改为异步调用,且无需等待返回
3.修改现有的tcc事务代码,try阶段对子事务的异步调用可以在业务代码中实现,但是confirm与cancel阶段对子事务的异步调用需要修改现有的tcc代码块来实现