多线程加锁,别锁太长~

多线程加锁,别锁太长~~~

BUG 描述:

     Acs(通用过滤系统)整体性能曲线波动幅度很大,最大幅度超过65%!!!

     以下是截取其中一段时间性能波动曲线回忆版(吞吐量是每隔10s统计一次的平均值)

    

BUG的影响:

     Acs整体的处理性能始终上不去,达不到现网要求的1w/s。

BUG的发现过程:

     采用性能测试工具压测svr,待系统稳定后,每10s采集一次系统的平均吞吐量,发现曲线波动非常大,不符合正常的性能曲线


BUG的分析与解决

BUG的分析:

         Acs的svr维护一个session会话,每当acs接受一个请求的时候就会往会话里追加该请求的一些信息,这些信息中间包含一个时间戳,记录这个请求开始处理的时间。每当acs处理完一个请求的时候,就会去session里面去取出这个请求当时保存的信息,在组包返回给前端。

         Acs的svr还有一个超时处理线程,该线程每隔3s就会去session会话里遍历读取5000个请求,进行超时判断,如果超时,就返回给前端该请求已经超时。注意此操作将要耗费相当长一段时间!

         此时,问题就出现了,我们可以简单的用一个图来描述一下

         Session会话就是我们的临界资源,此时一共有三个线程抢着给它上锁,他们分别:

         1)request线程:该线程从gnp的request队列里取请求后解包,将一些不需要与后端交互的信息暂时写到session会话里面,我们暂时就叫它request线程。

2)response线程:该线程收到后端应答后从session会话里面取出request线程之前存入的对应的信息进行组包返回扔到gnp的response队列里

3)超时处理线程:该线程要对session会话里面的超时请求定期进行清理。

三个线程具有平等的权利,谁抢到了全凭运气。于是一场无硝烟的战争开始了。

 


 


 

 

 

       我想大家应该都明白原因在哪里了:每当超时处理线程抢到这个资源的时候,实际工作的线程(request线程和response线程)就一直处理等待状态,此时吞吐量明显会下降,反之,当超时处理线程没有抢到的时候,咱的吞吐量还是很OK的。

BUG的解决:

1)                                方法一:缩短超时处理线程每次取出的请求个数,这样就可以减少超时处理线程加锁的时间,这样实际工作的线程就回有更多的机会和时间获取sesson会话的锁,从而提升实际的处理能力

2)                                方法二:Session会话其实就是一个队列,根据队列的先进先出原则,我们何不之前做一个判断?每次取出队列尾部的请求进行超时判断,若尾部都不超时,那么就说明整个队列都没有超时,若尾部超时了,结合我们的方法一,取出一小部分请求即可。所以我们采用的是这个。

BUG经验沉淀:

       有硬件的,当然也软件的。

       硬件的:加锁并不能保证“安全”。这也是一个关于线程安全的问题,尽管我们的系统已经加锁了,但是就不能说没有问题了,对于一个高并发的系统,还是结合实际的处理情况来决定加锁的时长甚至是锁的分配。

       软件的:发现问题的过程中,对问题要有敏锐的嗅觉,在呈现问题时需要提供非常有力清晰的证据,推动问题的解决则是基于本身对版本质量的强烈的责任意识。任何一个环节的缺失都将会将BUG遗漏掉。所以说,测试不仅仅是一门计算机科学,而是一个集合计算机,沟通,管理等多门综合的学科。虽然说的和教科书似得,但的确是这个BUG从解决到发现的整个过程Lisa对测试的进一步的理解